diff options
author | Ziemowit Laski <zlaski@apple.com> | 2003-09-25 01:26:01 +0000 |
---|---|---|
committer | Ziemowit Laski <zlaski@gcc.gnu.org> | 2003-09-25 01:26:01 +0000 |
commit | 264fa2db22ce7cf50ebb108edb097acf0c9f2a57 (patch) | |
tree | 1052b4d25cc404c17e6402e22b8183026f4d4263 | |
parent | 3b6fdb2fa04453ebf17ec1dfd3ef62b413442430 (diff) | |
download | gcc-264fa2db22ce7cf50ebb108edb097acf0c9f2a57.zip gcc-264fa2db22ce7cf50ebb108edb097acf0c9f2a57.tar.gz gcc-264fa2db22ce7cf50ebb108edb097acf0c9f2a57.tar.bz2 |
MERGE OF objc-improvements-branch into MAINLINE.
2003-09-24 Ziemowit Laski <zlaski@apple.com>
MERGE OF objc-improvements-branch into MAINLINE.
See 'gcc/ChangeLog' and 'gcc/testsuite/ChangeLog' for
the gory details.
From-SVN: r71748
120 files changed, 5734 insertions, 1479 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3e2d570..b869d0b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,232 @@ +2003-09-24 Ziemowit Laski <zlaski@apple.com> + + MERGE OF objc-improvements-branch into MAINLINE: + * Makefile.in (C_OBJS): Add in stub-objc.o. + (c-parse.y): Change sed demarcations to begin with '@@'. + (stub-objc.o): New rule. + * c-common.c (flag_nil_receivers, flag_objc_exceptions, flag_zero_link, + flag_replace_objc_classes): New flags. + * c-common.h (RID_AT_THROW, RID_AT_TRY, RID_AT_CATCH, RID_AT_FINALLY, + RID_AT_SYNCHRONIZED): New keywords. + (flag_nil_receivers, flag_objc_exceptions, flag_zero_link, + flag_replace_objc_classes): New flags. + (lookup_interface, is_class_name, objc_is_object_ptr, objc_check_decl, + objc_comptypes, objc_message_selector, lookup_objc_ivar, + get_current_scope, objc_mark_locals_volatile): New prototypes, + some moved from c-tree.h. + * c-decl.c (get_current_scope, objc_mark_locals_volatile): New functions. + (finish_decl): Adjust where objc_check_decl() gets called. + * c-lang.c (lookup_interface, is_class_name, objc_is_id, objc_check_decl, + objc_comptypes, objc_message_selector, lookup_objc_ivar): Remove stubs. + * c-opts.c (c_common_handle_option): Add handling for flag_nil_receivers, + flag_objc_exceptions, flag_replace_objc_classes and flag_zero_link. + * c-parse.in: Replace 'ifc' and 'end ifc' sed markers with '@@ifc' and + '@@end_ifc', respectively. + (AT_THROW, AT_TRY, AT_CATCH, AT_FINALLY, AT_SYNCHRONIZED): New %tokens. + (objc_try_stmt, superclass, class_ivars, objc_try_catch-stmt, + objc_finally_block): New rules. + (component_decl_list2): Clean up semantic action for @defs construct. + (component_decl, c99_block_start): Remove call to add_objc_decls(). + (poplevel): Add call to objc_clear_super_receiver(). + (stmt): Add rules for @throw, @try..@catch..@finally and @synchronized + constructs. + (classdef, methodprotolist): Clean up/simplify. + (methodprotolist2): Eliminate. + (methodproto): Call add_method() instead of add_class_method() and + add_instance_method(). + (receiver): Add TYPENAME production. + (reswords): Add "throw", "try", "catch", "finally" and "synchronized". + (rid_to_yy): Add AT_THROW, AT_TRY, AT_CATCH, AT_FINALLY and + AT_SYNCHRONIZED. + * c-tree.h (lookup_interface, is_class_name, objc_is_id, objc_check_decl, + objc_comptypes, objc_message_selector) + * c-typeck.c (comptypes): In ObjC mode, call objc_comptypes() for + struct and pointer types. + (build_c_cast): Do not discard ObjC protocol qualifiers. + (convert_for_assignment): Cache result of comp_target_types() instead + of calling it more than once. + * c.opt (fnext-runtime): Update description string. + (fnil-receivers, fobjc-exceptions, freplace-objc-classes, fzero-link): + New ObjC/ObjC++-specific flags. + * function.h (GCC_FUNCTION_H): Header guard. + * gengtype-lex.l: Teach lexer about new @@... sed demarcations. + * stub-objc.c: New file, to be used to satisfy references to ObjC + functions by the C and C++ front-ends. + * config/darwin.c (_OBJC_IMAGE_INFO): New global metadata. + * config/darwin.h (FUNCTION): Add in_objc_image_info. + (SECTION_FUNCTION): Add objc_image_info_section. + * doc/invoke.texi: Link to GCC web site for Objective-C information. + (-fconstant-string-class): Update documentation. + (-fno-nil-receivers, -fobjc-exceptions, -freplace-objc-classes, + -fzero-link): New documentation. + * objc/Make-lang.in (objc-parse.y): Change sed demarcations to begin + with '@@'. + * objc/lang-specs.h (@objective-c-header): Fix -E spec. + * objc/objc/objc-act.c: Replace TYPE_NAME with OBJC_TYPE_NAME + throughout; provide casts for return values from memory allocation + functions (xmalloc, alloca, ggc_alloc, etc.). + (OBJC_VOID_AT_END): New macro. + (rtl.h): Do not #include any more. + (STRING_OBJECT_GLOBAL_NAME): Replaced with STRING_OBJECT_GLOBAL_FORMAT. + (TAG_MSGSEND_STRET, TAG_MSGSENDSUPER_STRET, TAG_MSGSEND_NONNIL, + TAG_MSGSEND_NONNIL_STRET, TAG_EXCEPTIONEXTRACT, TAG_EXCEPTIONTRYENTER, + TAG_EXCEPTIONTRYEXIT, TAG_EXCEPTIONMATCH, TAG_EXCEPTIONTHROW, + TAG_SYNCENTER, TAG_SYNCEXIT): New NeXT runtime entry points. + (struct val_stack, catch_count_stack, exc_binding_stack, val_stack_push, + val_stack_pop): New. + (objc_check_decl): Fix precondition for error message, along with + the message itself. + (lookup_and_install_protocols): Remove nonexistent protocols from + protocol list instead of returning error_mark_node. + (create_builtin_decl): Use DECL_ARTIFICIAL only for VAR_DECLs. + (setup_string_decl): Generalize to use STRING_OBJECT_GLOBAL_FORMAT. + (synth_module_prologue): General clean-up; construct NeXT-specific + runtime API prototypes if needed. + (build_string_class_template): Remove. + (check_string_class_template, string_layout_checked): New. + (build_objc_string_object): Generalize to work with + -fconstant-string-class. + (build_objc_symtab_template): Fix layout for the NeXT runtime. + (build_metadata_decl): New. + (forward_declare_categories): Call build_metadata_decl() instead of + create_builtin_decl() et al. + (build_module_descriptor): Use OBJC_VOID_AT_END instead of + void_list_node_1. + (build_selector_reference_decl, build_class_reference_decl, + build_objc_string_decl): Do not set TREE_READONLY. + (get_proto_encoding): Do not call hack_method_prototype(). + (get_class_reference): Add failure mode for invalid class names; + support -fzero-link; defer if in an ObjC++ template declaration. + (objc_declare_alias, objc_declare_class): Fix up duplicate name + lookup; check for global scope if in ObjC++. + (is_class_name): Generalize to work with various tree nodes (TYPE_DECL, + RECORD_TYPE, IDENTIFIER_NODE, etc.) + (objc_is_id): Removed. + (objc_is_object_ptr): New function. + (get_class_ivars_from_name): New function, used for @defs construct. + (get_class_ivars): Add option to return raw ivars; create a + ClASS_OWN_IVARS list for each class as needed. + (objc_enter_block, objc_exit_block, objc_declare_variable, + objc_build_throw_stmt, val_stack_push, val_stack_pop, + objc_build_try_enter_fragment, objc_build_extract_expr, + objc_build_try_exit_fragment, objc_build_extract_fragment, + objc_build_try_prologue, objc_build_try_epilogue, + objc_build_catch_stmt, objc_build_catch_epilogue, + objc_build_finally_prologue, objc_build_finally_epilogue, + objc_build_try_catch_finally_stmt, objc_build_synchronized_prologue, + objc_build_synchronized_epilogue, build_objc_exception_stuff): + New functions. + (_JBLEN): _setjmp jmpbuf size (needs to be made a target hook in + the future). + (build_private_template): Fix up calls to get_class_ivars(). + (offset_is_register, forwarding_offset): Remove. + (objc_method_parm_type, objc_encoded_type_size): New functions. + (encode_method_prototype): Simplify to no longer depend on + back-end information. + (build_tmp_function_decl_xxx, build_tmp_function_decl, + hack_method_prototype): Removed. + (generate_protocol_references): Remove calls to + build_tmp_function_decl(). + (generate_protocols): Adjust calls to encode_method_prototype(). + (build_class_template): Generate sel_id' and 'gc_object_type' fields + for the NeXT runtime. + (synth_forward_declarations): Call build_metadata_decl(). + (check_ivars): Check that the number of ivars matches also. + (build_super_template): Modify super_type directly; disable debugging + output while generating decl. + (build_ivar_list_initializer): Skip list elements that are not + FIELD_DECLs. + (ivar_list_length): New function. + (generate_ivar_lists): Call ivar_list_length() instead of list_length() + and encode_method_prototype() instead of encode_method_def(). + (build_shared_structure_initializer): Generate 'sel_id' field for + the NeXT runtime. + (generate_category): Do not set TREE_USED. + (build_keyword_selector): Ditto; transform into a function argument + chain. + (get_arg_type_list): If there are no user-specified arguments, use + '...'; use OBJC_VOID_AT_END. + (check_duplicates): Add a parameter indicating whether methods or + selectors are being checked. + (receiver_is_class_object): Add parameters indicating whether + receiver is 'self' or 'super'; robustify. + (build_message_expr): Defer call to finish_message_expr() if + inside an ObjC++ template. + (lookup_method_in_hash_lists): New function. + (finish_message_expr): Complete rewrite/fix. + (build_objc_method_call): Ditto; factor out commonalities between + the GNU and NeXT runtimes; acccommodate ..._stret and ...NonNil + messenger variants on the NeXT. + (lookup_instance_method_static, lookup_class_method_static): + Fold into a single lookup_method_static() function with an + additional parameter. + (add_class_method, add_instance_method): Fold into a single + add_method() function with an additional parameter. + (add_category): Make duplicate categories a hard error in ObjC++. + (add_instance_variable): Properly handle unnamed ivars, arrays of + zero or no size and bitfields. In ObjC++, check for nontrivial + C++ class instances. + (is_public): Allow C functions to access non-@public ivars, with + a warning. + (start_class): Move common initializations to + synth_module_prologue(); check for global scope if in ObjC++. + (continue_class): Fix calls to finish_struct(). + (objc_declare_protocols, start_protocol): Check for global scope + if in ObjC++. + (encode_pointer): Encode 'BOOL *' specially on the NeXT. + (encode_aggregate_within): Rewrite to properly distinguish + struct tags from typedefs in both ObjC and ObjC++. + (encode_bitfield, encode_complete_bitfield): Remove. + (encode_next_bitfield, encode_gnu_bitfield): New functions. + (encode_field_decl): Call encode_next_bitfield() or + encode_gnu_bitfield() as needed. + (synth_self_and_ucmd_args): New function. + (start_method_def): Use it. + (objc_types_are_equivalent): New function. + (comp_proto_with_proto): Use it instead of comptypes(), since + we need symmetry. + (really_start_method): Use lookup_method_static() instead of + lookup_class_method_static() and lookup_instance_method_static(); + Emit 'extern "C"' if in ObjC++ mode. + (add_objc_decls): Removed. + (UOBJC_SUPER_scope): New variable. + (get_super_receiver): Move construction of 'super' from + add_objc_decls(); remove dependency on struct objc_class. + (encode_method_def): Removed; encode_method_prototype() is + used instead. + (objc_clear_super_receiver): New function. + (objc_expand_function_end): Do not do anything for ordinary + C functions. + (finish_method_def): Mark ObjC methods as un-inlinable. + (gen_declaration_1): Emit widths of bitfields. + (finish_objc): Call generate_objc_image_info() if needed; + use check_duplicates() when checking for selector duplicates. + (generate_objc_image_info): New function. + * objc/objc-act.h (add_instance_method, add_class_method, + get_class_ivars): Remove prototypes. + (objc_build_throw_stmt, objc_build_try_catch_finally_stmt, + objc_build_synchronized_prologue, objc_build_synchronized_epilogue, + objc_build_catch_stmt, objc_build_catch_epilogue, + objc_build_finally_prologue, objc_build_finally_epilogue, + add_method, get_class_ivars_from_name): New prototypes. + (CLASS_BINFO_ELTS, PROTOCOL_BINFO_ELTS): New. + (TYPE_PROTOCOL_LIST): Robustify to distinguish from + TRANSLATION_UNIT_DECLs. + (OBJC_TYPE_NAME): New. + (objc_tree_code): Ensure that either <c-tree.h> or <cp/cp-tree.h> + got included. + (IS_SUPER): Robustify. + (umsg_stret_decl, umsg_super_stret_decl, umsg_nonnil_decl, + umsg_nonnil_stret_decl, objc_storage_class, objc_exception_extract_decl, + objc_exception_try_enter_decl, objc_exception_try_exit_decl, + objc_exception_match_decl, objc_exception_throw_decl, + objc_sync_enter_decl, objc_sync_exit_decl, objc_exception_data_template, + objc_setjmp_decl, objc_stack_exception_data, objc_caught_exception, + objc_rethrow_exception, objc_eval_once, objc_exception_block_stack, + objc_catch_type): New ObjC/ObjC++ roots. + * objc/objc-tree.def (MESSAGE_SEND_EXPR, CLASS_REFERENCE_EXPR): New + ObjC/ObjC++ tree node codes. + 2003-09-24 Alexandre Oliva <aoliva@redhat.com> * cpplib.c (do_pragma): Reintroduce cb_line_change call in the diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 61587d8..962951c 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -821,7 +821,7 @@ C_AND_OBJC_OBJS = attribs.o c-errors.o c-lex.o c-pragma.o c-decl.o c-typeck.o \ c-objc-common.o c-dump.o c-pch.o libcpp.a $(C_TARGET_OBJS) # Language-specific object files for C. -C_OBJS = c-parse.o c-lang.o c-pretty-print.o $(C_AND_OBJC_OBJS) +C_OBJS = c-parse.o c-lang.o c-pretty-print.o stub-objc.o $(C_AND_OBJC_OBJS) # Language-independent object files. @@ -1263,8 +1263,8 @@ $(parsedir)/c-parse.c: $(parsedir)/c-parse.y $(parsedir)/c-parse.y: c-parse.in echo '/*WARNING: This file is automatically generated!*/' >tmp-c-parse.y - sed -e "/^ifobjc$$/,/^end ifobjc$$/d" \ - -e "/^ifc$$/d" -e "/^end ifc$$/d" \ + sed -e "/^@@ifobjc.*/,/^@@end_ifobjc.*/d" \ + -e "/^@@ifc.*/d" -e "/^@@end_ifc.*/d" \ $(srcdir)/c-parse.in >>tmp-c-parse.y $(SHELL) $(srcdir)/move-if-change tmp-c-parse.y $(parsedir)/c-parse.y @@ -1281,6 +1281,7 @@ c-typeck.o : c-typeck.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $( c-lang.o : c-lang.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(C_TREE_H) $(C_PRETTY_PRINT_H) $(DIAGNOSTIC_H) \ $(GGC_H) langhooks.h $(LANGHOOKS_DEF_H) $(C_COMMON_H) gtype-c.h +stub-objc.o : stub-objc.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) $(C_COMMON_H) c-lex.o : c-lex.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(RTL_H) debug.h $(C_TREE_H) $(C_COMMON_H) real.h c-incpath.h cppdefault.h \ c-pragma.h input.h intl.h flags.h toplev.h output.h \ diff --git a/gcc/c-common.c b/gcc/c-common.c index db37be3..cef633a 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -346,7 +346,25 @@ int warn_format_nonliteral; int warn_format_security; - +/* Zero means that faster, ...NonNil variants of objc_msgSend... + calls will be used in ObjC; passing nil receivers to such calls + will most likely result in crashes. */ +int flag_nil_receivers = 1; + +/* Nonzero means that we will allow new ObjC exception syntax (@throw, + @try, etc.) in source code. */ +int flag_objc_exceptions = 0; + +/* Nonzero means that code generation will be altered to support + "zero-link" execution. This currently affects ObjC only, but may + affect other languages in the future. */ +int flag_zero_link = 0; + +/* Nonzero means emit an '__OBJC, __image_info' for the current translation + unit. It will inform the ObjC runtime that class definition(s) herein + contained are to replace one(s) previously loaded. */ +int flag_replace_objc_classes = 0; + /* C/ObjC language option variables. */ diff --git a/gcc/c-common.h b/gcc/c-common.h index 0bbc955..c8a0ecc 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -99,7 +99,10 @@ enum rid RID_ID, RID_AT_ENCODE, RID_AT_END, RID_AT_CLASS, RID_AT_ALIAS, RID_AT_DEFS, RID_AT_PRIVATE, RID_AT_PROTECTED, RID_AT_PUBLIC, - RID_AT_PROTOCOL, RID_AT_SELECTOR, RID_AT_INTERFACE, + RID_AT_PROTOCOL, RID_AT_SELECTOR, + RID_AT_THROW, RID_AT_TRY, RID_AT_CATCH, + RID_AT_FINALLY, RID_AT_SYNCHRONIZED, + RID_AT_INTERFACE, RID_AT_IMPLEMENTATION, RID_MAX, @@ -354,6 +357,25 @@ extern void resort_sorted_fields (void *, void *, gt_pointer_operator, extern int flag_preprocess_only; +/* Zero means that faster, ...NonNil variants of objc_msgSend... + calls will be used in ObjC; passing nil receivers to such calls + will most likely result in crashes. */ +extern int flag_nil_receivers; + +/* Nonzero means that we will allow new ObjC exception syntax (@throw, + @try, etc.) in source code. */ +extern int flag_objc_exceptions; + +/* Nonzero means that code generation will be altered to support + "zero-link" execution. This currently affects ObjC only, but may + affect other languages in the future. */ +extern int flag_zero_link; + +/* Nonzero means emit an '__OBJC, __image_info' for the current translation + unit. It will inform the ObjC runtime that class definition(s) herein + contained are to replace one(s) previously loaded. */ +extern int flag_replace_objc_classes; + /* Nonzero means don't output line number information. */ extern char flag_no_line_commands; @@ -1309,6 +1331,19 @@ extern void fe_file_change (const struct line_map *); extern int c_estimate_num_insns (tree decl); extern bool c_decl_uninit (tree t); +/* The following have been moved here from c-tree.h, since they're needed + in the ObjC++ world, too. What is more, stub-objc.c could use a few + prototypes. */ +extern tree lookup_interface (tree); +extern tree is_class_name (tree); +extern tree objc_is_object_ptr (tree); +extern void objc_check_decl (tree); +extern int objc_comptypes (tree, tree, int); +extern tree objc_message_selector (void); +extern tree lookup_objc_ivar (tree); +extern void *get_current_scope (void); +extern void objc_mark_locals_volatile (void *); + /* In c-ppoutput.c */ extern void init_pp_output (FILE *); extern void preprocess_file (cpp_reader *); diff --git a/gcc/c-decl.c b/gcc/c-decl.c index db35f9a..bb1c4b0 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -410,6 +410,39 @@ pop_scope (void) scope_freelist = scope; } +/* The Objective-C front-end often needs to determine the current scope. */ + +void * +get_current_scope (void) +{ + return current_scope; +} + +/* The following function is used only by Objective-C. It needs to live here + because it accesses the innards of c_scope. */ + +void +objc_mark_locals_volatile (void *enclosing_blk) +{ + struct c_scope *scope; + + for (scope = current_scope; + scope && scope != enclosing_blk; + scope = scope->outer) + { + tree decl; + + for (decl = scope->names; decl; decl = TREE_CHAIN (decl)) + { + DECL_REGISTER (decl) = 0; + TREE_THIS_VOLATILE (decl) = 1; + } + /* Do not climb up past the current function. */ + if (scope->function_body) + break; + } +} + /* Nonzero if we are currently in the global scope. */ int @@ -2718,6 +2751,11 @@ finish_decl (tree decl, tree init, tree asmspec_tree) if (init) store_init_value (decl, init); + if (c_dialect_objc () && (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == FIELD_DECL)) + objc_check_decl (decl); + /* Deduce size of array from initialization, if not already known */ if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type) == 0 @@ -2909,12 +2947,7 @@ finish_decl (tree decl, tree init, tree asmspec_tree) mark_referenced (DECL_ASSEMBLER_NAME (decl)); if (TREE_CODE (decl) == TYPE_DECL) - { - /* This is a no-op in c-lang.c or something real in objc-act.c. */ - if (c_dialect_objc ()) - objc_check_decl (decl); - rest_of_decl_compilation (decl, NULL, DECL_FILE_SCOPE_P (decl), 0); - } + rest_of_decl_compilation (decl, NULL, DECL_FILE_SCOPE_P (decl), 0); /* At the end of a declaration, throw away any variable type sizes of types defined inside that declaration. There is no use @@ -4778,8 +4811,6 @@ grokfield (tree declarator, tree declspecs, tree width) finish_decl (value, NULL_TREE, NULL_TREE); DECL_INITIAL (value) = width; - if (c_dialect_objc ()) - objc_check_decl (value); return value; } diff --git a/gcc/c-lang.c b/gcc/c-lang.c index a6a4ede..1a097e2 100644 --- a/gcc/c-lang.c +++ b/gcc/c-lang.c @@ -179,52 +179,6 @@ const char *const tree_code_name[] = { }; #undef DEFTREECODE -/* Used by c-lex.c, but only for objc. */ - -tree -lookup_interface (tree arg ATTRIBUTE_UNUSED) -{ - return 0; -} - -tree -is_class_name (tree arg ATTRIBUTE_UNUSED) -{ - return 0; -} - -tree -objc_is_id (tree arg ATTRIBUTE_UNUSED) -{ - return 0; -} - -void -objc_check_decl (tree decl ATTRIBUTE_UNUSED) -{ -} - -int -objc_comptypes (tree lhs ATTRIBUTE_UNUSED, tree rhs ATTRIBUTE_UNUSED, - int reflexive ATTRIBUTE_UNUSED) -{ - return -1; -} - -tree -objc_message_selector (void) -{ - return 0; -} - -/* Used by c-typeck.c (build_external_ref), but only for objc. */ - -tree -lookup_objc_ivar (tree id ATTRIBUTE_UNUSED) -{ - return 0; -} - void finish_file (void) { @@ -244,5 +198,4 @@ c_initialize_diagnostics (diagnostic_context *context) free (base); } - #include "gtype-c.h" diff --git a/gcc/c-opts.c b/gcc/c-opts.c index ee957f7..7763702 100644 --- a/gcc/c-opts.c +++ b/gcc/c-opts.c @@ -847,10 +847,18 @@ c_common_handle_option (size_t scode, const char *arg, int value) flag_next_runtime = value; break; + case OPT_fnil_receivers: + flag_nil_receivers = value; + break; + case OPT_fnonansi_builtins: flag_no_nonansi_builtin = !value; break; + case OPT_fobjc_exceptions: + flag_objc_exceptions = value; + break; + case OPT_foperator_names: cpp_opts->operator_names = value; break; @@ -871,6 +879,10 @@ c_common_handle_option (size_t scode, const char *arg, int value) cpp_opts->preprocessed = value; break; + case OPT_freplace_objc_classes: + flag_replace_objc_classes = value; + break; + case OPT_frepo: flag_use_repository = value; if (value) @@ -915,6 +927,10 @@ c_common_handle_option (size_t scode, const char *arg, int value) flag_weak = value; break; + case OPT_fzero_link: + flag_zero_link = value; + break; + case OPT_gen_decls: flag_gen_declaration = 1; break; diff --git a/gcc/c-parse.in b/gcc/c-parse.in index bb9cc1a..3d14d916 100644 --- a/gcc/c-parse.in +++ b/gcc/c-parse.in @@ -20,17 +20,17 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This file defines the grammar of C and that of Objective C. - ifobjc ... end ifobjc conditionals contain code for Objective C only. - ifc ... end ifc conditionals contain code for C only. + @@ifobjc ... @@end_ifobjc conditionals contain code for Objective C only. + @@ifc ... @@end_ifc conditionals contain code for C only. Sed commands in Makefile.in are used to convert this file into c-parse.y and into objc-parse.y. */ /* To whomever it may concern: I have heard that such a thing was once written by AT&T, but I have never seen it. */ -ifc +@@ifc %expect 10 /* shift/reduce conflicts, and no reduce/reduce conflicts. */ -end ifc +@@end_ifc %{ #include "config.h" @@ -50,9 +50,9 @@ end ifc #include "toplev.h" #include "ggc.h" -ifobjc +@@ifobjc #include "objc-act.h" -end ifobjc +@@end_ifobjc /* Like YYERROR but do call yyerror. */ #define YYERROR1 { yyerror ("syntax error"); YYERROR; } @@ -175,6 +175,7 @@ do { \ Objective C, so that the token codes are the same in both. */ %token INTERFACE IMPLEMENTATION END SELECTOR DEFS ENCODE %token CLASSNAME PUBLIC PRIVATE PROTECTED PROTOCOL OBJECTNAME CLASS ALIAS +%token AT_THROW AT_TRY AT_CATCH AT_FINALLY AT_SYNCHRONIZED %token OBJC_STRING %type <code> unop @@ -233,7 +234,7 @@ do { \ %type <location> save_location -ifobjc +@@ifobjc /* the Objective-C nonterminals */ %type <ttype> ivar_decl_list ivar_decls ivar_decl ivars ivar_declarator @@ -245,7 +246,10 @@ ifobjc %type <ttype> non_empty_protocolrefs protocolrefs identifier_list objcprotocolexpr %type <ttype> CLASSNAME OBJECTNAME OBJC_STRING -end ifobjc + +%type <ttype> objc_try_stmt superclass +%type <itype> objc_try_catch_stmt objc_finally_block +@@end_ifobjc %{ /* Number of statements (loosely speaking) and compound statements @@ -306,7 +310,7 @@ static GTY(()) tree declspec_stack; flag_iso = (val >> 3) & 1; \ } while (0) -ifobjc +@@ifobjc /* Objective-C specific parser/lexer information */ static enum tree_code objc_inherit_code; @@ -318,11 +322,11 @@ static int objc_pq_context = 0, objc_public_flag = 0; exists. */ static int objc_need_raw_identifier; #define OBJC_NEED_RAW_IDENTIFIER(VAL) objc_need_raw_identifier = VAL -end ifobjc +@@end_ifobjc -ifc +@@ifc #define OBJC_NEED_RAW_IDENTIFIER(VAL) /* nothing */ -end ifc +@@end_ifc static bool parsing_iso_function_signature; @@ -371,9 +375,9 @@ extdef: extdef_1: fndef | datadef -ifobjc +@@ifobjc | objcdef -end ifobjc +@@end_ifobjc | ASM_KEYWORD '(' expr ')' ';' { STRIP_NOPS ($3); if ((TREE_CODE ($3) == ADDR_EXPR @@ -452,10 +456,10 @@ fndef: identifier: IDENTIFIER | TYPENAME -ifobjc +@@ifobjc | OBJECTNAME | CLASSNAME -end ifobjc +@@end_ifobjc ; unop: '&' @@ -464,10 +468,10 @@ unop: '&' { $$ = NEGATE_EXPR; } | '+' { $$ = CONVERT_EXPR; -ifc +@@ifc if (warn_traditional && !in_system_header) warning ("traditional C rejects the unary plus operator"); -end ifc +@@end_ifc } | PLUSPLUS { $$ = PREINCREMENT_EXPR; } @@ -708,29 +712,29 @@ primary: { $$ = build_array_ref ($1, $3); } | primary '.' identifier { -ifobjc +@@ifobjc if (!is_public ($1, $3)) $$ = error_mark_node; else -end ifobjc +@@end_ifobjc $$ = build_component_ref ($1, $3); } | primary POINTSAT identifier { tree expr = build_indirect_ref ($1, "->"); -ifobjc +@@ifobjc if (!is_public (expr, $3)) $$ = error_mark_node; else -end ifobjc +@@end_ifobjc $$ = build_component_ref (expr, $3); } | primary PLUSPLUS { $$ = build_unary_op (POSTINCREMENT_EXPR, $1, 0); } | primary MINUSMINUS { $$ = build_unary_op (POSTDECREMENT_EXPR, $1, 0); } -ifobjc +@@ifobjc | objcmessageexpr { $$ = build_message_expr ($1); } | objcselectorexpr @@ -741,7 +745,7 @@ ifobjc { $$ = build_encode_expr ($1); } | OBJC_STRING { $$ = build_objc_string_object ($1); } -end ifobjc +@@end_ifobjc ; old_style_parm_decls: @@ -1356,7 +1360,7 @@ typespec_nonreserved_nonattr: { /* For a typedef name, record the meaning, not the name. In case of `foo foo, bar;'. */ $$ = lookup_name ($1); } -ifobjc +@@ifobjc | CLASSNAME protocolrefs { $$ = get_static_reference ($1, $2); } | OBJECTNAME protocolrefs @@ -1366,7 +1370,7 @@ ifobjc - nisse@lysator.liu.se */ | non_empty_protocolrefs { $$ = get_object_reference ($1); } -end ifobjc +@@end_ifobjc | typeof '(' expr ')' { skip_evaluation--; $$ = TREE_TYPE ($3); } | typeof '(' typename ')' @@ -1632,9 +1636,9 @@ after_type_declarator: | '*' maybe_type_quals_attrs after_type_declarator %prec UNARY { $$ = make_pointer_declarator ($2, $3); } | TYPENAME -ifobjc +@@ifobjc | OBJECTNAME -end ifobjc +@@end_ifobjc ; /* Kinds of declarator that can appear in a parameter list @@ -1655,9 +1659,9 @@ parm_declarator_starttypename: | parm_declarator_starttypename array_declarator %prec '.' { $$ = set_array_declarator_type ($2, $1, 0); } | TYPENAME -ifobjc +@@ifobjc | OBJECTNAME -end ifobjc +@@end_ifobjc ; parm_declarator_nostarttypename: @@ -1806,22 +1810,11 @@ component_decl_list2: /* empty */ | component_decl_list2 ';' { if (pedantic) pedwarn ("extra semicolon in struct or union specified"); } -ifobjc +@@ifobjc /* foo(sizeof(struct{ @defs(ClassName)})); */ | DEFS '(' CLASSNAME ')' - { - tree interface = lookup_interface ($3); - - if (interface) - $$ = nreverse (get_class_ivars (interface)); - else - { - error ("cannot find interface declaration for `%s'", - IDENTIFIER_POINTER ($3)); - $$ = NULL_TREE; - } - } -end ifobjc + { $$ = nreverse (get_class_ivars_from_name ($3)); } +@@end_ifobjc ; component_decl: @@ -2056,15 +2049,17 @@ pushlevel: /* empty */ { pushlevel (0); clear_last_expr (); add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0); -ifobjc - if (objc_method_context) - add_objc_decls (); -end ifobjc } ; poplevel: /* empty */ - { $$ = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0); } + { +@@ifobjc + if (c_dialect_objc ()) + objc_clear_super_receiver (); +@@end_ifobjc + $$ = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0); + } ; /* Start and end blocks created for the new scopes of C99. */ @@ -2075,10 +2070,6 @@ c99_block_start: /* empty */ pushlevel (0); clear_last_expr (); add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0); -ifobjc - if (objc_method_context) - add_objc_decls (); -end ifobjc } else $$ = NULL_TREE; @@ -2404,6 +2395,59 @@ stmt: $$ = add_stmt (build_stmt (GOTO_STMT, $3)); } | ';' { $$ = NULL_TREE; } +@@ifobjc + | AT_THROW expr ';' + { stmt_count++; + $$ = objc_build_throw_stmt ($2); + } + | AT_THROW ';' + { stmt_count++; + $$ = objc_build_throw_stmt (NULL_TREE); + } + | objc_try_catch_stmt + { objc_build_finally_prologue (); } + objc_finally_block + { $$ = objc_build_try_catch_finally_stmt ($1, $3); } + | AT_SYNCHRONIZED '(' expr ')' + { objc_build_synchronized_prologue ($3); } + compstmt + { $$ = objc_build_synchronized_epilogue (); } + ; + +objc_try_catch_stmt: + objc_try_stmt + { objc_build_try_epilogue (1); } + objc_catch_list + { objc_build_catch_epilogue (); $$ = 1; } + | objc_try_stmt + { objc_build_try_epilogue (0); $$ = 0; } + ; + + +objc_try_stmt: + AT_TRY + { objc_build_try_prologue (); } + compstmt + ; + +objc_catch_list: + objc_catch_list objc_catch_block + | objc_catch_block + ; + +objc_catch_block: + AT_CATCH '(' parm ')' + { objc_build_catch_stmt ($3); } + compstmt + { stmt_count++; } + ; + +objc_finally_block: + AT_FINALLY compstmt + { $$ = 1; } + | /* NULL */ + { $$ = 0; } +@@end_ifobjc ; /* Any kind of label, including jump labels and case labels. @@ -2648,7 +2692,7 @@ extension: flag_iso = 0; } ; -ifobjc +@@ifobjc /* Objective-C productions. */ objcdef: @@ -2692,115 +2736,52 @@ aliasdecl: } ; -classdef: - INTERFACE identifier protocolrefs '{' - { - objc_interface_context = objc_ivar_context - = start_class (CLASS_INTERFACE_TYPE, $2, NULL_TREE, $3); - objc_public_flag = 0; - } - ivar_decl_list '}' - { - continue_class (objc_interface_context); - } - methodprotolist - END - { - finish_class (objc_interface_context); - objc_interface_context = NULL_TREE; - } +superclass: + ':' identifier { $$ = $2; } + | /* NULL */ %prec HYPERUNARY { $$ = NULL_TREE; } + ; - | INTERFACE identifier protocolrefs - { - objc_interface_context - = start_class (CLASS_INTERFACE_TYPE, $2, NULL_TREE, $3); - continue_class (objc_interface_context); - } - methodprotolist - END - { - finish_class (objc_interface_context); - objc_interface_context = NULL_TREE; - } +class_ivars: + '{' ivar_decl_list '}' + | /* NULL */ + ; - | INTERFACE identifier ':' identifier protocolrefs '{' +classdef: + INTERFACE identifier superclass protocolrefs { objc_interface_context = objc_ivar_context - = start_class (CLASS_INTERFACE_TYPE, $2, $4, $5); + = start_class (CLASS_INTERFACE_TYPE, $2, $3, $4); objc_public_flag = 0; } - ivar_decl_list '}' + class_ivars { continue_class (objc_interface_context); } - methodprotolist - END - { - finish_class (objc_interface_context); - objc_interface_context = NULL_TREE; - } - - | INTERFACE identifier ':' identifier protocolrefs - { - objc_interface_context - = start_class (CLASS_INTERFACE_TYPE, $2, $4, $5); - continue_class (objc_interface_context); - } - methodprotolist - END + methodprotolist END { finish_class (objc_interface_context); objc_interface_context = NULL_TREE; } - | IMPLEMENTATION identifier '{' - { - objc_implementation_context = objc_ivar_context - = start_class (CLASS_IMPLEMENTATION_TYPE, $2, NULL_TREE, NULL_TREE); - objc_public_flag = 0; - } - ivar_decl_list '}' - { - objc_ivar_chain - = continue_class (objc_implementation_context); - } - - | IMPLEMENTATION identifier - { - objc_implementation_context - = start_class (CLASS_IMPLEMENTATION_TYPE, $2, NULL_TREE, NULL_TREE); - objc_ivar_chain - = continue_class (objc_implementation_context); - } - - | IMPLEMENTATION identifier ':' identifier '{' + | IMPLEMENTATION identifier superclass { objc_implementation_context = objc_ivar_context - = start_class (CLASS_IMPLEMENTATION_TYPE, $2, $4, NULL_TREE); + = start_class (CLASS_IMPLEMENTATION_TYPE, $2, $3, NULL_TREE); objc_public_flag = 0; } - ivar_decl_list '}' + class_ivars { objc_ivar_chain = continue_class (objc_implementation_context); } - | IMPLEMENTATION identifier ':' identifier - { - objc_implementation_context - = start_class (CLASS_IMPLEMENTATION_TYPE, $2, $4, NULL_TREE); - objc_ivar_chain - = continue_class (objc_implementation_context); - } - | INTERFACE identifier '(' identifier ')' protocolrefs { objc_interface_context = start_class (CATEGORY_INTERFACE_TYPE, $2, $4, $6); continue_class (objc_interface_context); } - methodprotolist - END + methodprotolist END { finish_class (objc_interface_context); objc_interface_context = NULL_TREE; @@ -2947,10 +2928,7 @@ methoddef: methoddecl { objc_pq_context = 0; - if (objc_inherit_code == CLASS_METHOD_DECL) - add_class_method (objc_implementation_context, $3); - else - add_instance_method (objc_implementation_context, $3); + add_method (objc_implementation_context, $3, objc_inherit_code == CLASS_METHOD_DECL); start_method_def ($3); } optarglist @@ -2969,14 +2947,8 @@ methoddef: methodprotolist: /* empty */ - | {$<ttype>$ = NULL_TREE; } methodprotolist2 - ; - -methodprotolist2: /* eliminates a shift/reduce conflict */ - methodproto - | datadef - | methodprotolist2 methodproto - | methodprotolist2 {$<ttype>$ = NULL_TREE; } datadef + | methodprotolist methodproto + | methodprotolist { $<ttype>$ = NULL_TREE; } datadef ; semi_or_error: @@ -2994,10 +2966,7 @@ methodproto: { /* Forget protocol qualifiers here. */ objc_pq_context = 0; - if (objc_inherit_code == CLASS_METHOD_DECL) - add_class_method (objc_interface_context, $3); - else - add_instance_method (objc_interface_context, $3); + add_method (objc_interface_context, $3, objc_inherit_code == CLASS_METHOD_DECL); } semi_or_error ; @@ -3194,6 +3163,10 @@ receiver: { $$ = get_class_reference ($1); } + | TYPENAME + { + $$ = get_class_reference ($1); + } ; objcmessageexpr: @@ -3248,7 +3221,7 @@ objcencodeexpr: } ; -end ifobjc +@@end_ifobjc %% /* yylex() is a thin wrapper around c_lex(), all it does is translate @@ -3350,7 +3323,7 @@ static const struct resword reswords[] = { "void", RID_VOID, 0 }, { "volatile", RID_VOLATILE, 0 }, { "while", RID_WHILE, 0 }, -ifobjc +@@ifobjc { "id", RID_ID, D_OBJC }, /* These objc keywords are recognized only immediately after @@ -3367,7 +3340,11 @@ ifobjc { "protocol", RID_AT_PROTOCOL, D_OBJC }, { "public", RID_AT_PUBLIC, D_OBJC }, { "selector", RID_AT_SELECTOR, D_OBJC }, - + { "throw", RID_AT_THROW, D_OBJC }, + { "try", RID_AT_TRY, D_OBJC }, + { "catch", RID_AT_CATCH, D_OBJC }, + { "finally", RID_AT_FINALLY, D_OBJC }, + { "synchronized", RID_AT_SYNCHRONIZED, D_OBJC }, /* These are recognized only in protocol-qualifier context (see above) */ { "bycopy", RID_BYCOPY, D_OBJC }, @@ -3376,7 +3353,7 @@ ifobjc { "inout", RID_INOUT, D_OBJC }, { "oneway", RID_ONEWAY, D_OBJC }, { "out", RID_OUT, D_OBJC }, -end ifobjc +@@end_ifobjc }; #define N_reswords (sizeof reswords / sizeof (struct resword)) @@ -3503,6 +3480,11 @@ static const short rid_to_yy[RID_MAX] = /* RID_AT_PUBLIC */ PUBLIC, /* RID_AT_PROTOCOL */ PROTOCOL, /* RID_AT_SELECTOR */ SELECTOR, + /* RID_AT_THROW */ AT_THROW, + /* RID_AT_TRY */ AT_TRY, + /* RID_AT_CATCH */ AT_CATCH, + /* RID_AT_FINALLY */ AT_FINALLY, + /* RID_AT_SYNCHRONIZED */ AT_SYNCHRONIZED, /* RID_AT_INTERFACE */ INTERFACE, /* RID_AT_IMPLEMENTATION */ IMPLEMENTATION }; @@ -3567,16 +3549,16 @@ yylexname (void) { tree decl; -ifobjc +@@ifobjc int objc_force_identifier = objc_need_raw_identifier; OBJC_NEED_RAW_IDENTIFIER (0); -end ifobjc +@@end_ifobjc if (C_IS_RESERVED_WORD (yylval.ttype)) { enum rid rid_code = C_RID_CODE (yylval.ttype); -ifobjc +@@ifobjc /* Turn non-typedefed refs to "id" into plain identifiers; this allows constructs like "void foo(id id);" to work. */ if (rid_code == RID_ID) @@ -3588,7 +3570,7 @@ ifobjc if (!OBJC_IS_AT_KEYWORD (rid_code) && (!OBJC_IS_PQ_KEYWORD (rid_code) || objc_pq_context)) -end ifobjc +@@end_ifobjc { /* Return the canonical spelling for this keyword. */ yylval.ttype = ridpointers[(int) rid_code]; @@ -3602,7 +3584,7 @@ end ifobjc if (TREE_CODE (decl) == TYPE_DECL) return TYPENAME; } -ifobjc +@@ifobjc else { tree objc_interface_decl = is_class_name (yylval.ttype); @@ -3616,7 +3598,7 @@ ifobjc return CLASSNAME; } } -end ifobjc +@@end_ifobjc return IDENTIFIER; } diff --git a/gcc/c-tree.h b/gcc/c-tree.h index 76c77ec..96faf84 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -153,17 +153,6 @@ struct lang_type GTY(()) #define KEEP_MAYBE 2 -/* in c-lang.c and objc-act.c */ -extern tree lookup_interface (tree); -extern tree is_class_name (tree); -extern tree objc_is_id (tree); -extern void objc_check_decl (tree); -extern int objc_comptypes (tree, tree, int); -extern tree objc_message_selector (void); -extern tree lookup_objc_ivar (tree); -extern void c_expand_body (tree); - - /* in c-parse.in */ extern void c_parse_init (void); @@ -177,6 +166,7 @@ extern void pushlevel (int); extern void insert_block (tree); extern void set_block (tree); extern tree pushdecl (tree); +extern void c_expand_body (tree); extern void c_init_decl_processing (void); extern void c_dup_lang_specific_decl (tree); @@ -306,6 +296,8 @@ extern int system_header_p; /* In c-decl.c */ extern void c_finish_incomplete_decl (tree); +extern void *get_current_scope (void); +extern void objc_mark_locals_volatile (void *); extern void c_write_global_declarations (void); extern GTY(()) tree static_ctors; diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 23e73e8..51887599 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -511,8 +511,12 @@ comptypes (tree type1, tree type2, int flags) switch (TREE_CODE (t1)) { case POINTER_TYPE: + /* We must give ObjC the first crack at comparing pointers, since + protocol qualifiers may be involved. */ + if (c_dialect_objc () && (val = objc_comptypes (t1, t2, 0)) >= 0) + break; val = (TREE_TYPE (t1) == TREE_TYPE (t2) - ? 1 : comptypes (TREE_TYPE (t1), TREE_TYPE (t2), flags)); + ? 1 : comptypes (TREE_TYPE (t1), TREE_TYPE (t2), flags)); break; case FUNCTION_TYPE: @@ -560,6 +564,8 @@ comptypes (tree type1, tree type2, int flags) } case RECORD_TYPE: + /* We are dealing with two distinct structs. In assorted Objective-C + corner cases, however, these can still be deemed equivalent. */ if (c_dialect_objc () && objc_comptypes (t1, t2, 0) == 1) val = 1; @@ -2927,7 +2933,7 @@ build_c_cast (tree type, tree expr) /* The ObjC front-end uses TYPE_MAIN_VARIANT to tie together types differing only in <protocol> qualifications. But when constructing cast expressions, the protocols do matter and must be kept around. */ - if (!c_dialect_objc () || !objc_is_id (type)) + if (!c_dialect_objc () || !objc_is_object_ptr (type)) type = TYPE_MAIN_VARIANT (type); if (TREE_CODE (type) == ARRAY_TYPE) @@ -3488,6 +3494,7 @@ convert_for_assignment (tree type, tree rhs, const char *errtype, tree ttl = TREE_TYPE (type); tree ttr = TREE_TYPE (rhstype); bool is_opaque_pointer; + int target_cmp = 0; /* Cache comp_target_types () result. */ /* Opaque pointers are treated like void pointers. */ is_opaque_pointer = ((*targetm.vector_opaque_p) (type) @@ -3499,7 +3506,7 @@ convert_for_assignment (tree type, tree rhs, const char *errtype, and vice versa; otherwise, targets must be the same. Meanwhile, the lhs target must have all the qualifiers of the rhs. */ if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr) - || comp_target_types (type, rhstype, 0) + || (target_cmp = comp_target_types (type, rhstype, 0)) || is_opaque_pointer || (c_common_unsigned_type (TYPE_MAIN_VARIANT (ttl)) == c_common_unsigned_type (TYPE_MAIN_VARIANT (ttr)))) @@ -3525,7 +3532,7 @@ convert_for_assignment (tree type, tree rhs, const char *errtype, /* If this is not a case of ignoring a mismatch in signedness, no warning. */ else if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr) - || comp_target_types (type, rhstype, 0)) + || target_cmp) ; /* If there is a mismatch, do warn. */ else if (pedantic) @@ -551,7 +551,11 @@ C++ ObjC++ fnext-runtime ObjC ObjC++ -Generate code for NeXT runtime environment +Generate code for NeXT (Apple Mac OS X) runtime environment + +fnil-receivers +ObjC ObjC++ +Assume that receivers of Objective-C messages may be nil fnonansi-builtins C++ ObjC++ @@ -559,6 +563,10 @@ C++ ObjC++ fnonnull-objects C++ ObjC++ +fobjc-exceptions +ObjC ObjC++ +Enable Objective-C exception and synchronization syntax + foperator-names C++ ObjC++ Recognize C++ kewords like \"compl\" and \"xor\" @@ -578,6 +586,10 @@ fpreprocessed C ObjC C++ ObjC++ Treat the input file as already preprocessed +freplace-objc-classes +ObjC ObjC++ +Used in Fix-and-Continue mode to indicate that object files may be swapped in at runtime + frepo C++ ObjC++ Enable automatic template instantiation @@ -666,6 +678,10 @@ fxref C++ ObjC++ Emit cross referencing information +fzero-link +ObjC ObjC++ +Generate lazy class lookup (via objc_getClass()) for use in Zero-Link mode + gen-decls ObjC ObjC++ Dump declarations to a .decl file diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c index 4e1c45c..dc86462 100644 --- a/gcc/config/darwin.c +++ b/gcc/config/darwin.c @@ -1214,6 +1214,8 @@ machopic_select_section (tree exp, int reloc, objc_symbols_section (); else if (!strncmp (name, "_OBJC_MODULES", 13)) objc_module_info_section (); + else if (!strncmp (name, "_OBJC_IMAGE_INFO", 16)) + objc_image_info_section (); else if (!strncmp (name, "_OBJC_PROTOCOL_INSTANCE_METHODS_", 32)) objc_cat_inst_meth_section (); else if (!strncmp (name, "_OBJC_PROTOCOL_CLASS_METHODS_", 29)) diff --git a/gcc/config/darwin.h b/gcc/config/darwin.h index 528140d..3541515 100644 --- a/gcc/config/darwin.h +++ b/gcc/config/darwin.h @@ -510,6 +510,7 @@ FUNCTION (void) \ in_objc_symbols, in_objc_module_info, \ in_objc_protocol, in_objc_string_object, \ in_objc_constant_string_object, \ + in_objc_image_info, \ in_objc_class_names, in_objc_meth_var_names, \ in_objc_meth_var_types, in_objc_cls_refs, \ in_machopic_nl_symbol_ptr, \ @@ -599,6 +600,10 @@ SECTION_FUNCTION (objc_string_object_section, \ SECTION_FUNCTION (objc_constant_string_object_section, \ in_objc_constant_string_object, \ ".section __OBJC, __cstring_object", 1) \ +/* Fix-and-Continue image marker. */ \ +SECTION_FUNCTION (objc_image_info_section, \ + in_objc_image_info, \ + ".section __OBJC, __image_info", 1) \ SECTION_FUNCTION (objc_class_names_section, \ in_objc_class_names, \ ".objc_class_names", 1) \ diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index e137515..0bd16fb 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -193,8 +193,14 @@ in the following sections. @item Objective-C Language Options @xref{Objective-C Dialect Options,,Options Controlling Objective-C Dialect}. -@gccoptlist{-fconstant-string-class=@var{class-name} @gol --fgnu-runtime -fnext-runtime -gen-decls @gol +@gccoptlist{ +-fconstant-string-class=@var{class-name} @gol +-fgnu-runtime -fnext-runtime @gol +-fno-nil-receivers @gol +-fobjc-exceptions @gol +-freplace-objc-classes @gol +-fzero-link @gol +-gen-decls @gol -Wno-protocol -Wselector -Wundeclared-selector} @item Language Independent Options @@ -1743,6 +1749,9 @@ In this example, G++ will synthesize a default @samp{A& operator = @cindex compiler options, Objective-C @cindex Objective-C options, command line @cindex options, Objective-C +(NOTE: This manual does not describe the Objective-C language itself. See +@w{@uref{http://gcc.gnu.org/readings.html}} for references.) + This section describes the command-line options that are only meaningful for Objective-C programs, but you can also use most of the GNU compiler options regardless of what language your program is in. For example, @@ -1765,7 +1774,11 @@ programs: @opindex fconstant-string-class Use @var{class-name} as the name of the class to instantiate for each literal string specified with the syntax @code{@@"@dots{}"}. The default -class name is @code{NXConstantString}. +class name is @code{NXConstantString} if the GNU runtime is being used, and +@code{NSConstantString} if the NeXT runtime is being used (see below). The +@option{-fconstant-cfstrings} option, if also present, will override the +@option{-fconstant-string-class} setting and cause @code{@@"@dots{}"} literals +to be laid out as constant CoreFoundation strings. @item -fgnu-runtime @opindex fgnu-runtime @@ -1779,6 +1792,127 @@ for NeXT-based systems, including Darwin and Mac OS X@. The macro @code{__NEXT_RUNTIME__} is predefined if (and only if) this option is used. +@item -fno-nil-receivers +@opindex -fno-nil-receivers +Assume that all Objective-C message dispatches (e.g., +@code{[receiver message:arg]}) in this translation unit ensure that the receiver +is not @code{nil}. This allows for more efficient entry points in the runtime to be +used. Currently, this option is only available in conjunciton with +the NeXT runtime on Mac OS X 10.3 and later. + +@item -fobjc-exceptions +@opindex -fobjc-exceptions +Enable syntactic support for structured exception handling in Objective-C, +similar to what is offered by C++ and Java. Currently, this option is only +available in conjunciton with the NeXT runtime on Mac OS X 10.3 and later. + +@smallexample + @@try @{ + @dots{} + @@throw expr; + @dots{} + @} + @@catch (AnObjCClass *exc) @{ + @dots{} + @@throw expr; + @dots{} + @@throw; + @dots{} + @} + @@catch (AnotherClass *exc) @{ + @dots{} + @} + @@catch (id allOthers) @{ + @dots{} + @} + @@finally @{ + @dots{} + @@throw expr; + @dots{} + @} +@end smallexample + +The @code{@@throw} statement may appear anywhere in an Objective-C or +Objective-C++ program; when used inside of a @code{@@catch} block, the +@code{@@throw} may appear without an argument (as shown above), in which case +the object caught by the @code{@@catch} will be rethrown. + +Note that only (pointers to) Objective-C objects may be thrown and +caught using this scheme. When an object is thrown, it will be caught +by the nearest @code{@@catch} clause capable of handling objects of that type, +analogously to how @code{catch} blocks work in C++ and Java. A +@code{@@catch(id @dots{})} clause (as shown above) may also be provided to catch +any and all Objective-C exceptions not caught by previous @code{@@catch} +clauses (if any). + +The @code{@@finally} clause, if present, will be executed upon exit from the +immediately preceding @code{@@try @dots{} @@catch} section. This will happen +regardless of whether any exceptions are thrown, caught or rethrown +inside the @code{@@try @dots{} @@catch} section, analogously to the behavior +of the @code{finally} clause in Java. + +There are several caveats to using the new exception mechanism: + +@itemize @bullet +@item +Although currently designed to be binary compatible with @code{NS_HANDLER}-style +idioms provided by the @code{NSException} class, the new +exceptions can only be used on Mac OS X 10.3 (Panther) and later +systems, due to additional functionality needed in the (NeXT) Objective-C +runtime. + +@item +As mentioned above, the new exceptions do not support handling +types other than Objective-C objects. Furthermore, when used from +Objective-C++, the Objective-C exception model does not interoperate with C++ +exceptions at this time. This means you cannot @code{@@throw} an exception +from Objective-C and @code{catch} it in C++, or vice versa +(i.e., @code{throw @dots{} @@catch}). +@end itemize + +The @option{-fobjc-exceptions} switch also enables the use of synchronization +blocks for thread-safe execution: + +@smallexample + @@synchronized (ObjCClass *guard) @{ + @dots{} + @} +@end smallexample + +Upon entering the @code{@@synchronized} block, a thread of execution shall +first check whether a lock has been placed on the corresponding @code{guard} +object by another thread. If it has, the current thread shall wait until +the other thread relinquishes its lock. Once @code{guard} becomes available, +the current thread will place its own lock on it, execute the code contained in +the @code{@@synchronized} block, and finally relinquish the lock (thereby +making @code{guard} available to other threads). + +Unlike Java, Objective-C does not allow for entire methods to be marked +@code{@@synchronized}. Note that throwing exceptions out of +@code{@@synchronized} blocks is allowed, and will cause the guarding object +to be unlocked properly. + +@item -freplace-objc-classes +@opindex -freplace-objc-classes +Emit a special marker instructing @command{ld(1)} not to statically link in +the resulting object file, and allow @command{dyld(1)} to load it in at +run time instead. This is used in conjunction with the Fix-and-Continue +debugging mode, where the object file in question may be recompiled and +dynamically reloaded in the course of program execution, without the need +to restart the program itself. Currently, Fix-and-Continue functionality +is only available in conjunciton withthe NeXT runtime on Mac OS X 10.3 +and later. + +@item -fzero-link +@opindex -fzero-link +When compiling for the NeXT runtime, the compiler ordinarily replaces calls +to @code{objc_getClass("@dots{}")} (when the name of the class is known at +compile time) with static class references that get initialized at load time, +which improves run-time performance. Specifying the @option{-fzero-link} flag +suppresses this behavior and causes calls to @code{objc_getClass("@dots{}")} +to be retained. This is useful in Zero-Link debugging mode, since it allows +for individual class implementations to be modified during program execution. + @item -gen-decls @opindex gen-decls Dump interface declarations for all classes seen in the source file to a diff --git a/gcc/function.h b/gcc/function.h index f94a642..9c06d95 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -19,6 +19,9 @@ 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. */ +#ifndef GCC_FUNCTION_H +#define GCC_FUNCTION_H + struct var_refs_queue GTY(()) { rtx modified; @@ -628,3 +631,5 @@ extern void init_virtual_regs (struct emit_status *); /* Called once, at initialization, to initialize function.c. */ extern void init_function_once (void); + +#endif /* GCC_FUNCTION_H */ diff --git a/gcc/gengtype-lex.l b/gcc/gengtype-lex.l index ad70ba8..bbdf991 100644 --- a/gcc/gengtype-lex.l +++ b/gcc/gengtype-lex.l @@ -194,6 +194,8 @@ ITYPE {IWORD}({WS}{IWORD})* ^"%{" { BEGIN(in_yacc_escape); } +^"@@".* /* Used for c-parse.in C/ObjC demarcation. */ + {WS} { update_lineno (yytext, yyleng); } "const"/[^[:alnum:]_] /* don't care */ diff --git a/gcc/objc/Make-lang.in b/gcc/objc/Make-lang.in index 30ec482..c716e73 100644 --- a/gcc/objc/Make-lang.in +++ b/gcc/objc/Make-lang.in @@ -86,8 +86,8 @@ $(parsedir)/objc/objc-parse.c : $(parsedir)/objc/objc-parse.y $(parsedir)/objc/objc-parse.y: $(srcdir)/c-parse.in echo '/*WARNING: This file is automatically generated!*/' >tmp-objc-prs.y - sed -e "/^ifc$$/,/^end ifc$$/d" \ - -e "/^ifobjc$$/d" -e "/^end ifobjc$$/d" \ + sed -e "/^@@ifc.*/,/^@@end_ifc.*/d" \ + -e "/^@@ifobjc.*/d" -e "/^@@end_ifobjc.*/d" \ $(srcdir)/c-parse.in >>tmp-objc-prs.y $(SHELL) $(srcdir)/move-if-change tmp-objc-prs.y $(parsedir)/objc/objc-parse.y diff --git a/gcc/objc/lang-specs.h b/gcc/objc/lang-specs.h index 7c78420..39cbe5c 100644 --- a/gcc/objc/lang-specs.h +++ b/gcc/objc/lang-specs.h @@ -39,8 +39,8 @@ Boston, MA 02111-1307, USA. */ "%{!M:%{!MM:%{!E:cc1obj -fpreprocessed %i %(cc1_options) %{gen-decls}\ %{!fsyntax-only:%(invoke_as)}}}}", 0}, {"@objective-c-header", - "%{E|M|MM:%(trad_capable_cpp)\ - -lang-objc %(cpp_options) %(cpp_debug_options)}\ + "%{E|M|MM:cc1obj -E %{traditional|ftraditional|traditional-cpp:-traditional-cpp}\ + %(cpp_options) %(cpp_debug_options)}\ %{!E:%{!M:%{!MM:\ %{traditional|ftraditional|traditional-cpp:\ %eGNU Objective C no longer supports traditional compilation}\ diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 0c07543..40c7004 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -62,6 +62,8 @@ Boston, MA 02111-1307, USA. */ #include "diagnostic.h" #include "cgraph.h" +#define OBJC_VOID_AT_END build_tree_list (NULL_TREE, void_type_node) + /* This is the default way of generating a method name. */ /* I am not sure it is really correct. Perhaps there's a danger that it will make name conflicts @@ -89,19 +91,16 @@ Boston, MA 02111-1307, USA. */ #define OBJC_FORWARDING_MIN_OFFSET 0 #endif - /* Set up for use of obstacks. */ #include "obstack.h" /* This obstack is used to accumulate the encoding of a data type. */ static struct obstack util_obstack; -/* This points to the beginning of obstack contents, - so we can free the whole contents. */ -char *util_firstobj; -/* for encode_method_def */ -#include "rtl.h" +/* This points to the beginning of obstack contents, so we can free + the whole contents. */ +char *util_firstobj; /* The version identifies which language generation and runtime the module (file) was compiled for, and is recorded in the @@ -111,7 +110,7 @@ char *util_firstobj; #define PROTOCOL_VERSION 2 /* (Decide if these can ever be validly changed.) */ -#define OBJC_ENCODE_INLINE_DEFS 0 +#define OBJC_ENCODE_INLINE_DEFS 0 #define OBJC_ENCODE_DONT_INLINE_DEFS 1 /*** Private Interface (procedures) ***/ @@ -127,24 +126,35 @@ static void synth_module_prologue (void); static tree objc_build_constructor (tree, tree); static rtx build_module_descriptor (void); static tree init_module_descriptor (tree); -static tree build_objc_method_call (int, tree, tree, tree, tree, 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 objc_add_static_instance (tree, tree); +static void build_objc_exception_stuff (void); +static tree objc_declare_variable (enum rid, tree, tree, tree); +static tree objc_enter_block (void); +static tree objc_exit_block (void); +static void objc_build_try_enter_fragment (void); +static void objc_build_try_exit_fragment (void); +static void objc_build_extract_fragment (void); +static tree objc_build_extract_expr (void); + static tree build_ivar_template (void); static tree build_method_template (void); static tree build_private_template (tree); static void build_class_template (void); static void build_selector_template (void); static void build_category_template (void); -static tree build_super_template (void); +static tree lookup_method_in_hash_lists (tree); +static void build_super_template (void); static tree build_category_initializer (tree, tree, tree, tree, tree, tree); static tree build_protocol_initializer (tree, tree, tree, tree, tree); - static void synth_forward_declarations (void); +static int ivar_list_length (tree); +static tree get_class_ivars (tree, int); static void generate_ivar_lists (void); static void generate_dispatch_tables (void); static void generate_shared_structures (void); @@ -172,8 +182,7 @@ 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_instance_method_static (tree, tree); -static tree lookup_class_method_static (tree, tree); +static tree lookup_method_static (tree, tree, int); static tree add_class (tree); static void add_category (tree, tree); @@ -202,15 +211,18 @@ 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_bitfield (int); +static void encode_next_bitfield (int); +static void encode_gnu_bitfield (int, tree, int); static void encode_type (tree, int, int); static void encode_field_decl (tree, int, int); static void really_start_method (tree, tree); static int comp_method_with_proto (tree, tree); +static int objc_types_are_equivalent (tree, tree); static int comp_proto_with_proto (tree, tree); static tree get_arg_type_list (tree, int, int); static tree objc_expr_last (tree); +static void synth_self_and_ucmd_args (void); /* Utilities for debugging and error diagnostics. */ @@ -231,11 +243,12 @@ static tree lookup_method_in_protocol_list (tree, tree, int); static tree lookup_protocol_in_reflist (tree, tree); static tree create_builtin_decl (enum tree_code, tree, const char *); static void setup_string_decl (void); -static void build_string_class_template (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); @@ -247,12 +260,11 @@ static tree build_protocol_template (void); static tree build_descriptor_table_initializer (tree, tree); static tree build_method_prototype_list_template (tree, int); static tree build_method_prototype_template (void); -static int forwarding_offset (tree); -static tree encode_method_prototype (tree, tree); +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 tree build_tmp_function_decl (void); -static void hack_method_prototype (tree, tree); static void generate_protocol_references (tree); static void generate_protocols (void); static void check_ivars (tree, tree); @@ -262,25 +274,24 @@ 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 tree build_shared_structure_initializer (tree, tree, tree, tree, + tree, int, tree, tree, tree); static void generate_category (tree); static int is_objc_type_qualifier (tree); static tree adjust_type_for_id_default (tree); -static tree check_duplicates (hash); -static tree receiver_is_class_object (tree); +static tree check_duplicates (hash, 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 tree encode_method_def (tree); static void gen_declspecs (tree, char *, int); static void generate_classref_translation_entry (tree); static void handle_class_ref (tree); static void generate_struct_by_value_array (void) ATTRIBUTE_NORETURN; -static void encode_complete_bitfield (int, tree, int); static void mark_referenced_methods (void); +static void generate_objc_image_info (void); /*** Private Interface (data) ***/ @@ -309,7 +320,7 @@ static void mark_referenced_methods (void); /* Note that the string object global name is only needed for the NeXT runtime. */ -#define STRING_OBJECT_GLOBAL_NAME "_NSConstantStringClassReference" +#define STRING_OBJECT_GLOBAL_FORMAT "_%sClassReference" #define PROTOCOL_OBJECT_CLASS_NAME "Protocol" @@ -317,9 +328,60 @@ static const char *TAG_GETCLASS; static const char *TAG_GETMETACLASS; static const char *TAG_MSGSEND; static const char *TAG_MSGSENDSUPER; +/* The NeXT Objective-C messenger may have two extra entry points, for use + when returning a structure. */ +static const char *TAG_MSGSEND_STRET; +static const char *TAG_MSGSENDSUPER_STRET; static const char *TAG_EXECCLASS; static const char *default_constant_string_class_name; +/* Runtime metadata flags. */ +#define CLS_FACTORY 0x0001L +#define CLS_META 0x0002L + +#define OBJC_MODIFIER_STATIC 0x00000001 +#define OBJC_MODIFIER_FINAL 0x00000002 +#define OBJC_MODIFIER_PUBLIC 0x00000004 +#define OBJC_MODIFIER_PRIVATE 0x00000008 +#define OBJC_MODIFIER_PROTECTED 0x00000010 +#define OBJC_MODIFIER_NATIVE 0x00000020 +#define OBJC_MODIFIER_SYNCHRONIZED 0x00000040 +#define OBJC_MODIFIER_ABSTRACT 0x00000080 +#define OBJC_MODIFIER_VOLATILE 0x00000100 +#define OBJC_MODIFIER_TRANSIENT 0x00000200 +#define OBJC_MODIFIER_NONE_SPECIFIED 0x80000000 + +#define TAG_MSGSEND_NONNIL "objc_msgSendNonNil" +#define TAG_MSGSEND_NONNIL_STRET "objc_msgSendNonNil_stret" +#define TAG_EXCEPTIONEXTRACT "objc_exception_extract" +#define TAG_EXCEPTIONTRYENTER "objc_exception_try_enter" +#define TAG_EXCEPTIONTRYEXIT "objc_exception_try_exit" +#define TAG_EXCEPTIONMATCH "objc_exception_match" +#define TAG_EXCEPTIONTHROW "objc_exception_throw" +#define TAG_SYNCENTER "objc_sync_enter" +#define TAG_SYNCEXIT "objc_sync_exit" +#define TAG_SETJMP "_setjmp" +#define TAG_RETURN_STRUCT "objc_return_struct" + +#define UTAG_EXCDATA "_objc_exception_data" +#define UTAG_EXCDATA_VAR "_stackExceptionData" +#define UTAG_CAUGHTEXC_VAR "_caughtException" +#define UTAG_RETHROWEXC_VAR "_rethrowException" +#define UTAG_EVALONCE_VAR "_eval_once" + +struct val_stack { + long val; + struct val_stack *next; +}; +static struct val_stack *catch_count_stack, *exc_binding_stack; + +/* useful for debugging */ +static int if_nesting_count; +static int blk_nesting_count; + +static void val_stack_push (struct val_stack **, long); +static void val_stack_pop (struct val_stack **); + /* The OCTI_... enumeration itself is in objc/objc-act.h. */ tree objc_global_trees[OCTI_MAX]; @@ -329,7 +391,8 @@ struct imp_entry *imp_list = 0; int imp_count = 0; /* `@implementation' */ int cat_count = 0; /* `@category' */ -static int method_slot = 0; /* Used by start_method_def, */ +/* Use to generate method labels. */ +static int method_slot = 0; #define BUFSIZE 1024 @@ -444,6 +507,8 @@ objc_init (void) TAG_GETMETACLASS = "objc_getMetaClass"; TAG_MSGSEND = "objc_msgSend"; TAG_MSGSENDSUPER = "objc_msgSendSuper"; + TAG_MSGSEND_STRET = "objc_msgSend_stret"; + TAG_MSGSENDSUPER_STRET = "objc_msgSendSuper_stret"; TAG_EXECCLASS = "__objc_execClass"; default_constant_string_class_name = "NSConstantString"; } @@ -453,6 +518,8 @@ objc_init (void) TAG_GETMETACLASS = "objc_get_meta_class"; TAG_MSGSEND = "objc_msg_lookup"; TAG_MSGSENDSUPER = "objc_msg_lookup_super"; + /* GNU runtime does not provide special functions to support + structure-returning methods. */ TAG_EXECCLASS = "__objc_exec_class"; default_constant_string_class_name = "NXConstantString"; flag_typed_selectors = 1; @@ -491,18 +558,6 @@ define_decl (tree declarator, tree declspecs) return decl; } -/* Return 1 if LHS and RHS are compatible types for assignment or - various other operations. Return 0 if they are incompatible, and - return -1 if we choose to not decide. When the operation is - REFLEXIVE, check for compatibility in either direction. - - For statically typed objects, an assignment of the form `a' = `b' - is permitted if: - - `a' is of type "id", - `a' and `b' are the same class type, or - `a' and `b' are of class types A and B such that B is a descendant of A. */ - static tree lookup_method_in_protocol_list (tree rproto_list, tree sel_name, int class_meth) @@ -674,7 +729,7 @@ objc_comptypes (tree lhs, tree rhs, int reflexive) /* <Protocol> = <class> * */ else if (TYPED_OBJECT (TREE_TYPE (rhs))) { - tree rname = TYPE_NAME (TREE_TYPE (rhs)); + tree rname = OBJC_TYPE_NAME (TREE_TYPE (rhs)); tree rinter; /* Make sure the protocol is supported by the object on @@ -715,18 +770,18 @@ objc_comptypes (tree lhs, tree rhs, int reflexive) if (!rproto) warning ("class `%s' does not implement the `%s' protocol", - IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (rhs))), + IDENTIFIER_POINTER (OBJC_TYPE_NAME (TREE_TYPE (rhs))), IDENTIFIER_POINTER (PROTOCOL_NAME (p))); } return 1; } /* <Protocol> = id */ - else if (TYPE_NAME (TREE_TYPE (rhs)) == objc_object_id) + else if (OBJC_TYPE_NAME (TREE_TYPE (rhs)) == objc_object_id) { return 1; } /* <Protocol> = Class */ - else if (TYPE_NAME (TREE_TYPE (rhs)) == objc_class_id) + else if (OBJC_TYPE_NAME (TREE_TYPE (rhs)) == objc_class_id) { return 0; } @@ -740,7 +795,7 @@ objc_comptypes (tree lhs, tree rhs, int reflexive) { if (reflexive) { - tree rname = TYPE_NAME (TREE_TYPE (lhs)); + tree rname = OBJC_TYPE_NAME (TREE_TYPE (lhs)); tree rinter; tree rproto, rproto_list = TYPE_PROTOCOL_LIST (rhs); @@ -781,14 +836,14 @@ objc_comptypes (tree lhs, tree rhs, int reflexive) p); cat = CLASS_CATEGORY_LIST (cat); } - + rinter = lookup_interface (CLASS_SUPER_NAME (rinter)); } - + if (!lproto) warning ("class `%s' does not implement the `%s' protocol", - IDENTIFIER_POINTER (TYPE_NAME + IDENTIFIER_POINTER (OBJC_TYPE_NAME (TREE_TYPE (lhs))), IDENTIFIER_POINTER (PROTOCOL_NAME (p))); } @@ -798,12 +853,12 @@ objc_comptypes (tree lhs, tree rhs, int reflexive) return 0; } /* id = <Protocol> */ - else if (TYPE_NAME (TREE_TYPE (lhs)) == objc_object_id) + else if (OBJC_TYPE_NAME (TREE_TYPE (lhs)) == objc_object_id) { return 1; } /* Class = <Protocol> */ - else if (TYPE_NAME (TREE_TYPE (lhs)) == objc_class_id) + else if (OBJC_TYPE_NAME (TREE_TYPE (lhs)) == objc_class_id) { return 0; } @@ -836,24 +891,24 @@ objc_comptypes (tree lhs, tree rhs, int reflexive) 'Object *o = [[Object alloc] init]; falls in the case <class> * = `id'. */ - if ((TYPE_NAME (lhs) == objc_object_id && TYPED_OBJECT (rhs)) - || (TYPE_NAME (rhs) == objc_object_id && TYPED_OBJECT (lhs))) + if ((OBJC_TYPE_NAME (lhs) == objc_object_id && TYPED_OBJECT (rhs)) + || (OBJC_TYPE_NAME (rhs) == objc_object_id && TYPED_OBJECT (lhs))) return 1; /* `id' = `Class', `Class' = `id' */ - else if ((TYPE_NAME (lhs) == objc_object_id - && TYPE_NAME (rhs) == objc_class_id) - || (TYPE_NAME (lhs) == objc_class_id - && TYPE_NAME (rhs) == objc_object_id)) + else if ((OBJC_TYPE_NAME (lhs) == objc_object_id + && OBJC_TYPE_NAME (rhs) == objc_class_id) + || (OBJC_TYPE_NAME (lhs) == objc_class_id + && OBJC_TYPE_NAME (rhs) == objc_object_id)) return 1; /* `<class> *' = `<class> *' */ else if (TYPED_OBJECT (lhs) && TYPED_OBJECT (rhs)) { - tree lname = TYPE_NAME (lhs); - tree rname = TYPE_NAME (rhs); + tree lname = OBJC_TYPE_NAME (lhs); + tree rname = OBJC_TYPE_NAME (rhs); tree inter; if (lname == rname) @@ -880,17 +935,19 @@ objc_comptypes (tree lhs, tree rhs, int reflexive) return -1; } -/* Called from c-decl.c before all calls to rest_of_decl_compilation. */ +/* Called from finish_decl. */ void objc_check_decl (tree decl) { tree type = TREE_TYPE (decl); - if (TREE_CODE (type) == RECORD_TYPE - && TREE_STATIC_TEMPLATE (type) + if (TREE_CODE (type) != RECORD_TYPE) + return; + if (TYPE_NAME (type) && (type = is_class_name (TYPE_NAME (type))) && type != constant_string_type) - error ("%J'%D' cannot be statically allocated", decl, decl); + error ("statically allocated instance of Objective-C class `%s'", + IDENTIFIER_POINTER (type)); } /* Implement static typing. At this point, we know we have an interface. */ @@ -997,12 +1054,14 @@ check_protocol_recursively (tree proto, tree list) } } +/* Look up PROTOCOLS, and return a list of those that are found. + If none are found, return NULL. */ + static tree lookup_and_install_protocols (tree protocols) { tree proto; - tree prev = NULL; - tree return_value = protocols; + tree return_value = NULL_TREE; for (proto = protocols; proto; proto = TREE_CHAIN (proto)) { @@ -1010,20 +1069,11 @@ lookup_and_install_protocols (tree protocols) tree p = lookup_protocol (ident); if (!p) - { - error ("cannot find protocol declaration for `%s'", - IDENTIFIER_POINTER (ident)); - if (prev) - TREE_CHAIN (prev) = TREE_CHAIN (proto); - else - return_value = TREE_CHAIN (proto); - } + error ("cannot find protocol declaration for `%s'", + IDENTIFIER_POINTER (ident)); else - { - /* Replace identifier with actual protocol node. */ - TREE_VALUE (proto) = p; - prev = proto; - } + return_value = chainon (return_value, + build_tree_list (NULL_TREE, p)); } return return_value; @@ -1043,9 +1093,9 @@ create_builtin_decl (enum tree_code code, tree type, const char *name) TREE_STATIC (decl) = 1; make_decl_rtl (decl, 0); pushdecl (decl); + DECL_ARTIFICIAL (decl) = 1; } - DECL_ARTIFICIAL (decl) = 1; return decl; } @@ -1057,7 +1107,17 @@ setup_string_decl (void) if (!string_class_decl) { if (!constant_string_global_id) - constant_string_global_id = get_identifier (STRING_OBJECT_GLOBAL_NAME); + { + char *name; + size_t length; + /* %s in format will provide room for terminating null */ + length = strlen (STRING_OBJECT_GLOBAL_FORMAT) + + strlen (constant_string_class_name); + name = xmalloc (length); + sprintf (name, STRING_OBJECT_GLOBAL_FORMAT, + constant_string_class_name); + constant_string_global_id = get_identifier (name); + } string_class_decl = lookup_name (constant_string_global_id); } } @@ -1077,7 +1137,6 @@ static void synth_module_prologue (void) { tree temp_type; - tree super_p; /* Defined in `objc.h' */ objc_object_id = get_identifier (TAG_OBJECT); @@ -1090,8 +1149,10 @@ synth_module_prologue (void) objc_class_id = get_identifier (TAG_CLASS); objc_class_type = build_pointer_type (xref_tag (RECORD_TYPE, objc_class_id)); + temp_type = get_identifier (PROTOCOL_OBJECT_CLASS_NAME); + objc_declare_class (tree_cons (NULL_TREE, temp_type, NULL_TREE)); protocol_type = build_pointer_type (xref_tag (RECORD_TYPE, - get_identifier (PROTOCOL_OBJECT_CLASS_NAME))); + temp_type)); /* Declare type of selector-objects that represent an operation name. */ @@ -1103,7 +1164,8 @@ synth_module_prologue (void) /* Forward declare type, or else the prototype for msgSendSuper will complain. */ - super_p = build_pointer_type (xref_tag (RECORD_TYPE, + /* `struct objc_super *' */ + super_type = build_pointer_type (xref_tag (RECORD_TYPE, get_identifier (TAG_SUPER))); @@ -1128,14 +1190,21 @@ synth_module_prologue (void) pushdecl (umsg_decl); } else - umsg_decl = builtin_function (TAG_MSGSEND, temp_type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); + { + umsg_decl = builtin_function (TAG_MSGSEND, + temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + /* id objc_msgSendNonNil (id, SEL, ...); */ + umsg_nonnil_decl = builtin_function (TAG_MSGSEND_NONNIL, + temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + } /* id objc_msgSendSuper (struct objc_super *, SEL, ...); */ temp_type = build_function_type (id_type, - tree_cons (NULL_TREE, super_p, + tree_cons (NULL_TREE, super_type, tree_cons (NULL_TREE, selector_type, NULL_TREE))); @@ -1143,13 +1212,68 @@ synth_module_prologue (void) temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + /* The NeXT runtime defines the following additional entry points, + used for dispatching calls to methods returning structs: + + #if defined(__cplusplus) + id objc_msgSend_stret(id self, SEL op, ...); + id objc_msgSendSuper_stret(struct objc_super *super, SEL op, ...); + #else + void objc_msgSend_stret(void * stretAddr, id self, SEL op, ...); + void objc_msgSendSuper_stret(void * stretAddr, struct objc_super *super, + SEL op, ...); + #endif + + struct objc_return_struct objc_msgSendNonNil_stret(id self, SEL op, ...); + + These prototypes appear in <objc/objc-runtime.h>; however, they + CANNOT BE USED DIRECTLY. In order to call one of the ..._stret + functions, the function must first be cast to a signature that + corresponds to the actual ObjC method being invoked. This is + what is done by the build_objc_method_call() routine below. */ + + if (flag_next_runtime) + { + tree objc_return_struct_type + = xref_tag (RECORD_TYPE, + get_identifier (TAG_RETURN_STRUCT)); + + tree stret_temp_type + = build_function_type (id_type, + tree_cons (NULL_TREE, id_type, + tree_cons (NULL_TREE, selector_type, + NULL_TREE))); + + umsg_stret_decl = builtin_function (TAG_MSGSEND_STRET, + stret_temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + stret_temp_type + = build_function_type (objc_return_struct_type, + tree_cons (NULL_TREE, id_type, + tree_cons (NULL_TREE, selector_type, + NULL_TREE))); + + umsg_nonnil_stret_decl = builtin_function (TAG_MSGSEND_NONNIL_STRET, + stret_temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + + stret_temp_type + = build_function_type (id_type, + tree_cons (NULL_TREE, super_type, + tree_cons (NULL_TREE, selector_type, + NULL_TREE))); + + umsg_super_stret_decl = builtin_function (TAG_MSGSENDSUPER_STRET, + stret_temp_type, 0, NOT_BUILT_IN, 0, + NULL_TREE); + } + /* id objc_getClass (const char *); */ temp_type = build_function_type (id_type, - tree_cons (NULL_TREE, - const_string_type_node, - tree_cons (NULL_TREE, void_type_node, - NULL_TREE))); + tree_cons (NULL_TREE, + const_string_type_node, + OBJC_VOID_AT_END)); objc_get_class_decl = builtin_function (TAG_GETCLASS, temp_type, 0, NOT_BUILT_IN, @@ -1158,8 +1282,11 @@ synth_module_prologue (void) /* id objc_getMetaClass (const char *); */ objc_get_meta_class_decl - = builtin_function (TAG_GETMETACLASS, temp_type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); + = builtin_function (TAG_GETMETACLASS, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + + build_super_template (); + if (flag_next_runtime) + build_objc_exception_stuff (); /* static SEL _OBJC_SELECTOR_TABLE[]; */ @@ -1199,10 +1326,21 @@ synth_module_prologue (void) constant_string_class_name = default_constant_string_class_name; constant_string_id = get_identifier (constant_string_class_name); - constant_string_type = xref_tag (RECORD_TYPE, constant_string_id); + objc_declare_class (tree_cons (NULL_TREE, constant_string_id, NULL_TREE)); + + /* Pre-build the following entities - for speed/convenience. */ + self_id = get_identifier ("self"); + ucmd_id = get_identifier ("_cmd"); +#ifndef OBJCPLUS + /* The C++ front-end does not appear to grok __attribute__((__unused__)). */ + unused_list = build_tree_list (get_identifier ("__unused__"), NULL_TREE); +#endif } -/* Predefine the following data type: +/* Ensure that the ivar list for NSConstantString/NXConstantString + (or whatever was specified via `-fconstant-string-class') + contains fields at least as large as the following three, so that + the runtime can stomp on them with confidence: struct STRING_OBJECT_CLASS_NAME { @@ -1211,25 +1349,32 @@ synth_module_prologue (void) unsigned int length; }; */ -static void -build_string_class_template (void) +static int +check_string_class_template (void) { - tree field_decl, field_decl_chain; + tree field_decl = TYPE_FIELDS (constant_string_type); - field_decl = create_builtin_decl (FIELD_DECL, id_type, "isa"); - field_decl_chain = field_decl; +#define AT_LEAST_AS_LARGE_AS(F, T) \ + (F && TREE_CODE (F) == FIELD_DECL \ + && (TREE_INT_CST_LOW (DECL_SIZE (F)) \ + >= TREE_INT_CST_LOW (TYPE_SIZE (T)))) - field_decl = create_builtin_decl (FIELD_DECL, - build_pointer_type (char_type_node), - "cString"); - chainon (field_decl_chain, field_decl); + if (!AT_LEAST_AS_LARGE_AS (field_decl, ptr_type_node)) + return 0; - field_decl = create_builtin_decl (FIELD_DECL, unsigned_type_node, "length"); - chainon (field_decl_chain, field_decl); + field_decl = TREE_CHAIN (field_decl); + if (!AT_LEAST_AS_LARGE_AS (field_decl, ptr_type_node)) + return 0; + + field_decl = TREE_CHAIN (field_decl); + return AT_LEAST_AS_LARGE_AS (field_decl, unsigned_type_node); - finish_struct (constant_string_type, field_decl_chain, NULL_TREE); +#undef AT_LEAST_AS_LARGE_AS } +/* Avoid calling `check_string_class_template ()' more than once. */ +static GTY(()) int string_layout_checked; + /* Custom build_string which sets TREE_TYPE! */ static tree @@ -1238,34 +1383,47 @@ my_build_string (int len, const char *str) return fix_string_type (build_string (len, str)); } -/* Build a static instance of NXConstantString which points at the - string constant STRING. - We place the string object in the __string_objects section of the - __OBJC segment. The Objective-C runtime will initialize the isa - pointers of the string objects to point at the NXConstantString - class object. */ +/* Given a chain of STRING_CST's, build a static instance of + NXConstantString which points at the concatenation of those + strings. We place the string object in the __string_objects + section of the __OBJC segment. The Objective-C runtime will + initialize the isa pointers of the string objects to point at the + NXConstantString class object. */ tree build_objc_string_object (tree string) { - tree initlist, constructor; + tree initlist, constructor, constant_string_class; int length; - if (lookup_interface (constant_string_id) == NULL_TREE) + string = fix_string_type (string); + + constant_string_class = lookup_interface (constant_string_id); + if (!constant_string_class + || !(constant_string_type + = CLASS_STATIC_TEMPLATE (constant_string_class))) { error ("cannot find interface declaration for `%s'", IDENTIFIER_POINTER (constant_string_id)); return error_mark_node; } - add_class_reference (constant_string_id); - + /* Call to 'combine_strings' has been moved above. */ + TREE_SET_CODE (string, STRING_CST); length = TREE_STRING_LENGTH (string) - 1; - /* We could not properly create NXConstantString in synth_module_prologue, - because that's called before debugging is initialized. Do it now. */ - if (TYPE_FIELDS (constant_string_type) == NULL_TREE) - build_string_class_template (); + if (!string_layout_checked) + { + /* The NSConstantString/NXConstantString ivar layout is now + known. */ + if (!check_string_class_template ()) + { + error ("interface `%s' does not have valid constant string layout", + IDENTIFIER_POINTER (constant_string_id)); + return error_mark_node; + } + add_class_reference (constant_string_id); + } /* & ((NXConstantString) { NULL, string, length }) */ @@ -1308,6 +1466,7 @@ build_objc_string_object (tree string) /* Declare a static instance of CLASS_DECL initialized by CONSTRUCTOR. */ static GTY(()) int num_static_inst; + static tree objc_add_static_instance (tree constructor, tree class_decl) { @@ -1322,7 +1481,7 @@ objc_add_static_instance (tree constructor, tree class_decl) if (!*chain) { *chain = tree_cons (NULL_TREE, class_decl, NULL_TREE); - add_objc_string (TYPE_NAME (class_decl), class_names); + add_objc_string (OBJC_TYPE_NAME (class_decl), class_names); } sprintf (buf, "_OBJC_INSTANCE_%d", num_static_inst++); @@ -1375,6 +1534,11 @@ objc_build_constructor (tree type, tree elts) TREE_STATIC (constructor) = 1; TREE_READONLY (constructor) = 1; +#ifdef OBJCPLUS + /* zlaski 2001-Apr-02: mark this as a call to a constructor, as required by + build_unary_op (wasn't true in 2.7.2.1 days) */ + TREE_HAS_CONSTRUCTOR (constructor) = 1; +#endif return constructor; } @@ -1394,7 +1558,7 @@ objc_build_constructor (tree type, tree elts) static void build_objc_symtab_template (void) { - tree field_decl, field_decl_chain, index; + tree field_decl, field_decl_chain; objc_symtab_template = start_struct (RECORD_TYPE, get_identifier (UTAG_SYMTAB)); @@ -1427,18 +1591,20 @@ build_objc_symtab_template (void) "cat_def_cnt"); chainon (field_decl_chain, field_decl); - /* void *defs[cls_def_cnt + cat_def_cnt]; */ - - if (!flag_next_runtime) - index = build_index_type (build_int_2 (imp_count + cat_count, 0)); - else - index = build_index_type (build_int_2 (imp_count + cat_count - 1, - imp_count == 0 && cat_count == 0 - ? -1 : 0)); - field_decl = create_builtin_decl (FIELD_DECL, - build_array_type (ptr_type_node, index), - "defs"); - chainon (field_decl_chain, field_decl); + if (imp_count || cat_count || !flag_next_runtime) + { + /* void *defs[imp_count + cat_count (+ 1)]; */ + /* NB: The index is one less than the size of the array. */ + int index = imp_count + cat_count + + (flag_next_runtime? -1: 0); + field_decl = create_builtin_decl + (FIELD_DECL, + build_array_type + (ptr_type_node, + build_index_type (build_int_2 (index, 0))), + "defs"); + chainon (field_decl_chain, field_decl); + } finish_struct (objc_symtab_template, field_decl_chain, NULL_TREE); } @@ -1519,7 +1685,7 @@ init_objc_symtab (tree type) /* cls_def = { ..., { &Foo, &Bar, ...}, ... } */ - if (imp_count || cat_count || static_instances_decl) + if (imp_count || cat_count || !flag_next_runtime) { tree field = TYPE_FIELDS (type); @@ -1532,6 +1698,26 @@ init_objc_symtab (tree type) return objc_build_constructor (type, nreverse (initlist)); } +/* Generate forward declarations for metadata such as + 'OBJC_CLASS_...'. */ + +static tree +build_metadata_decl (const char *name, tree type) +{ + tree decl, decl_specs; + /* extern struct TYPE NAME_<name>; */ + decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_EXTERN]); + decl_specs = tree_cons (NULL_TREE, type, decl_specs); + decl = define_decl (synth_id_with_class_suffix + (name, + objc_implementation_context), + decl_specs); + TREE_USED (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + TREE_PUBLIC (decl) = 0; + return decl; +} + /* Push forward-declarations of all the categories so that init_def_list can use them in a CONSTRUCTOR. */ @@ -1547,16 +1733,15 @@ forward_declare_categories (void) { /* Set an invisible arg to synth_id_with_class_suffix. */ objc_implementation_context = impent->imp_context; - impent->class_decl - = create_builtin_decl (VAR_DECL, objc_category_template, - IDENTIFIER_POINTER (synth_id_with_class_suffix ("_OBJC_CATEGORY", objc_implementation_context))); - TREE_PUBLIC (impent->class_decl) = 0; + /* extern struct objc_category _OBJC_CATEGORY_<name>; */ + impent->class_decl = build_metadata_decl ("_OBJC_CATEGORY", + objc_category_template); } } objc_implementation_context = sav; } -/* Create the declaration of _OBJC_SYMBOLS, with type `strict _objc_symtab' +/* Create the declaration of _OBJC_SYMBOLS, with type `struct _objc_symtab' and initialized appropriately. */ static void @@ -1706,7 +1891,8 @@ build_module_descriptor (void) get_identifier (TAG_EXECCLASS), build_function_type (void_type_node, tree_cons (NULL_TREE, ptr_type_node, - void_list_node_1))); + OBJC_VOID_AT_END))); + DECL_EXTERNAL (execclass_decl) = 1; DECL_ARTIFICIAL (execclass_decl) = 1; TREE_PUBLIC (execclass_decl) = 1; @@ -1720,7 +1906,7 @@ build_module_descriptor (void) start_function (void_list_node_1, build_nt (CALL_EXPR, init_function_name, tree_cons (NULL_TREE, NULL_TREE, - void_list_node_1), + OBJC_VOID_AT_END), NULL_TREE), NULL_TREE); store_parm_decls (); @@ -1821,7 +2007,7 @@ generate_static_references (void) /* Output {class_name, ...}. */ class = TREE_VALUE (cl_chain); - class_name = get_objc_string_decl (TYPE_NAME (class), class_names); + class_name = get_objc_string_decl (OBJC_TYPE_NAME (class), class_names); initlist = build_tree_list (NULL_TREE, build_unary_op (ADDR_EXPR, class_name, 1)); @@ -1920,6 +2106,7 @@ generate_strings (void) } static GTY(()) int selector_reference_idx; + static tree build_selector_reference_decl (void) { @@ -1934,7 +2121,6 @@ build_selector_reference_decl (void) DECL_EXTERNAL (decl) = 1; TREE_PUBLIC (decl) = 0; TREE_USED (decl) = 1; - TREE_READONLY (decl) = 1; DECL_ARTIFICIAL (decl) = 1; DECL_CONTEXT (decl) = 0; @@ -2054,15 +2240,11 @@ get_proto_encoding (tree proto) tree encoding; if (proto) { - tree tmp_decl; - if (! METHOD_ENCODING (proto)) { - tmp_decl = build_tmp_function_decl (); - hack_method_prototype (proto, tmp_decl); - encoding = encode_method_prototype (proto, tmp_decl); - METHOD_ENCODING (proto) = encoding; - } + encoding = encode_method_prototype (proto); + METHOD_ENCODING (proto) = encoding; + } else encoding = METHOD_ENCODING (proto); @@ -2131,6 +2313,7 @@ build_selector_reference (tree ident) } static GTY(()) int class_reference_idx; + static tree build_class_reference_decl (void) { @@ -2145,7 +2328,6 @@ build_class_reference_decl (void) DECL_EXTERNAL (decl) = 1; TREE_PUBLIC (decl) = 0; TREE_USED (decl) = 1; - TREE_READONLY (decl) = 1; DECL_CONTEXT (decl) = 0; DECL_ARTIFICIAL (decl) = 1; @@ -2189,7 +2371,25 @@ add_class_reference (tree ident) tree get_class_reference (tree ident) { - if (flag_next_runtime) + tree orig_ident; + +#ifdef OBJCPLUS + if (processing_template_decl) + /* Must wait until template instantiation time. */ + return build_min_nt (CLASS_REFERENCE_EXPR, ident); + if (TREE_CODE (ident) == TYPE_DECL) + ident = DECL_NAME (ident); +#endif + orig_ident = ident; + + if (!(ident = is_class_name (ident))) + { + error ("`%s' is not an Objective-C class name or alias", + IDENTIFIER_POINTER (orig_ident)); + return error_mark_node; + } + + if (flag_next_runtime && !flag_zero_link) { tree *chain; tree decl; @@ -2277,7 +2477,6 @@ build_objc_string_decl (enum string_section section) DECL_EXTERNAL (decl) = 1; TREE_PUBLIC (decl) = 0; TREE_USED (decl) = 1; - TREE_READONLY (decl) = 1; TREE_CONSTANT (decl) = 1; DECL_CONTEXT (decl) = 0; DECL_ARTIFICIAL (decl) = 1; @@ -2292,34 +2491,49 @@ build_objc_string_decl (enum string_section section) void objc_declare_alias (tree alias_ident, tree class_ident) { - if (is_class_name (class_ident) != class_ident) + tree underlying_class; + +#ifdef OBJCPLUS + if (current_namespace != global_namespace) { + error ("Objective-C declarations may only appear in global scope"); + } +#endif /* OBJCPLUS */ + + if (!(underlying_class = is_class_name (class_ident))) warning ("cannot find class `%s'", IDENTIFIER_POINTER (class_ident)); else if (is_class_name (alias_ident)) warning ("class `%s' already exists", IDENTIFIER_POINTER (alias_ident)); else - alias_chain = tree_cons (class_ident, alias_ident, alias_chain); + alias_chain = tree_cons (underlying_class, alias_ident, alias_chain); } void objc_declare_class (tree ident_list) { tree list; +#ifdef OBJCPLUS + if (current_namespace != global_namespace) { + error ("Objective-C declarations may only appear in global scope"); + } +#endif /* OBJCPLUS */ for (list = ident_list; list; list = TREE_CHAIN (list)) { tree ident = TREE_VALUE (list); - tree decl; - if ((decl = lookup_name (ident))) + if (! is_class_name (ident)) { - error ("`%s' redeclared as different kind of symbol", - IDENTIFIER_POINTER (ident)); - error ("%Jprevious declaration of '%D'", decl, decl); - } + tree record = lookup_name (ident); + + if (record && ! TREE_STATIC_TEMPLATE (record)) + { + error ("`%s' redeclared as different kind of symbol", + IDENTIFIER_POINTER (ident)); + error ("%Jprevious declaration of '%D'", + record, record); + } - if (! is_class_name (ident)) - { - tree record = xref_tag (RECORD_TYPE, ident); + record = xref_tag (RECORD_TYPE, ident); TREE_STATIC_TEMPLATE (record) = 1; class_chain = tree_cons (NULL_TREE, ident, class_chain); } @@ -2331,6 +2545,21 @@ is_class_name (tree ident) { tree chain; + if (ident && TREE_CODE (ident) == IDENTIFIER_NODE + && identifier_global_value (ident)) + ident = identifier_global_value (ident); + while (ident && TREE_CODE (ident) == TYPE_DECL && DECL_ORIGINAL_TYPE (ident)) + ident = TYPE_NAME (DECL_ORIGINAL_TYPE (ident)); + +#ifdef OBJCPLUS + if (ident && TREE_CODE (ident) == RECORD_TYPE) + ident = TYPE_NAME (ident); + if (ident && TREE_CODE (ident) == TYPE_DECL) + ident = DECL_NAME (ident); +#endif + if (!ident || TREE_CODE (ident) != IDENTIFIER_NODE) + return NULL_TREE; + if (lookup_interface (ident)) return ident; @@ -2349,14 +2578,23 @@ is_class_name (tree ident) return 0; } +/* Check whether TYPE is either 'id', 'Class', or a pointer to an ObjC + class instance. This is needed by other parts of the compiler to + handle ObjC types gracefully. */ + tree -objc_is_id (tree ident) +objc_is_object_ptr (tree type) { - /* NB: This function may be called before the ObjC front-end - has been initialized, in which case ID_TYPE will be NULL. */ - return (id_type && ident && TYPE_P (ident) && IS_ID (ident)) - ? id_type - : NULL_TREE; + type = TYPE_MAIN_VARIANT (type); + if (!type || TREE_CODE (type) != POINTER_TYPE) + return 0; + /* NB: This function may be called before the ObjC front-end has + been initialized, in which case ID_TYPE will be NULL. */ + if (id_type && type && TYPE_P (type) + && (IS_ID (type) + || TREE_TYPE (type) == TREE_TYPE (objc_class_type))) + return type; + return is_class_name (OBJC_TYPE_NAME (TREE_TYPE (type))); } tree @@ -2364,30 +2602,70 @@ lookup_interface (tree ident) { tree chain; +#ifdef OBJCPLUS + if (ident && TREE_CODE (ident) == TYPE_DECL) + ident = DECL_NAME (ident); +#endif for (chain = interface_chain; chain; chain = TREE_CHAIN (chain)) { if (ident == CLASS_NAME (chain)) - return chain; + return chain; } return NULL_TREE; } +/* Implement @defs (<classname>) within struct bodies. */ + +tree +get_class_ivars_from_name (tree class_name) +{ + tree interface = lookup_interface (class_name); + tree field, fields = NULL_TREE; + + if (interface) + { + tree raw_ivar = get_class_ivars (interface, 1); + + /* Regenerate the FIELD_DECLs for the enclosing struct. */ + for (; raw_ivar; raw_ivar = TREE_CHAIN (raw_ivar)) + { + field = grokfield (TREE_PURPOSE (TREE_VALUE (raw_ivar)), + TREE_PURPOSE (raw_ivar), + TREE_VALUE (TREE_VALUE (raw_ivar))); +#ifdef OBJCPLUS + finish_member_declaration (field); +#else + fields = chainon (fields, field); +#endif + } + } + else + error ("cannot find interface declaration for `%s'", + IDENTIFIER_POINTER (class_name)); + + return fields; +} + /* Used by: build_private_template, continue_class, and for @defs constructs. */ -tree -get_class_ivars (tree interface) +static tree +get_class_ivars (tree interface, int raw) { tree my_name, super_name, ivar_chain; my_name = CLASS_NAME (interface); super_name = CLASS_SUPER_NAME (interface); - ivar_chain = CLASS_IVARS (interface); - - /* Save off a pristine copy of the leaf ivars (i.e, those not - inherited from a super class). */ - if (!CLASS_OWN_IVARS (interface)) - CLASS_OWN_IVARS (interface) = copy_list (ivar_chain); + if (raw) + ivar_chain = CLASS_RAW_IVARS (interface); + else + { + ivar_chain = CLASS_IVARS (interface); + /* Save off a pristine copy of the leaf ivars (i.e, those not + inherited from a super class). */ + if (!CLASS_OWN_IVARS (interface)) + CLASS_OWN_IVARS (interface) = copy_list (ivar_chain); + } while (super_name) { @@ -2411,7 +2689,7 @@ get_class_ivars (tree interface) my_name = CLASS_NAME (interface); super_name = CLASS_SUPER_NAME (interface); - op1 = CLASS_OWN_IVARS (interface); + op1 = (raw ? CLASS_RAW_IVARS (interface) : CLASS_OWN_IVARS (interface)); if (op1) { tree head = copy_list (op1); @@ -2422,9 +2700,691 @@ get_class_ivars (tree interface) ivar_chain = head; } } + return ivar_chain; } +static tree +objc_enter_block (void) +{ + tree block; + +#ifdef OBJCPLUS + block = begin_compound_stmt (0); +#else + block = c_begin_compound_stmt (); + pushlevel (0); + clear_last_expr (); + add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0); +#endif + + objc_exception_block_stack = tree_cons (NULL_TREE, block, + objc_exception_block_stack); + + blk_nesting_count++; + return block; +} + +static tree +objc_exit_block (void) +{ + tree block = TREE_VALUE (objc_exception_block_stack); +#ifndef OBJCPLUS + tree scope_stmt, inner; +#endif + + objc_clear_super_receiver (); +#ifdef OBJCPLUS + finish_compound_stmt (0, block); +#else + scope_stmt = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0); + inner = poplevel (KEEP_MAYBE, 1, 0); + + SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmt)) + = SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmt)) + = inner; + RECHAIN_STMTS (block, COMPOUND_BODY (block)); +#endif + last_expr_type = NULL_TREE; + objc_exception_block_stack = TREE_CHAIN (objc_exception_block_stack); + + blk_nesting_count--; + return block; +} + +static tree +objc_declare_variable (enum rid scspec, tree name, tree type, tree init) +{ + tree decl; + + type = tree_cons (NULL_TREE, type, + tree_cons (NULL_TREE, ridpointers[(int) scspec], + NULL_TREE)); + TREE_STATIC (type) = 1; + decl = start_decl (name, type, (init != NULL_TREE), NULL_TREE); + finish_decl (decl, init, NULL_TREE); + /* This prevents `unused variable' warnings when compiling with -Wall. */ + TREE_USED (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + return decl; +} + +tree +objc_build_throw_stmt (tree throw_expr) +{ + tree func_params; + + if (!flag_objc_exceptions) + fatal_error ("Use `-fobjc-exceptions' to enable Objective-C exception syntax"); + + if (!throw_expr && objc_caught_exception) + throw_expr = TREE_VALUE (objc_caught_exception); + + if (!throw_expr) + { + error ("`@throw;' (rethrow) used outside of a `@catch' block"); + return error_mark_node; + } + + func_params = tree_cons (NULL_TREE, throw_expr, NULL_TREE); + + assemble_external (objc_exception_throw_decl); + return c_expand_expr_stmt (build_function_call (objc_exception_throw_decl, + func_params)); +} + +static void +val_stack_push (struct val_stack **nc, long val) +{ + struct val_stack *new_elem = xmalloc (sizeof (struct val_stack)); + new_elem->val = val; + new_elem->next = *nc; + *nc = new_elem; +} + +static void +val_stack_pop (struct val_stack **nc) +{ + struct val_stack *old_elem = *nc; + *nc = old_elem->next; + free (old_elem); +} + +static void +objc_build_try_enter_fragment (void) +{ + /* objc_exception_try_enter(&_stackExceptionData); + if (!_setjmp(&_stackExceptionData.buf)) { */ + + tree func_params, if_stmt, cond; + + func_params + = tree_cons (NULL_TREE, + build_unary_op (ADDR_EXPR, + TREE_VALUE (objc_stack_exception_data), + 0), + NULL_TREE); + + assemble_external (objc_exception_try_enter_decl); + c_expand_expr_stmt (build_function_call + (objc_exception_try_enter_decl, func_params)); + + if_stmt = c_begin_if_stmt (); + if_nesting_count++; + /* If <setjmp.h> has been included, the _setjmp prototype has + acquired a real, breathing type for its parameter. Cast our + argument to that type. */ + func_params + = tree_cons (NULL_TREE, + build_c_cast (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl)) + ? TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl))) + : ptr_type_node, + build_unary_op + (ADDR_EXPR, + build_component_ref (TREE_VALUE (objc_stack_exception_data), + get_identifier ("buf")), 0)), + NULL_TREE); + assemble_external (objc_setjmp_decl); + cond = build_unary_op (TRUTH_NOT_EXPR, + build_function_call (objc_setjmp_decl, func_params), + 0); + c_expand_start_cond (c_common_truthvalue_conversion (cond), + 0, if_stmt); + objc_enter_block (); +} + +static tree +objc_build_extract_expr (void) +{ + /* ... = objc_exception_extract(&_stackExceptionData); */ + + tree func_params + = tree_cons (NULL_TREE, + build_unary_op (ADDR_EXPR, + TREE_VALUE (objc_stack_exception_data), 0), + NULL_TREE); + + assemble_external (objc_exception_extract_decl); + return build_function_call (objc_exception_extract_decl, func_params); +} + +static void +objc_build_try_exit_fragment (void) +{ + /* objc_exception_try_exit(&_stackExceptionData); */ + + tree func_params + = tree_cons (NULL_TREE, + build_unary_op (ADDR_EXPR, + TREE_VALUE (objc_stack_exception_data), 0), + NULL_TREE); + + assemble_external (objc_exception_try_exit_decl); + c_expand_expr_stmt (build_function_call (objc_exception_try_exit_decl, + func_params)); +} + +static void +objc_build_extract_fragment (void) +{ + /* } else { + _rethrowException = objc_exception_extract(&_stackExceptionData); + } */ + + objc_exit_block (); + c_finish_then (); + + c_expand_start_else (); + objc_enter_block (); + c_expand_expr_stmt (build_modify_expr + (TREE_VALUE (objc_rethrow_exception), + NOP_EXPR, + objc_build_extract_expr ())); + objc_exit_block (); + c_finish_else (); + c_expand_end_cond (); + if_nesting_count--; +} + +tree +objc_build_try_prologue (void) +{ + /* { // new scope + struct _objc_exception_data _stackExceptionData; + volatile id _rethrowException = nil; + { // begin TRY-CATCH scope + objc_exception_try_enter(&_stackExceptionData); + if (!_setjmp(&_stackExceptionData.buf)) { */ + + tree try_catch_block; + + if (!flag_objc_exceptions) + fatal_error ("Use `-fobjc-exceptions' to enable Objective-C exception syntax"); + + objc_mark_locals_volatile ((void *)(exc_binding_stack + ? exc_binding_stack->val + : 0)); + objc_enter_block (); + objc_stack_exception_data + = tree_cons (NULL_TREE, + objc_declare_variable (RID_AUTO, + get_identifier (UTAG_EXCDATA_VAR), + xref_tag (RECORD_TYPE, + get_identifier (UTAG_EXCDATA)), + NULL_TREE), + objc_stack_exception_data); + objc_rethrow_exception = tree_cons (NULL_TREE, + objc_declare_variable (RID_VOLATILE, + get_identifier (UTAG_RETHROWEXC_VAR), + id_type, + build_int_2 (0, 0)), + objc_rethrow_exception); + + try_catch_block = objc_enter_block (); + val_stack_push (&exc_binding_stack, (long) get_current_scope ()); + objc_build_try_enter_fragment (); + + return try_catch_block; +} + +void +objc_build_try_epilogue (int also_catch_prologue) +{ + if (also_catch_prologue) + { + /* } else { + register id _caughtException = objc_exception_extract( &_stackExceptionData); + objc_exception_try_enter(&_stackExceptionData); + if(!_setjmp(&_stackExceptionData.buf)) { + if (0) { */ + + tree if_stmt; + + objc_exit_block (); + c_finish_then (); + + c_expand_start_else (); + objc_enter_block (); + objc_caught_exception + = tree_cons (NULL_TREE, + objc_declare_variable (RID_REGISTER, + get_identifier (UTAG_CAUGHTEXC_VAR), + id_type, + objc_build_extract_expr ()), + objc_caught_exception); + objc_build_try_enter_fragment (); + val_stack_push (&catch_count_stack, 1); + if_stmt = c_begin_if_stmt (); + if_nesting_count++; + c_expand_start_cond (c_common_truthvalue_conversion (boolean_false_node), + 0, if_stmt); + objc_enter_block (); + + /* Start a new chain of @catch statements for this @try. */ + objc_catch_type = tree_cons (objc_catch_type, NULL_TREE, NULL_TREE); + } + else + { /* !also_catch_prologue */ + + /* } else { + _rethrowException = objc_exception_extract( &_stackExceptionData); + } + } */ + objc_build_extract_fragment (); + objc_exit_block (); + } +} + +void +objc_build_catch_stmt (tree catch_expr) +{ + /* } else if (objc_exception_match(objc_get_class("SomeClass"), _caughtException)) { + register SomeClass *e = _caughtException; */ + + tree if_stmt, cond, func_params, prev_catch, var_name, var_type; + int catch_id; + +#ifndef OBJCPLUS + /* Yet another C/C++ impedance mismatch. */ + catch_expr = TREE_PURPOSE (catch_expr); +#endif + + var_name = TREE_VALUE (catch_expr); + var_type = TREE_VALUE (TREE_PURPOSE (catch_expr)); + if (TREE_CODE (var_name) == INDIRECT_REF) + var_name = TREE_OPERAND (var_name, 0); + if (TREE_CODE (var_type) == TYPE_DECL + || TREE_CODE (var_type) == POINTER_TYPE) + var_type = TREE_TYPE (var_type); + catch_id = (var_type == TREE_TYPE (id_type)); + + if (!flag_objc_exceptions) + fatal_error ("Use `-fobjc-exceptions' to enable Objective-C exception syntax"); + + if (!(catch_id || TYPED_OBJECT (var_type))) + fatal_error ("`@catch' parameter is not a known Objective-C class type"); + + /* Examine previous @catch clauses for the current @try block for + superclasses of the 'var_type' class. */ + for (prev_catch = objc_catch_type; TREE_VALUE (prev_catch); + prev_catch = TREE_CHAIN (prev_catch)) + { + if (TREE_VALUE (prev_catch) == TREE_TYPE (id_type)) + { + warning ("Exception already handled by preceding `@catch(id)'"); + break; + } + else if (!catch_id + && objc_comptypes (TREE_VALUE (prev_catch), var_type, 0) == 1) + warning ("Exception of type `%s *' already handled by `@catch (%s *)'", + IDENTIFIER_POINTER (OBJC_TYPE_NAME (var_type)), + IDENTIFIER_POINTER (OBJC_TYPE_NAME (TREE_VALUE (prev_catch)))); + } + + objc_catch_type = tree_cons (NULL_TREE, var_type, objc_catch_type); + + objc_exit_block (); + c_finish_then (); + + c_expand_start_else (); + catch_count_stack->val++; + if_stmt = c_begin_if_stmt (); + if_nesting_count++; + + if (catch_id) + cond = integer_one_node; + else + { + cond = get_class_reference (OBJC_TYPE_NAME (var_type)); + + func_params + = tree_cons (NULL_TREE, cond, + tree_cons (NULL_TREE, + TREE_VALUE (objc_caught_exception), + NULL_TREE)); + assemble_external (objc_exception_match_decl); + cond = build_function_call (objc_exception_match_decl, func_params); + } + + c_expand_start_cond (c_common_truthvalue_conversion (cond), + 0, if_stmt); + objc_enter_block (); + objc_declare_variable (RID_REGISTER, var_name, + build_pointer_type (var_type), + TREE_VALUE (objc_caught_exception)); +} + +void +objc_build_catch_epilogue (void) +{ + /* } else { + _rethrowException = _caughtException; + objc_exception_try_exit(&_stackExceptionData); + } + } else { + _rethrowException = objc_exception_extract(&_stackExceptionData); + } + } + } // end TRY-CATCH scope + */ + + objc_exit_block (); + c_finish_then (); + + c_expand_start_else (); + objc_enter_block (); + c_expand_expr_stmt + (build_modify_expr + (TREE_VALUE (objc_rethrow_exception), + NOP_EXPR, + TREE_VALUE (objc_caught_exception))); + objc_build_try_exit_fragment (); + objc_exit_block (); + while (catch_count_stack->val--) + { + c_finish_else (); /* close off all the nested ifs ! */ + c_expand_end_cond (); + if_nesting_count--; + } + val_stack_pop (&catch_count_stack); + objc_caught_exception = TREE_CHAIN (objc_caught_exception); + + objc_build_extract_fragment (); + + objc_exit_block (); + c_finish_else (); + c_expand_end_cond (); + if_nesting_count--; + objc_exit_block (); + + /* Return to enclosing chain of @catch statements (if any). */ + while (TREE_VALUE (objc_catch_type)) + objc_catch_type = TREE_CHAIN (objc_catch_type); + objc_catch_type = TREE_PURPOSE (objc_catch_type); +} + +tree +objc_build_finally_prologue () +{ + /* { // begin FINALLY scope + if (!_rethrowException) { + objc_exception_try_exit(&_stackExceptionData); + } */ + + tree blk = objc_enter_block (); + + tree if_stmt = c_begin_if_stmt (); + if_nesting_count++; + + c_expand_start_cond (c_common_truthvalue_conversion + (build_unary_op + (TRUTH_NOT_EXPR, + TREE_VALUE (objc_rethrow_exception), 0)), + 0, if_stmt); + objc_enter_block (); + objc_build_try_exit_fragment (); + objc_exit_block (); + c_finish_then (); + c_expand_end_cond (); + if_nesting_count--; + + return blk; +} + +tree +objc_build_finally_epilogue (void) +{ + /* if (_rethrowException) { + objc_exception_throw(_rethrowException); + } + } // end FINALLY scope + } */ + + tree if_stmt = c_begin_if_stmt (); + if_nesting_count++; + + c_expand_start_cond + (c_common_truthvalue_conversion (TREE_VALUE (objc_rethrow_exception)), + 0, if_stmt); + objc_enter_block (); + objc_build_throw_stmt (TREE_VALUE (objc_rethrow_exception)); + objc_exit_block (); + c_finish_then (); + c_expand_end_cond (); + if_nesting_count--; + + objc_exit_block (); + objc_rethrow_exception = TREE_CHAIN (objc_rethrow_exception); + objc_stack_exception_data = TREE_CHAIN (objc_stack_exception_data); + + val_stack_pop (&exc_binding_stack); + return objc_exit_block (); +} + +tree +objc_build_try_catch_finally_stmt (int has_catch, int has_finally) +{ + /* NB: The operative assumption here is that TRY_FINALLY_EXPR will + deal with all exits from 'try_catch_blk' and route them through + 'finally_blk'. */ + tree outer_blk = objc_build_finally_epilogue (); + tree prec_stmt = TREE_CHAIN (TREE_CHAIN (COMPOUND_BODY (outer_blk))); + tree try_catch_blk = TREE_CHAIN (prec_stmt), try_catch_expr; + tree finally_blk = TREE_CHAIN (try_catch_blk), finally_expr; + tree succ_stmt = TREE_CHAIN (finally_blk); + tree try_finally_stmt, try_finally_expr; + + if (!flag_objc_exceptions) + fatal_error ("Use `-fobjc-exceptions' to enable Objective-C exception syntax"); + + /* It is an error to have a @try block without a @catch and/or @finally + (even though sensible code can be generated nonetheless). */ + + if (!has_catch && !has_finally) + error ("`@try' without `@catch' or `@finally'"); + + /* We shall now do something truly disgusting. We shall remove the + 'try_catch_blk' and 'finally_blk' from the 'outer_blk' statement + chain, and replace them with a TRY_FINALLY_EXPR statement! If + this doesn't work, we will have to learn (from Per/gcj) how to + construct the 'outer_blk' lazily. */ + + TREE_CHAIN (try_catch_blk) = TREE_CHAIN (finally_blk) = NULL_TREE; + try_catch_expr = build1 (STMT_EXPR, void_type_node, try_catch_blk); + TREE_SIDE_EFFECTS (try_catch_expr) = 1; + finally_expr = build1 (STMT_EXPR, void_type_node, finally_blk); + TREE_SIDE_EFFECTS (finally_expr) = 1; + try_finally_expr = build (TRY_FINALLY_EXPR, void_type_node, try_catch_expr, + finally_expr); + TREE_SIDE_EFFECTS (try_finally_expr) = 1; + try_finally_stmt = build_stmt (EXPR_STMT, try_finally_expr); + TREE_CHAIN (prec_stmt) = try_finally_stmt; + TREE_CHAIN (try_finally_stmt) = succ_stmt; + + return outer_blk; /* the whole enchilada */ +} + +void +objc_build_synchronized_prologue (tree sync_expr) +{ + /* { + id _eval_once = <sync_expr>; + @try { + objc_sync_enter( _eval_once ); */ + + tree func_params; + + if (!flag_objc_exceptions) + fatal_error ("Use `-fobjc-exceptions' to enable Objective-C exception syntax"); + + objc_enter_block (); + objc_eval_once + = tree_cons (NULL_TREE, + objc_declare_variable (RID_AUTO, + get_identifier (UTAG_EVALONCE_VAR), + id_type, + sync_expr), + objc_eval_once); + objc_build_try_prologue (); + objc_enter_block (); + func_params = tree_cons (NULL_TREE, + TREE_VALUE (objc_eval_once), + NULL_TREE); + + assemble_external (objc_sync_enter_decl); + c_expand_expr_stmt (build_function_call + (objc_sync_enter_decl, func_params)); +} + +tree +objc_build_synchronized_epilogue (void) +{ + /* } + @finally { + objc_sync_exit( _eval_once ); + } + } */ + + tree func_params; + + objc_exit_block (); + objc_build_try_epilogue (0); + objc_build_finally_prologue (); + func_params = tree_cons (NULL_TREE, TREE_VALUE (objc_eval_once), + NULL_TREE); + + assemble_external (objc_sync_exit_decl); + c_expand_expr_stmt (build_function_call (objc_sync_exit_decl, + func_params)); + objc_build_try_catch_finally_stmt (0, 1); + + return objc_exit_block (); +} + +/* Predefine the following data type: + + struct _objc_exception_data + { + int buf[_JBLEN]; + void *pointers[4]; + }; */ + +/* The following yuckiness should prevent users from having to #include + <setjmp.h> in their code... */ + +#ifdef TARGET_POWERPC +/* snarfed from /usr/include/ppc/setjmp.h */ +#define _JBLEN (26 + 36 + 129 + 1) +#else +/* snarfed from /usr/include/i386/{setjmp,signal}.h */ +#define _JBLEN 18 +#endif + +static void +build_objc_exception_stuff (void) +{ + tree field_decl, field_decl_chain, index, temp_type; + + /* Suppress outputting debug symbols, because + dbxout_init hasn't been called yet. */ + enum debug_info_type save_write_symbols = write_symbols; + const struct gcc_debug_hooks *save_hooks = debug_hooks; + + write_symbols = NO_DEBUG; + debug_hooks = &do_nothing_debug_hooks; + objc_exception_data_template + = start_struct (RECORD_TYPE, get_identifier (UTAG_EXCDATA)); + + /* int buf[_JBLEN]; */ + + index = build_index_type (build_int_2 (_JBLEN - 1, 0)); + field_decl = create_builtin_decl (FIELD_DECL, + build_array_type (integer_type_node, index), + "buf"); + field_decl_chain = field_decl; + + /* void *pointers[4]; */ + + index = build_index_type (build_int_2 (4 - 1, 0)); + field_decl = create_builtin_decl (FIELD_DECL, + build_array_type (ptr_type_node, index), + "pointers"); + chainon (field_decl_chain, field_decl); + + finish_struct (objc_exception_data_template, field_decl_chain, NULL_TREE); + + /* int _setjmp(...); */ + /* If the user includes <setjmp.h>, this shall be superceded by + 'int _setjmp(jmp_buf);' */ + temp_type = build_function_type (integer_type_node, NULL_TREE); + objc_setjmp_decl + = builtin_function (TAG_SETJMP, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + + /* id objc_exception_extract(struct _objc_exception_data *); */ + temp_type + = build_function_type (id_type, + tree_cons (NULL_TREE, + 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); + /* void objc_exception_try_enter(struct _objc_exception_data *); */ + /* void objc_exception_try_exit(struct _objc_exception_data *); */ + temp_type + = build_function_type (void_type_node, + tree_cons (NULL_TREE, + build_pointer_type (objc_exception_data_template), + OBJC_VOID_AT_END)); + objc_exception_try_enter_decl + = builtin_function (TAG_EXCEPTIONTRYENTER, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + objc_exception_try_exit_decl + = builtin_function (TAG_EXCEPTIONTRYEXIT, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + /* void objc_exception_throw(id) __attribute__((noreturn)); */ + /* void objc_sync_enter(id); */ + /* void objc_sync_exit(id); */ + temp_type = build_function_type (void_type_node, + tree_cons (NULL_TREE, id_type, + OBJC_VOID_AT_END)); + objc_exception_throw_decl + = builtin_function (TAG_EXCEPTIONTHROW, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + DECL_ATTRIBUTES (objc_exception_throw_decl) + = tree_cons (get_identifier ("noreturn"), NULL_TREE, NULL_TREE); + objc_sync_enter_decl + = builtin_function (TAG_SYNCENTER, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + objc_sync_exit_decl + = builtin_function (TAG_SYNCEXIT, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + /* int objc_exception_match(id, id); */ + temp_type = build_function_type (integer_type_node, + tree_cons (NULL_TREE, id_type, + tree_cons (NULL_TREE, id_type, + OBJC_VOID_AT_END))); + objc_exception_match_decl + = builtin_function (TAG_EXCEPTIONMATCH, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + + write_symbols = save_write_symbols; + debug_hooks = save_hooks; +} + /* struct <classname> { struct objc_class *isa; ... @@ -2443,8 +3403,7 @@ build_private_template (tree class) else { uprivate_record = start_struct (RECORD_TYPE, CLASS_NAME (class)); - - ivar_context = get_class_ivars (class); + ivar_context = get_class_ivars (class, 0); finish_struct (uprivate_record, ivar_context, NULL_TREE); @@ -2626,115 +3585,97 @@ build_method_prototype_template (void) return proto_record; } -/* True if last call to forwarding_offset yielded a register offset. */ -static int offset_is_register; +static tree +objc_method_parm_type (tree type) +{ + type = groktypename (TREE_TYPE (type)); + if (TREE_CODE (type) == TYPE_DECL) + type = TREE_TYPE (type); + return TYPE_MAIN_VARIANT (type); +} static int -forwarding_offset (tree parm) +objc_encoded_type_size (tree type) { - int offset_in_bytes; - - if (GET_CODE (DECL_INCOMING_RTL (parm)) == MEM) - { - rtx addr = XEXP (DECL_INCOMING_RTL (parm), 0); + int sz = int_size_in_bytes (type); - /* ??? Here we assume that the parm address is indexed - off the frame pointer or arg pointer. - If that is not true, we produce meaningless results, - but do not crash. */ - if (GET_CODE (addr) == PLUS - && GET_CODE (XEXP (addr, 1)) == CONST_INT) - offset_in_bytes = INTVAL (XEXP (addr, 1)); - else - offset_in_bytes = 0; - - offset_in_bytes += OBJC_FORWARDING_STACK_OFFSET; - offset_is_register = 0; - } - else if (GET_CODE (DECL_INCOMING_RTL (parm)) == REG) - { - int regno = REGNO (DECL_INCOMING_RTL (parm)); - offset_in_bytes = apply_args_register_offset (regno); - offset_is_register = 1; - } - else - return 0; - - /* This is the case where the parm is passed as an int or double - and it is converted to a char, short or float and stored back - in the parmlist. In this case, describe the parm - with the variable's declared type, and adjust the address - if the least significant bytes (which we are using) are not - the first ones. */ - if (BYTES_BIG_ENDIAN && TREE_TYPE (parm) != DECL_ARG_TYPE (parm)) - offset_in_bytes += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parm))) - - GET_MODE_SIZE (GET_MODE (DECL_RTL (parm)))); - - return offset_in_bytes; + /* Make all integer and enum types at least as large + as an int. */ + if (sz > 0 && (TREE_CODE (type) == INTEGER_TYPE + || TREE_CODE (type) == BOOLEAN_TYPE + || TREE_CODE (type) == ENUMERAL_TYPE)) + sz = MAX (sz, int_size_in_bytes (integer_type_node)); + /* Treat arrays as pointers, since that's how they're + passed in. */ + else if (TREE_CODE (type) == ARRAY_TYPE) + sz = int_size_in_bytes (ptr_type_node); + return sz; } static tree -encode_method_prototype (tree method_decl, tree func_decl) +encode_method_prototype (tree method_decl) { tree parms; - int stack_size, i; - tree user_args; - HOST_WIDE_INT max_parm_end = 0; + int parm_offset, i; char buf[40]; tree result; /* ONEWAY and BYCOPY, for remote object are the only method qualifiers. */ encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (method_decl))); - /* C type. */ - encode_type (TREE_TYPE (TREE_TYPE (func_decl)), + /* Encode return type. */ + encode_type (objc_method_parm_type (method_decl), obstack_object_size (&util_obstack), OBJC_ENCODE_INLINE_DEFS); /* Stack size. */ - for (parms = DECL_ARGUMENTS (func_decl); parms; + /* The first two arguments (self and _cmd) are pointers; account for + their size. */ + i = int_size_in_bytes (ptr_type_node); + parm_offset = 2 * i; + for (parms = METHOD_SEL_ARGS (method_decl); parms; parms = TREE_CHAIN (parms)) { - HOST_WIDE_INT parm_end = (forwarding_offset (parms) - + int_size_in_bytes (TREE_TYPE (parms))); + tree type = objc_method_parm_type (parms); + int sz = objc_encoded_type_size (type); - if (!offset_is_register && max_parm_end < parm_end) - max_parm_end = parm_end; + /* If a type size is not known, bail out. */ + if (sz < 0) + { + error ("%Jtype '%D' does not have a known size", + type, type); + /* Pretend that the encoding succeeded; the compilation will + fail nevertheless. */ + goto finish_encoding; + } + parm_offset += sz; } - stack_size = max_parm_end - OBJC_FORWARDING_MIN_OFFSET; - - sprintf (buf, "%d", stack_size); + sprintf (buf, "%d@0:%d", parm_offset, i); obstack_grow (&util_obstack, buf, strlen (buf)); - user_args = METHOD_SEL_ARGS (method_decl); - /* Argument types. */ - for (parms = DECL_ARGUMENTS (func_decl), i = 0; parms; - parms = TREE_CHAIN (parms), i++) + parm_offset = 2 * i; + for (parms = METHOD_SEL_ARGS (method_decl); parms; + parms = TREE_CHAIN (parms)) { + tree type = objc_method_parm_type (parms); + /* Process argument qualifiers for user supplied arguments. */ - if (i > 1) - { - encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (user_args))); - user_args = TREE_CHAIN (user_args); - } + encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (parms))); /* Type. */ - encode_type (TREE_TYPE (parms), - obstack_object_size (&util_obstack), + encode_type (type, obstack_object_size (&util_obstack), OBJC_ENCODE_INLINE_DEFS); /* Compute offset. */ - sprintf (buf, "%d", forwarding_offset (parms)); - - /* Indicate register. */ - if (offset_is_register) - obstack_1grow (&util_obstack, '+'); + sprintf (buf, "%d", parm_offset); + parm_offset += objc_encoded_type_size (type); obstack_grow (&util_obstack, buf, strlen (buf)); } + finish_encoding: obstack_1grow (&util_obstack, '\0'); result = get_identifier (obstack_finish (&util_obstack)); obstack_free (&util_obstack, util_firstobj); @@ -2822,103 +3763,6 @@ generate_method_descriptors (tree protocol) UOBJC_INSTANCE_METHODS_decl = 0; } -/* Generate a temporary FUNCTION_DECL node to be used in - hack_method_prototype below. */ - -static GTY(()) int build_tmp_function_decl_xxx; -static tree -build_tmp_function_decl (void) -{ - tree decl_specs, expr_decl, parms; - char buffer[80]; - tree tmp_decl; - - /* struct objc_object *objc_xxx (id, SEL, ...); */ - pushlevel (0); - decl_specs = build_tree_list (NULL_TREE, objc_object_reference); - push_parm_decl (build_tree_list - (build_tree_list (decl_specs, - build1 (INDIRECT_REF, NULL_TREE, - NULL_TREE)), - NULL_TREE)); - - decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, - get_identifier (TAG_SELECTOR))); - expr_decl = build1 (INDIRECT_REF, NULL_TREE, NULL_TREE); - - push_parm_decl (build_tree_list (build_tree_list (decl_specs, expr_decl), - NULL_TREE)); - parms = get_parm_info (0); - poplevel (0, 0, 0); - - decl_specs = build_tree_list (NULL_TREE, objc_object_reference); - sprintf (buffer, "__objc_tmp_%x", build_tmp_function_decl_xxx++); - expr_decl = build_nt (CALL_EXPR, get_identifier (buffer), parms, NULL_TREE); - expr_decl = build1 (INDIRECT_REF, NULL_TREE, expr_decl); - - tmp_decl = define_decl (expr_decl, decl_specs); - DECL_SOURCE_LINE (tmp_decl) = 0; - - return tmp_decl; -} - -/* Generate the prototypes for protocol methods. This is used to - generate method encodings for these. - - NST_METHODS is the method to generate a _DECL node for TMP_DECL is - a decl node to be used. This is also where the return value is - given. */ - -static void -hack_method_prototype (tree nst_methods, tree tmp_decl) -{ - tree parms; - tree parm; - - /* Hack to avoid problem with static typing of self arg. */ - TREE_SET_CODE (nst_methods, CLASS_METHOD_DECL); - start_method_def (nst_methods); - TREE_SET_CODE (nst_methods, INSTANCE_METHOD_DECL); - - if (METHOD_ADD_ARGS (nst_methods) == objc_ellipsis_node) - parms = get_parm_info (0); /* we have a `, ...' */ - else - parms = get_parm_info (1); /* place a `void_at_end' */ - - poplevel (0, 0, 0); /* Must be called BEFORE start_function. */ - - /* Usually called from store_parm_decls -> init_function_start. */ - - DECL_ARGUMENTS (tmp_decl) = TREE_PURPOSE (parms); - - if (current_function_decl) - abort (); - current_function_decl = tmp_decl; - - { - /* Code taken from start_function. */ - tree restype = TREE_TYPE (TREE_TYPE (tmp_decl)); - /* Promote the value to int before returning it. */ - if (TREE_CODE (restype) == INTEGER_TYPE - && TYPE_PRECISION (restype) < TYPE_PRECISION (integer_type_node)) - restype = integer_type_node; - DECL_RESULT (tmp_decl) = build_decl (RESULT_DECL, 0, restype); - } - - for (parm = DECL_ARGUMENTS (tmp_decl); parm; parm = TREE_CHAIN (parm)) - DECL_CONTEXT (parm) = tmp_decl; - - init_function_start (tmp_decl); - - /* Typically called from expand_function_start for function definitions. */ - assign_parms (tmp_decl); - - /* install return type */ - TREE_TYPE (TREE_TYPE (tmp_decl)) = groktypename (TREE_TYPE (nst_methods)); - - current_function_decl = NULL; -} - static void generate_protocol_references (tree plist) { @@ -2955,7 +3799,7 @@ generate_protocol_references (tree plist) The statically allocated Protocol objects that we generate here need to be fixed up at runtime in order to be used: the 'isa' - pointer of the objects need to be set up to point to the 'Protocol' + pointer of the objects need to be set up to point to the 'Protocol' class, as known at runtime. The NeXT runtime fixes up all protocols at program startup time, @@ -2978,16 +3822,15 @@ generate_protocol_references (tree plist) being referenced multiple times when compiled with the GNU runtime, and end up being fixed up multiple times at runtime inizialization. But that doesn't hurt, it's just a little inefficient. */ + static void generate_protocols (void) { - tree p, tmp_decl, encoding; + tree p, encoding; tree sc_spec, decl_specs, decl; tree initlist, protocol_name_expr, refs_decl, refs_expr; tree cast_type2; - tmp_decl = build_tmp_function_decl (); - if (! objc_protocol_template) objc_protocol_template = build_protocol_template (); @@ -3012,8 +3855,7 @@ generate_protocols (void) { if (! METHOD_ENCODING (nst_methods)) { - hack_method_prototype (nst_methods, tmp_decl); - encoding = encode_method_prototype (nst_methods, tmp_decl); + encoding = encode_method_prototype (nst_methods); METHOD_ENCODING (nst_methods) = encoding; } nst_methods = TREE_CHAIN (nst_methods); @@ -3023,8 +3865,7 @@ generate_protocols (void) { if (! METHOD_ENCODING (cls_methods)) { - hack_method_prototype (cls_methods, tmp_decl); - encoding = encode_method_prototype (cls_methods, tmp_decl); + encoding = encode_method_prototype (cls_methods); METHOD_ENCODING (cls_methods) = encoding; } @@ -3234,9 +4075,16 @@ build_selector_template (void) struct objc_class *sibling_class; } struct objc_protocol_list *protocols; + if (flag_next_runtime) + void *sel_id; void *gc_object_type; }; */ +/* NB: The 'sel_id' and 'gc_object_type' fields are not being used by + the NeXT/Apple runtime; still, the compiler must generate them to + maintain backward binary compatibility (and to allow for future + expansion). */ + static void build_class_template (void) { @@ -3357,12 +4205,16 @@ build_class_template (void) field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); - /* void *sel_id; */ + if (flag_next_runtime) + { + /* void *sel_id; */ - decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_VOID]); - field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("sel_id")); - field_decl = grokfield (field_decl, decl_specs, NULL_TREE); - chainon (field_decl_chain, field_decl); + decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_VOID]); + field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("sel_id")); + field_decl + = grokfield (field_decl, decl_specs, NULL_TREE); + chainon (field_decl_chain, field_decl); + } /* void *gc_object_type; */ @@ -3379,28 +4231,15 @@ build_class_template (void) static void synth_forward_declarations (void) { - tree sc_spec, decl_specs, an_id; + tree an_id; /* static struct objc_class _OBJC_CLASS_<my_name>; */ - - an_id = synth_id_with_class_suffix ("_OBJC_CLASS", objc_implementation_context); - - sc_spec = build_tree_list (NULL_TREE, ridpointers[(int) RID_EXTERN]); - decl_specs = tree_cons (NULL_TREE, objc_class_template, sc_spec); - UOBJC_CLASS_decl = define_decl (an_id, decl_specs); - TREE_USED (UOBJC_CLASS_decl) = 1; - DECL_ARTIFICIAL (UOBJC_CLASS_decl) = 1; - TREE_PUBLIC (UOBJC_CLASS_decl) = 0; + UOBJC_CLASS_decl = build_metadata_decl ("_OBJC_CLASS", + objc_class_template); /* static struct objc_class _OBJC_METACLASS_<my_name>; */ - - an_id = synth_id_with_class_suffix ("_OBJC_METACLASS", - objc_implementation_context); - - UOBJC_METACLASS_decl = define_decl (an_id, decl_specs); - TREE_USED (UOBJC_METACLASS_decl) = 1; - DECL_ARTIFICIAL (UOBJC_METACLASS_decl) = 1; - TREE_PUBLIC (UOBJC_METACLASS_decl) = 0; + UOBJC_METACLASS_decl = build_metadata_decl ("_OBJC_METACLASS", + objc_class_template); /* Pre-build the following entities - for speed/convenience. */ @@ -3412,7 +4251,9 @@ synth_forward_declarations (void) static void error_with_ivar (const char *message, tree decl, tree rawdecl) { - error ("%J%s `%s'", decl, message, gen_declaration (rawdecl, errbuf)); + error ("%J%s `%s'", decl, + message, gen_declaration (rawdecl, errbuf)); + } static void @@ -3427,6 +4268,10 @@ check_ivars (tree inter, tree imp) { tree t1, t2; +#ifdef OBJCPLUS + if (intdecls && TREE_CODE (intdecls) == TYPE_DECL) + intdecls = TREE_CHAIN (intdecls); +#endif if (intdecls == 0 && impdecls == 0) break; if (intdecls == 0 || impdecls == 0) @@ -3437,7 +4282,9 @@ check_ivars (tree inter, tree imp) t1 = TREE_TYPE (intdecls); t2 = TREE_TYPE (impdecls); - if (!comptypes (t1, t2, false)) + if (!comptypes (t1, t2, false) + || !tree_int_cst_equal (TREE_VALUE (TREE_VALUE (rawintdecls)), + TREE_VALUE (TREE_VALUE (rawimpdecls)))) { if (DECL_NAME (intdecls) == DECL_NAME (impdecls)) { @@ -3468,16 +4315,23 @@ check_ivars (tree inter, tree imp) } } -/* Set super_type to the data type node for struct objc_super *, - first defining struct objc_super itself. +/* Set 'objc_super_template' to the data type node for 'struct _objc_super'. This needs to be done just once per compilation. */ -static tree +static void build_super_template (void) { - tree record, decl_specs, field_decl, field_decl_chain; + tree decl_specs, field_decl, field_decl_chain; + + /* Suppress outputting debug symbols, because + dbxout_init hasn't been called yet. */ + enum debug_info_type save_write_symbols = write_symbols; + const struct gcc_debug_hooks *save_hooks = debug_hooks; - record = start_struct (RECORD_TYPE, get_identifier (UTAG_SUPER)); + write_symbols = NO_DEBUG; + debug_hooks = &do_nothing_debug_hooks; + + objc_super_template = start_struct (RECORD_TYPE, get_identifier (UTAG_SUPER)); /* struct objc_object *self; */ @@ -3496,14 +4350,10 @@ build_super_template (void) field_decl = grokfield (field_decl, decl_specs, NULL_TREE); chainon (field_decl_chain, field_decl); - finish_struct (record, field_decl_chain, NULL_TREE); + finish_struct (objc_super_template, field_decl_chain, NULL_TREE); - /* `struct objc_super *' */ - super_type = groktypename (build_tree_list (build_tree_list (NULL_TREE, - record), - build1 (INDIRECT_REF, - NULL_TREE, NULL_TREE))); - return record; + write_symbols = save_write_symbols; + debug_hooks = save_hooks; } /* struct objc_ivar { @@ -3672,8 +4522,9 @@ build_ivar_list_initializer (tree type, tree field_decl) initlist = tree_cons (NULL_TREE, objc_build_constructor (type, nreverse (ivar)), initlist); - - field_decl = TREE_CHAIN (field_decl); + do + field_decl = TREE_CHAIN (field_decl); + while (field_decl && TREE_CODE (field_decl) != FIELD_DECL); } while (field_decl); @@ -3702,6 +4553,20 @@ generate_ivars_list (tree type, const char *name, int size, tree list) return decl; } +/* Count only the fields occurring in T. */ +static int +ivar_list_length (t) + tree t; +{ + int count = 0; + + for (; t; t = TREE_CHAIN (t)) + if (TREE_CODE (t) == FIELD_DECL) + ++count; + + return count; +} + static void generate_ivar_lists (void) { @@ -3727,7 +4592,7 @@ generate_ivar_lists (void) if (CLASS_SUPER_NAME (implementation_template) == NULL_TREE && (chain = TYPE_FIELDS (objc_class_template))) { - size = list_length (chain); + size = ivar_list_length (chain); ivar_list_template = build_ivar_list_template (objc_ivar_template, size); initlist = build_ivar_list_initializer (objc_ivar_template, chain); @@ -3743,7 +4608,7 @@ generate_ivar_lists (void) chain = CLASS_IVARS (implementation_template); if (chain) { - size = list_length (chain); + size = ivar_list_length (chain); ivar_list_template = build_ivar_list_template (objc_ivar_template, size); initlist = build_ivar_list_initializer (objc_ivar_template, chain); @@ -3774,7 +4639,7 @@ build_dispatch_table_initializer (tree type, tree entries) /* Generate the method encoding if we don't have one already. */ if (! METHOD_ENCODING (entries)) METHOD_ENCODING (entries) = - encode_method_def (METHOD_DEFINITION (entries)); + encode_method_prototype (entries); elemlist = tree_cons (NULL_TREE, add_objc_string (METHOD_ENCODING (entries), @@ -4106,6 +4971,8 @@ build_category_initializer (tree type, tree cat_name, tree class_name, struct objc_class *sibling_class; } struct objc_protocol_list *protocols; + if (flag_next_runtime) + void *sel_id; void *gc_object_type; }; */ @@ -4187,6 +5054,10 @@ build_shared_structure_initializer (tree type, tree isa, tree super, initlist = tree_cons (NULL_TREE, expr, initlist); } + if (flag_next_runtime) + /* sel_id = NULL */ + initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); + /* gc_object_type = NULL */ initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist); @@ -4238,7 +5109,6 @@ generate_category (tree cat) UOBJC_CLASS_METHODS_decl, protocol_decl); - TREE_USED (decl) = 1; finish_decl (decl, initlist, NULL_TREE); } @@ -4357,7 +5227,7 @@ synth_id_with_class_suffix (const char *preamble, tree ctxt) { const char *const class_name = IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context)); - string = alloca (strlen (preamble) + strlen (class_name) + 3); + string = (char *) alloca (strlen (preamble) + strlen (class_name) + 3); sprintf (string, "%s_%s", preamble, IDENTIFIER_POINTER (CLASS_NAME (ctxt))); } @@ -4369,14 +5239,17 @@ synth_id_with_class_suffix (const char *preamble, tree ctxt) = IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context)); const char *const class_super_name = IDENTIFIER_POINTER (CLASS_SUPER_NAME (objc_implementation_context)); - string = alloca (strlen (preamble) + strlen (class_name) - + strlen (class_super_name) + 3); + string = (char *) alloca (strlen (preamble) + + strlen (class_name) + + strlen (class_super_name) + + 3); sprintf (string, "%s_%s_%s", preamble, class_name, class_super_name); } else if (TREE_CODE (ctxt) == PROTOCOL_INTERFACE_TYPE) { const char *protocol_name = IDENTIFIER_POINTER (PROTOCOL_NAME (ctxt)); - string = alloca (strlen (preamble) + strlen (protocol_name) + 3); + string + = (char *) alloca (strlen (preamble) + strlen (protocol_name) + 3); sprintf (string, "%s_%s", preamble, protocol_name); } else @@ -4492,7 +5365,7 @@ build_keyword_selector (tree selector) len++; } - buf = alloca (len + 1); + buf = (char *) alloca (len + 1); /* Start the buffer out as an empty string. */ buf[0] = '\0'; @@ -4501,7 +5374,13 @@ build_keyword_selector (tree selector) if (TREE_CODE (selector) == KEYWORD_DECL) key_name = KEYWORD_KEY_NAME (key_chain); else if (TREE_CODE (selector) == TREE_LIST) - key_name = TREE_PURPOSE (key_chain); + { + key_name = TREE_PURPOSE (key_chain); + /* The keyword decl chain will later be used as a function argument + chain. Unhook the selector itself so as to not confuse other + parts of the compiler. */ + TREE_PURPOSE (key_chain) = NULL_TREE; + } else abort (); @@ -4548,12 +5427,13 @@ build_method_decl (enum tree_code code, tree ret_type, tree selector, #define METHOD_DEF 0 #define METHOD_REF 1 -/* Used by `build_objc_method_call' and `comp_method_types'. Return +/* Used by `build_objc_method_call' and `comp_proto_with_proto'. Return an argument list for method METH. CONTEXT is either METHOD_DEF or METHOD_REF, saying whether we are trying to define a method or call one. SUPERFLAG says this is for a send to super; this makes a difference for the NeXT calling sequence in which the lookup and - the method call are done together. */ + the method call are done together. If METH is null, user-defined + arguments (i.e., beyond self and _cmd) shall be represented by `...'. */ static tree get_arg_type_list (tree meth, int context, int superflag) @@ -4571,6 +5451,11 @@ get_arg_type_list (tree meth, int context, int superflag) /* Selector type - will eventually change to `int'. */ chainon (arglist, build_tree_list (NULL_TREE, selector_type)); + /* No actual method prototype given -- assume that remaining arguments + are `...'. */ + if (!meth) + return arglist; + /* Build a list of argument types. */ for (akey = METHOD_SEL_ARGS (meth); akey; akey = TREE_CHAIN (akey)) { @@ -4590,13 +5475,13 @@ get_arg_type_list (tree meth, int context, int superflag) } else /* finalize the arglist...simulate get_parm_info (1) */ - chainon (arglist, build_tree_list (NULL_TREE, void_type_node)); + chainon (arglist, OBJC_VOID_AT_END); return arglist; } static tree -check_duplicates (hash hsh) +check_duplicates (hash hsh, int methods) { tree meth = NULL_TREE; @@ -4606,14 +5491,16 @@ check_duplicates (hash hsh) if (hsh->list) { - /* We have two methods with the same name and different types. */ + /* We have two or more methods with the same name but + different types. */ attr loop; char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL) ? '-' : '+'; - warning ("multiple declarations for method `%s'", + warning ("multiple %s named `%c%s' found", + methods ? "methods" : "selectors", type, IDENTIFIER_POINTER (METHOD_SEL_NAME (meth))); - warn_with_method ("using", type, meth); + warn_with_method (methods ? "using" : "found", type, meth); for (loop = hsh->list; loop; loop = loop->next) warn_with_method ("also found", type, loop->value); } @@ -4627,51 +5514,53 @@ check_duplicates (hash hsh) used. */ static tree -receiver_is_class_object (tree receiver) +receiver_is_class_object (tree receiver, int self, int super) { tree chain, exp, arg; - /* The receiver is 'self' in the context of a class method. */ + /* The receiver is 'self' or 'super' in the context of a class method. */ if (objc_method_context - && receiver == self_decl - && TREE_CODE (objc_method_context) == CLASS_METHOD_DECL) - { - return CLASS_NAME (objc_implementation_context); - } + && TREE_CODE (objc_method_context) == CLASS_METHOD_DECL + && (self || super)) + return (super + ? CLASS_SUPER_NAME (implementation_template) + : CLASS_NAME (implementation_template)); if (flag_next_runtime) { /* The receiver is a variable created by build_class_reference_decl. */ if (TREE_CODE (receiver) == VAR_DECL - && TREE_TYPE (receiver) == objc_class_type) - /* Look up the identifier. */ + && TREE_TYPE (TREE_TYPE (receiver)) == TREE_TYPE (objc_class_type)) + /* Look up the identifier. */ for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain)) if (TREE_PURPOSE (chain) == receiver) - return TREE_VALUE (chain); - } - else - { - /* The receiver is a function call that returns an id. Check if - it is a call to objc_getClass, if so, pick up the class name. */ - if (TREE_CODE (receiver) == CALL_EXPR - && (exp = TREE_OPERAND (receiver, 0)) - && TREE_CODE (exp) == ADDR_EXPR - && (exp = TREE_OPERAND (exp, 0)) - && TREE_CODE (exp) == FUNCTION_DECL - && exp == objc_get_class_decl - /* We have a call to objc_getClass! */ - && (arg = TREE_OPERAND (receiver, 1)) - && TREE_CODE (arg) == TREE_LIST - && (arg = TREE_VALUE (arg))) - { - STRIP_NOPS (arg); - if (TREE_CODE (arg) == ADDR_EXPR - && (arg = TREE_OPERAND (arg, 0)) - && TREE_CODE (arg) == STRING_CST) - /* Finally, we have the class name. */ - return get_identifier (TREE_STRING_POINTER (arg)); - } + return TREE_VALUE (chain); + } + + /* The receiver is a function call that returns an id. Check if + it is a call to objc_getClass, if so, pick up the class name. */ + if (TREE_CODE (receiver) == CALL_EXPR + && (exp = TREE_OPERAND (receiver, 0)) + && TREE_CODE (exp) == ADDR_EXPR + && (exp = TREE_OPERAND (exp, 0)) + && TREE_CODE (exp) == FUNCTION_DECL + /* For some reason, we sometimes wind up with multiple FUNCTION_DECL + prototypes for objc_get_class(). Thankfuly, they seem to share the + same function type. */ + && TREE_TYPE (exp) == TREE_TYPE (objc_get_class_decl) + && !strcmp (IDENTIFIER_POINTER (DECL_NAME (exp)), TAG_GETCLASS) + /* We have a call to objc_get_class/objc_getClass! */ + && (arg = TREE_OPERAND (receiver, 1)) + && TREE_CODE (arg) == TREE_LIST + && (arg = TREE_VALUE (arg))) + { + STRIP_NOPS (arg); + if (TREE_CODE (arg) == ADDR_EXPR + && (arg = TREE_OPERAND (arg, 0)) + && TREE_CODE (arg) == STRING_CST) + /* Finally, we have the class name. */ + return get_identifier (TREE_STRING_POINTER (arg)); } return 0; } @@ -4739,9 +5628,29 @@ build_message_expr (tree mess) method_params = args; } +#ifdef OBJCPLUS + if (processing_template_decl) + /* Must wait until template instantiation time. */ + return build_min_nt (MESSAGE_SEND_EXPR, receiver, sel_name, + method_params); +#endif + return finish_message_expr (receiver, sel_name, method_params); } +static tree +lookup_method_in_hash_lists (tree sel_name) +{ + hash method_prototype = hash_lookup (nst_method_hash_list, + sel_name); + + if (!method_prototype) + method_prototype = hash_lookup (cls_method_hash_list, + sel_name); + + return check_duplicates (method_prototype, 1); +} + /* The 'finish_message_expr' routine is called from within 'build_message_expr' for non-template functions. In the case of C++ template functions, it is called from 'build_expr_from_tree' @@ -4750,211 +5659,155 @@ build_message_expr (tree mess) tree finish_message_expr (tree receiver, tree sel_name, tree method_params) { - tree method_prototype = NULL_TREE, class_ident = NULL_TREE; - tree selector, self_object, retval; - int statically_typed = 0, statically_allocated = 0; - - /* Determine receiver type. */ - tree rtype = TREE_TYPE (receiver); - int super = IS_SUPER (rtype); - - if (! super) - { - if (TREE_STATIC_TEMPLATE (rtype)) - statically_allocated = 1; - else if (TREE_CODE (rtype) == POINTER_TYPE - && TREE_STATIC_TEMPLATE (TREE_TYPE (rtype))) - statically_typed = 1; - else if ((flag_next_runtime - || (IS_ID (rtype))) - && (class_ident = receiver_is_class_object (receiver))) - ; - else if (! IS_ID (rtype) - /* Allow any type that matches objc_class_type. */ - && ! comptypes (rtype, objc_class_type, false)) + tree method_prototype = NULL_TREE, rprotos = NULL_TREE, rtype; + tree selector, retval, is_class; + int self, super, have_cast; + + /* Extract the receiver of the message, as well as its type + (where the latter may take the form of a cast or be inferred + from the implementation context). */ + rtype = receiver; + while (TREE_CODE (rtype) == COMPOUND_EXPR + || TREE_CODE (rtype) == MODIFY_EXPR + || TREE_CODE (rtype) == NOP_EXPR + || TREE_CODE (rtype) == COMPONENT_REF) + rtype = TREE_OPERAND (rtype, 0); + self = (rtype == self_decl); + super = (rtype == UOBJC_SUPER_decl); + rtype = TREE_TYPE (receiver); + have_cast = (TREE_CODE (receiver) == NOP_EXPR + || (TREE_CODE (receiver) == COMPOUND_EXPR + && !IS_SUPER (rtype))); + + /* If the receiver is a class object, retrieve the corresponding + @interface, if one exists. */ + is_class = receiver_is_class_object (receiver, self, super); + + /* Now determine the receiver type (if an explicit cast has not been + provided). */ + if (!have_cast) + { + if (is_class) + rtype = lookup_interface (is_class); + /* Handle `self' and `super'. */ + else if (super) { - warning ("invalid receiver type `%s'", - gen_declaration (rtype, errbuf)); + if (!CLASS_SUPER_NAME (implementation_template)) + { + error ("no super class declared in @interface for `%s'", + IDENTIFIER_POINTER (CLASS_NAME (implementation_template))); + return error_mark_node; + } + rtype = lookup_interface (CLASS_SUPER_NAME (implementation_template)); } - if (statically_allocated) - receiver = build_unary_op (ADDR_EXPR, receiver, 0); - - /* Don't evaluate the receiver twice. */ - receiver = save_expr (receiver); - self_object = receiver; + else if (self) + rtype = lookup_interface (CLASS_NAME (implementation_template)); } - else - /* If sending to `super', use current self as the object. */ - self_object = self_decl; - /* Determine operation return type. */ - - if (super) + /* If receiver is of type `id' or `Class' (or if the @interface for a + class is not visible), we shall be satisfied with the existence of + any instance or class method. */ + if (!rtype || IS_ID (rtype) + || TREE_TYPE (rtype) == TREE_TYPE (objc_class_type)) { - tree iface; - - if (CLASS_SUPER_NAME (implementation_template)) + if (!rtype) + rtype = xref_tag (RECORD_TYPE, is_class); + else if (IS_ID (rtype)) { - iface - = lookup_interface (CLASS_SUPER_NAME (implementation_template)); - - if (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL) - method_prototype = lookup_instance_method_static (iface, sel_name); - else - method_prototype = lookup_class_method_static (iface, sel_name); - - if (iface && !method_prototype) - warning ("`%s' does not respond to `%s'", - IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_template)), - IDENTIFIER_POINTER (sel_name)); + rprotos = TYPE_PROTOCOL_LIST (rtype); + rtype = NULL_TREE; } else - { - error ("no super class declared in interface for `%s'", - IDENTIFIER_POINTER (CLASS_NAME (implementation_template))); - return error_mark_node; - } - - } - else if (statically_allocated) - { - tree ctype = TREE_TYPE (rtype); - tree iface = lookup_interface (TYPE_NAME (rtype)); + is_class = TYPE_NAME (rtype) = get_identifier ("Class"); - if (iface) - method_prototype = lookup_instance_method_static (iface, sel_name); - - if (! method_prototype && ctype && TYPE_PROTOCOL_LIST (ctype)) + if (rprotos) method_prototype - = lookup_method_in_protocol_list (TYPE_PROTOCOL_LIST (ctype), - sel_name, 0); - - if (!method_prototype) - warning ("`%s' does not respond to `%s'", - IDENTIFIER_POINTER (TYPE_NAME (rtype)), - IDENTIFIER_POINTER (sel_name)); + = lookup_method_in_protocol_list (rprotos, sel_name, + is_class != NULL_TREE); + if (!method_prototype && !rprotos) + method_prototype + = (is_class + ? check_duplicates (hash_lookup (cls_method_hash_list, sel_name), 1) + : lookup_method_in_hash_lists (sel_name)); } - else if (statically_typed) + else { - tree ctype = TREE_TYPE (rtype); - - /* `self' is now statically_typed. All methods should be visible - within the context of the implementation. */ - if (objc_implementation_context - && CLASS_NAME (objc_implementation_context) == TYPE_NAME (ctype)) + tree orig_rtype = rtype, saved_rtype; + + if (TREE_CODE (rtype) == POINTER_TYPE) + rtype = TREE_TYPE (rtype); + /* Traverse typedef aliases */ + while (TREE_CODE (rtype) == RECORD_TYPE && TYPE_NAME (rtype) + && TREE_CODE (TYPE_NAME (rtype)) == TYPE_DECL + && DECL_ORIGINAL_TYPE (TYPE_NAME (rtype))) + rtype = DECL_ORIGINAL_TYPE (TYPE_NAME (rtype)); + saved_rtype = rtype; + if (TYPED_OBJECT (rtype)) { - method_prototype - = lookup_instance_method_static (implementation_template, - sel_name); - - if (! method_prototype && TYPE_PROTOCOL_LIST (ctype)) - method_prototype - = lookup_method_in_protocol_list (TYPE_PROTOCOL_LIST (ctype), - sel_name, 0); - - if (! method_prototype - && implementation_template != objc_implementation_context) - /* The method is not published in the interface. Check - locally. */ - method_prototype - = lookup_method (CLASS_NST_METHODS (objc_implementation_context), - sel_name); + rprotos = TYPE_PROTOCOL_LIST (rtype); + rtype = lookup_interface (OBJC_TYPE_NAME (rtype)); } - else - { - tree iface; - - if ((iface = lookup_interface (TYPE_NAME (ctype)))) - method_prototype = lookup_instance_method_static (iface, sel_name); - - if (! method_prototype) - { - tree protocol_list = TYPE_PROTOCOL_LIST (ctype); - if (protocol_list) - method_prototype - = lookup_method_in_protocol_list (protocol_list, - sel_name, 0); - } - } - - if (!method_prototype) - warning ("`%s' does not respond to `%s'", - IDENTIFIER_POINTER (TYPE_NAME (ctype)), - IDENTIFIER_POINTER (sel_name)); - } - else if (class_ident) - { - if (objc_implementation_context - && CLASS_NAME (objc_implementation_context) == class_ident) + /* If we could not find an @interface declaration, we must have + only seen a @class declaration; so, we cannot say anything + more intelligent about which methods the receiver will + understand. */ + if (!rtype) + rtype = saved_rtype; + else if (TREE_CODE (rtype) == CLASS_INTERFACE_TYPE + || TREE_CODE (rtype) == CLASS_IMPLEMENTATION_TYPE) { + /* We have a valid ObjC class name. Look up the method name + in the published @interface for the class (and its + superclasses). */ method_prototype - = lookup_class_method_static (implementation_template, sel_name); + = lookup_method_static (rtype, sel_name, is_class != NULL_TREE); - if (!method_prototype - && implementation_template != objc_implementation_context) - /* The method is not published in the interface. Check - locally. */ + /* If the method was not found in the @interface, it may still + exist locally as part of the @implementation. */ + if (!method_prototype && objc_implementation_context + && CLASS_NAME (objc_implementation_context) + == OBJC_TYPE_NAME (rtype)) method_prototype - = lookup_method (CLASS_CLS_METHODS (objc_implementation_context), - sel_name); + = lookup_method + ((is_class + ? CLASS_CLS_METHODS (objc_implementation_context) + : CLASS_NST_METHODS (objc_implementation_context)), + sel_name); + + /* If we haven't found a candidate method by now, try looking for + it in the protocol list. */ + if (!method_prototype && rprotos) + method_prototype + = lookup_method_in_protocol_list (rprotos, sel_name, + is_class != NULL_TREE); } else { - tree iface; - - if ((iface = lookup_interface (class_ident))) - method_prototype = lookup_class_method_static (iface, sel_name); - } - - if (!method_prototype) - { - warning ("cannot find class (factory) method"); - warning ("return type for `%s' defaults to id", - IDENTIFIER_POINTER (sel_name)); + warning ("invalid receiver type `%s'", + gen_declaration (orig_rtype, errbuf)); + rtype = rprotos = NULL_TREE; } - } - else if (IS_PROTOCOL_QUALIFIED_ID (rtype)) - { - /* An anonymous object that has been qualified with a protocol. */ - - tree protocol_list = TYPE_PROTOCOL_LIST (rtype); - - method_prototype = lookup_method_in_protocol_list (protocol_list, - sel_name, 0); - - if (!method_prototype) - { - hash hsh; - - warning ("method `%s' not implemented by protocol", - IDENTIFIER_POINTER (sel_name)); - - /* Try and find the method signature in the global pools. */ - - if (!(hsh = hash_lookup (nst_method_hash_list, sel_name))) - hsh = hash_lookup (cls_method_hash_list, sel_name); + } - if (!(method_prototype = check_duplicates (hsh))) - warning ("return type defaults to id"); - } - } - else + if (!method_prototype) { - hash hsh; - - /* We think we have an instance...loophole: extern id Object; */ - hsh = hash_lookup (nst_method_hash_list, sel_name); - - if (!hsh) - /* For various loopholes */ - hsh = hash_lookup (cls_method_hash_list, sel_name); + static bool warn_missing_methods = false; - method_prototype = check_duplicates (hsh); - if (!method_prototype) + if (rtype) + warning ("`%s' may not respond to `%c%s'", + IDENTIFIER_POINTER (OBJC_TYPE_NAME (rtype)), + (is_class ? '+' : '-'), + IDENTIFIER_POINTER (sel_name)); + if (rprotos) + warning ("`%c%s' not implemented by protocol(s)", + (is_class ? '+' : '-'), + IDENTIFIER_POINTER (sel_name)); + if (!warn_missing_methods) { - warning ("cannot find method"); - warning ("return type for `%s' defaults to id", - IDENTIFIER_POINTER (sel_name)); + warning ("(Messages without a matching method signature"); + warning ("will be assumed to return `id' and accept"); + warning ("`...' as arguments.)"); + warn_missing_methods = true; } } @@ -4970,7 +5823,7 @@ finish_message_expr (tree receiver, tree sel_name, tree method_params) selector = build_selector_reference (sel_name); retval = build_objc_method_call (super, method_prototype, - receiver, self_object, + receiver, selector, method_params); current_objc_message_selector = 0; @@ -4987,73 +5840,68 @@ finish_message_expr (tree receiver, tree sel_name, tree method_params) static tree build_objc_method_call (int super_flag, tree method_prototype, - tree lookup_object, tree object, tree selector, + tree lookup_object, tree selector, tree method_params) { - tree sender = (super_flag ? umsg_super_decl : umsg_decl); - tree rcv_p = (super_flag - ? build_pointer_type (xref_tag (RECORD_TYPE, - get_identifier (TAG_SUPER))) - : id_type); + tree sender = (super_flag ? umsg_super_decl : + (!flag_next_runtime || flag_nil_receivers + ? umsg_decl + : umsg_nonnil_decl)); + tree rcv_p = (super_flag ? super_type : id_type); + + /* If a prototype for the method to be called exists, then cast + the sender's return type and arguments to match that of the method. + Otherwise, leave sender as is. */ + tree ret_type + = (method_prototype + ? groktypename (TREE_TYPE (method_prototype)) + : id_type); + tree sender_cast + = build_pointer_type + (build_function_type + (ret_type, + get_arg_type_list + (method_prototype, METHOD_REF, super_flag))); + + lookup_object = build_c_cast (rcv_p, lookup_object); if (flag_next_runtime) { - if (! method_prototype) - { - method_params = tree_cons (NULL_TREE, lookup_object, - tree_cons (NULL_TREE, selector, - method_params)); - assemble_external (sender); - return build_function_call (sender, method_params); - } - else - { - /* This is a real kludge, but it is used only for the Next. - Clobber the data type of SENDER temporarily to accept - all the arguments for this operation, and to return - whatever this operation returns. */ - tree arglist = NULL_TREE, retval, savarg, savret; - tree ret_type = groktypename (TREE_TYPE (method_prototype)); - - /* Save the proper contents of SENDER's data type. */ - savarg = TYPE_ARG_TYPES (TREE_TYPE (sender)); - savret = TREE_TYPE (TREE_TYPE (sender)); - - /* Install this method's argument types. */ - arglist = get_arg_type_list (method_prototype, METHOD_REF, - super_flag); - TYPE_ARG_TYPES (TREE_TYPE (sender)) = arglist; - - /* Install this method's return type. */ - TREE_TYPE (TREE_TYPE (sender)) = ret_type; - - /* Call SENDER with all the parameters. This will do type - checking using the arg types for this method. */ - method_params = tree_cons (NULL_TREE, lookup_object, - tree_cons (NULL_TREE, selector, - method_params)); - assemble_external (sender); - retval = build_function_call (sender, method_params); - - /* Restore SENDER's return/argument types. */ - TYPE_ARG_TYPES (TREE_TYPE (sender)) = savarg; - TREE_TYPE (TREE_TYPE (sender)) = savret; - return retval; - } +#ifdef STRUCT_VALUE + /* If we are returning a struct in memory, and the address + of that memory location is passed as a hidden first + argument, then change which messenger entry point this + expr will call. NB: Note that sender_cast remains + unchanged (it already has a struct return type). */ + if ((TREE_CODE (ret_type) == RECORD_TYPE + || TREE_CODE (ret_type) == UNION_TYPE) +#if defined (DEFAULT_PCC_STRUCT_RETURN) && DEFAULT_PCC_STRUCT_RETURN == 0 + && RETURN_IN_MEMORY (ret_type) +#endif + && STRUCT_VALUE == 0) + sender = (super_flag ? umsg_super_stret_decl : + flag_nil_receivers ? umsg_stret_decl : umsg_nonnil_stret_decl); +#endif + method_params = tree_cons (NULL_TREE, lookup_object, + tree_cons (NULL_TREE, selector, + method_params)); + TREE_USED (sender) = 1; + assemble_external (sender); + /* We want to cast the sender, not convert it. */ + return build_function_call (build_c_cast (sender_cast, sender), + method_params); } else { - /* This is the portable way. - First call the lookup function to get a pointer to the method, - then cast the pointer, then call it with the method arguments. */ - tree method; - - /* Avoid trouble since we may evaluate each of these twice. */ - object = save_expr (object); - selector = save_expr (selector); - - lookup_object = build_c_cast (rcv_p, lookup_object); + /* This is the portable (GNU) way. */ + tree method, object; + /* First, call the lookup function to get a pointer to the method, + then cast the pointer, then call it with the method arguments. + Use SAVE_EXPR to avoid evaluating the receiver twice. */ + lookup_object = save_expr (lookup_object); + object = (super_flag ? self_decl : lookup_object); + TREE_USED (sender) = 1; assemble_external (sender); method = build_function_call (sender, @@ -5061,27 +5909,13 @@ build_objc_method_call (int super_flag, tree method_prototype, tree_cons (NULL_TREE, selector, NULL_TREE))); - /* If we have a method prototype, construct the data type this - method needs, and cast what we got from SENDER into a pointer - to that type. */ - if (method_prototype) - { - tree arglist = get_arg_type_list (method_prototype, METHOD_REF, - super_flag); - tree valtype = groktypename (TREE_TYPE (method_prototype)); - tree fake_function_type = build_function_type (valtype, arglist); - TREE_TYPE (method) = build_pointer_type (fake_function_type); - } - else - TREE_TYPE (method) - = build_pointer_type (build_function_type (ptr_type_node, NULL_TREE)); - /* Pass the object to the method. */ + TREE_USED (method) = 1; assemble_external (method); - return build_function_call (method, - tree_cons (NULL_TREE, object, - tree_cons (NULL_TREE, selector, - method_params))); + return build_function_call + (build_c_cast (sender_cast, method), + tree_cons (NULL_TREE, object, + tree_cons (NULL_TREE, selector, method_params))); } } @@ -5170,7 +6004,7 @@ build_protocol_expr (tree protoname) if (!*chain) { *chain = tree_cons (NULL_TREE, protocol_struct_type, NULL_TREE); - add_objc_string (TYPE_NAME (protocol_struct_type), + add_objc_string (OBJC_TYPE_NAME (protocol_struct_type), class_names); } @@ -5289,8 +6123,10 @@ hash_func (tree sel_name) static void hash_init (void) { - nst_method_hash_list = ggc_calloc (SIZEHASHTABLE, sizeof (hash)); - cls_method_hash_list = ggc_calloc (SIZEHASHTABLE, sizeof (hash)); + nst_method_hash_list + = (hash *) ggc_alloc_cleared (SIZEHASHTABLE * sizeof (hash)); + cls_method_hash_list + = (hash *) ggc_alloc_cleared (SIZEHASHTABLE * sizeof (hash)); } /* WARNING!!!! hash_enter is called with a method, and will peek @@ -5304,7 +6140,7 @@ hash_enter (hash *hashlist, tree method) hash obj; int slot = hash_func (METHOD_SEL_NAME (method)) % SIZEHASHTABLE; - obj = ggc_alloc (sizeof (struct hashed_entry)); + obj = (hash) ggc_alloc (sizeof (struct hashed_entry)); obj->list = 0; obj->next = hashlist[slot]; obj->key = method; @@ -5334,7 +6170,7 @@ hash_add_attr (hash entry, tree value) { attr obj; - obj = ggc_alloc (sizeof (struct hashed_attribute)); + obj = (attr) ggc_alloc (sizeof (struct hashed_attribute)); obj->next = entry->list; obj->value = value; @@ -5362,189 +6198,108 @@ lookup_method (tree mchain, tree method) } static tree -lookup_instance_method_static (tree interface, tree ident) +lookup_method_static (tree interface, tree ident, int is_class) { + tree meth = NULL_TREE, root_inter = NULL_TREE; tree inter = interface; - tree chain = CLASS_NST_METHODS (inter); - tree meth = NULL_TREE; - do + while (inter) { + tree chain = is_class ? CLASS_CLS_METHODS (inter) : CLASS_NST_METHODS (inter); + tree category = inter; + + /* First, look up the method in the class itself. */ if ((meth = lookup_method (chain, ident))) return meth; - if (CLASS_CATEGORY_LIST (inter)) + /* Failing that, look for the method in each category of the class. */ + while ((category = CLASS_CATEGORY_LIST (category))) { - tree category = CLASS_CATEGORY_LIST (inter); - chain = CLASS_NST_METHODS (category); + chain = is_class ? CLASS_CLS_METHODS (category) : CLASS_NST_METHODS (category); - do - { - if ((meth = lookup_method (chain, ident))) - return meth; - - /* Check for instance methods in protocols in categories. */ - if (CLASS_PROTOCOL_LIST (category)) - { - if ((meth = (lookup_method_in_protocol_list - (CLASS_PROTOCOL_LIST (category), ident, 0)))) - return meth; - } - - if ((category = CLASS_CATEGORY_LIST (category))) - chain = CLASS_NST_METHODS (category); - } - while (category); - } - - if (CLASS_PROTOCOL_LIST (inter)) - { - if ((meth = (lookup_method_in_protocol_list - (CLASS_PROTOCOL_LIST (inter), ident, 0)))) + /* Check directly in each category. */ + if ((meth = lookup_method (chain, ident))) return meth; - } - - if ((inter = lookup_interface (CLASS_SUPER_NAME (inter)))) - chain = CLASS_NST_METHODS (inter); - } - while (inter); - - return meth; -} -static tree -lookup_class_method_static (tree interface, tree ident) -{ - tree inter = interface; - tree chain = CLASS_CLS_METHODS (inter); - tree meth = NULL_TREE; - tree root_inter = NULL_TREE; - - do - { - if ((meth = lookup_method (chain, ident))) - return meth; - - if (CLASS_CATEGORY_LIST (inter)) - { - tree category = CLASS_CATEGORY_LIST (inter); - chain = CLASS_CLS_METHODS (category); - - do + /* Failing that, check in each category's protocols. */ + if (CLASS_PROTOCOL_LIST (category)) { - if ((meth = lookup_method (chain, ident))) + if ((meth = (lookup_method_in_protocol_list + (CLASS_PROTOCOL_LIST (category), ident, is_class)))) return meth; - - /* Check for class methods in protocols in categories. */ - if (CLASS_PROTOCOL_LIST (category)) - { - if ((meth = (lookup_method_in_protocol_list - (CLASS_PROTOCOL_LIST (category), ident, 1)))) - return meth; - } - - if ((category = CLASS_CATEGORY_LIST (category))) - chain = CLASS_CLS_METHODS (category); } - while (category); } - /* Check for class methods in protocols. */ + /* If not found in categories, check in protocols of the main class. */ if (CLASS_PROTOCOL_LIST (inter)) { if ((meth = (lookup_method_in_protocol_list - (CLASS_PROTOCOL_LIST (inter), ident, 1)))) + (CLASS_PROTOCOL_LIST (inter), ident, is_class)))) return meth; } + /* Failing that, climb up the inheritance hierarchy. */ root_inter = inter; - if ((inter = lookup_interface (CLASS_SUPER_NAME (inter)))) - chain = CLASS_CLS_METHODS (inter); + inter = lookup_interface (CLASS_SUPER_NAME (inter)); } while (inter); /* If no class (factory) method was found, check if an _instance_ method of the same name exists in the root class. This is what - the Objective-C runtime will do. */ - return lookup_instance_method_static (root_inter, ident); + the Objective-C runtime will do. If an instance method was not + found, return 0. */ + return is_class ? lookup_method_static (root_inter, ident, 0): NULL_TREE; } tree -add_class_method (tree class, tree method) +add_method (tree class, tree method, int is_class) { tree mth; hash hsh; - if (!(mth = lookup_method (CLASS_CLS_METHODS (class), method))) + if (!(mth = lookup_method (is_class ? CLASS_CLS_METHODS (class) : CLASS_NST_METHODS (class), method))) { /* put method on list in reverse order */ - TREE_CHAIN (method) = CLASS_CLS_METHODS (class); - CLASS_CLS_METHODS (class) = method; - } - else - { - if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE) - error ("duplicate definition of class method `%s'", - IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); + if (is_class) + { + TREE_CHAIN (method) = CLASS_CLS_METHODS (class); + CLASS_CLS_METHODS (class) = method; + } else - { - /* Check types; if different, complain. */ - if (!comp_proto_with_proto (method, mth)) - error ("duplicate declaration of class method `%s'", - IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); - } - } - - if (!(hsh = hash_lookup (cls_method_hash_list, METHOD_SEL_NAME (method)))) - { - /* Install on a global chain. */ - hash_enter (cls_method_hash_list, method); - } - else - { - /* Check types; if different, add to a list. */ - if (!comp_proto_with_proto (method, hsh->key)) - hash_add_attr (hsh, method); - } - return method; -} - -tree -add_instance_method (tree class, tree method) -{ - tree mth; - hash hsh; - - if (!(mth = lookup_method (CLASS_NST_METHODS (class), method))) - { - /* Put method on list in reverse order. */ - TREE_CHAIN (method) = CLASS_NST_METHODS (class); - CLASS_NST_METHODS (class) = method; + { + TREE_CHAIN (method) = CLASS_NST_METHODS (class); + CLASS_NST_METHODS (class) = method; + } } else { - if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE) - error ("duplicate definition of instance method `%s'", - IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); - else - { - /* Check types; if different, complain. */ - if (!comp_proto_with_proto (method, mth)) - error ("duplicate declaration of instance method `%s'", - IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); - } + /* When processing an @interface for a class or category, give hard errors on methods with + identical selectors but differing argument and/or return types. We do not do this for + @implementations, because C/C++ will do it for us (i.e., there will be + duplicate function definition errors). */ + if ((TREE_CODE (class) == CLASS_INTERFACE_TYPE + || TREE_CODE (class) == CATEGORY_INTERFACE_TYPE) + && !comp_proto_with_proto (method, mth)) + error ("duplicate declaration of method `%c%s'", + is_class ? '+' : '-', IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); } - if (!(hsh = hash_lookup (nst_method_hash_list, METHOD_SEL_NAME (method)))) + if (!(hsh = hash_lookup (is_class + ? cls_method_hash_list + : nst_method_hash_list, METHOD_SEL_NAME (method)))) { /* Install on a global chain. */ - hash_enter (nst_method_hash_list, method); + hash_enter (is_class ? cls_method_hash_list : nst_method_hash_list, method); } else { - /* Check types; if different, add to a list. */ - if (!comp_proto_with_proto (method, hsh->key)) - hash_add_attr (hsh, method); + /* Check types against those; if different, add to a list. */ + attr loop; + int already_there = comp_proto_with_proto (method, hsh->key); + for (loop = hsh->list; !already_there && loop; loop = loop->next) + already_there |= comp_proto_with_proto (method, loop->value); + if (!already_there) + hash_add_attr (hsh, method); } return method; } @@ -5567,7 +6322,11 @@ add_category (tree class, tree category) while (cat) { if (CLASS_SUPER_NAME (cat) == CLASS_SUPER_NAME (category)) +#ifdef OBJCPLUS + error ("duplicate interface declaration for category `%s(%s)'", +#else warning ("duplicate interface declaration for category `%s(%s)'", +#endif IDENTIFIER_POINTER (CLASS_NAME (class)), IDENTIFIER_POINTER (CLASS_SUPER_NAME (category))); cat = CLASS_CATEGORY_LIST (cat); @@ -5586,16 +6345,61 @@ tree add_instance_variable (tree class, int public, tree declarator, tree declspecs, tree width) { - tree field_decl, raw_decl; - - raw_decl = build_tree_list (declspecs, declarator); + tree field_decl = grokfield (declarator, declspecs, width); + tree field_type = TREE_TYPE (field_decl); + const char *ivar_name = DECL_NAME (field_decl) + ? IDENTIFIER_POINTER (DECL_NAME (field_decl)) + : "<unnamed>"; + tree raw_decl; - if (CLASS_RAW_IVARS (class)) - chainon (CLASS_RAW_IVARS (class), raw_decl); - else - CLASS_RAW_IVARS (class) = raw_decl; +#ifdef OBJCPLUS + if (TREE_CODE (field_type) == REFERENCE_TYPE) + { + error ("illegal reference type specified for instance variable `%s'", + ivar_name); + /* Return class as is without adding this ivar. */ + return class; + } +#endif - field_decl = grokfield (declarator, declspecs, width); + if (field_type == error_mark_node || !TYPE_SIZE (field_type) + || TYPE_SIZE (field_type) == error_mark_node + /* 'type[0]' is allowed, but 'type[]' is not! */ +#ifdef OBJCPLUS + || (TYPE_SIZE (field_type) == bitsize_zero_node + && !TREE_OPERAND (declarator, 1)) +#endif + ) + { + error ("instance variable `%s' has unknown size", ivar_name); + /* Return class as is without adding this ivar. */ + return class; + } + +#ifdef OBJCPLUS + /* zlaski 2001-Apr-24: C++ classes with non-trivial constructors and/or destructors + cannot be ivars; ditto for classes with vtables. */ + if(IS_AGGR_TYPE (field_type) && (TYPE_NEEDS_CONSTRUCTING (field_type) + || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type) || TYPE_POLYMORPHIC_P (field_type))) + { + const char *type_name = IDENTIFIER_POINTER (OBJC_TYPE_NAME (field_type)); + if(TYPE_POLYMORPHIC_P (field_type)) { + /* vtable pointers are Real Bad(tm), since Obj-C cannot initialize them */ + error ("type `%s' has virtual member functions", type_name); + error ("illegal aggregate type `%s' specified for instance variable `%s'", + type_name, ivar_name); + /* Return class as is without adding this ivar. */ + return class; + } + /* user-defined constructors and destructors are not known to Obj-C and + hence will not be called. This may or may not be a problem. */ + if (TYPE_NEEDS_CONSTRUCTING (field_type)) + warning ("type `%s' has a user-defined constructor", type_name); + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type)) + warning ("type `%s' has a user-defined destructor", type_name); + warning ("C++ constructors and destructors will not be invoked for Objective-C fields"); + } +#endif /* Overload the public attribute, it is not used for FIELD_DECLs. */ switch (public) @@ -5620,11 +6424,9 @@ add_instance_variable (tree class, int public, tree declarator, } - if (CLASS_IVARS (class)) - chainon (CLASS_IVARS (class), field_decl); - else - CLASS_IVARS (class) = field_decl; - + raw_decl = build_tree_list (declspecs, build_tree_list (declarator, width)); + CLASS_RAW_IVARS (class) = chainon (CLASS_RAW_IVARS (class), raw_decl); + CLASS_IVARS (class) = chainon (CLASS_IVARS (class), field_decl); return class; } @@ -5666,10 +6468,10 @@ is_public (tree expr, tree identifier) { if (TREE_STATIC_TEMPLATE (basetype)) { - if (!lookup_interface (TYPE_NAME (basetype))) + if (!lookup_interface (OBJC_TYPE_NAME (basetype))) { error ("cannot find interface declaration for `%s'", - IDENTIFIER_POINTER (TYPE_NAME (basetype))); + IDENTIFIER_POINTER (OBJC_TYPE_NAME (basetype))); return 0; } @@ -5687,9 +6489,20 @@ is_public (tree expr, tree identifier) || (TREE_CODE (objc_implementation_context) == CATEGORY_IMPLEMENTATION_TYPE)) && (CLASS_NAME (objc_implementation_context) - == TYPE_NAME (basetype)))) + == OBJC_TYPE_NAME (basetype)))) return ! is_private (decl); + /* The 2.95.2 compiler sometimes allowed C functions to access + non-@public ivars. We will let this slide for now... */ + if (!objc_method_context) + { + warning ("instance variable `%s' is %s; " + "this will be a hard error in the future", + IDENTIFIER_POINTER (identifier), + TREE_PRIVATE (decl) ? "@private" : "@protected"); + return 1; + } + error ("instance variable `%s' is declared %s", IDENTIFIER_POINTER (identifier), TREE_PRIVATE (decl) ? "private" : "protected"); @@ -5911,6 +6724,12 @@ start_class (enum tree_code code, tree class_name, tree super_name, { tree class, decl; +#ifdef OBJCPLUS + if (current_namespace != global_namespace) { + error ("Objective-C declarations may only appear in global scope"); + } +#endif /* OBJCPLUS */ + if (objc_implementation_context) { warning ("`@end' missing in implementation context"); @@ -5920,17 +6739,19 @@ start_class (enum tree_code code, tree class_name, tree super_name, } class = make_node (code); - TYPE_BINFO (class) = make_tree_vec (BINFO_ELTS); + TYPE_BINFO (class) = make_tree_vec (CLASS_BINFO_ELTS); CLASS_NAME (class) = class_name; CLASS_SUPER_NAME (class) = super_name; CLASS_CLS_METHODS (class) = NULL_TREE; - if (! is_class_name (class_name) && (decl = lookup_name (class_name))) + if (! is_class_name (class_name) + && (decl = lookup_name (class_name))) { error ("`%s' redeclared as different kind of symbol", IDENTIFIER_POINTER (class_name)); - error ("%Jprevious declaration of '%D'", decl, decl); + error ("%Jprevious declaration of '%D'", + decl, decl); } if (code == CLASS_IMPLEMENTATION_TYPE) @@ -5949,17 +6770,6 @@ start_class (enum tree_code code, tree class_name, tree super_name, implemented_classes); } - /* Pre-build the following entities - for speed/convenience. */ - if (!self_id) - self_id = get_identifier ("self"); - if (!ucmd_id) - ucmd_id = get_identifier ("_cmd"); - if (!unused_list) - unused_list - = build_tree_list (get_identifier ("__unused__"), NULL_TREE); - if (!objc_super_template) - objc_super_template = build_super_template (); - /* Reset for multiple classes per file. */ method_slot = 0; @@ -5998,8 +6808,12 @@ start_class (enum tree_code code, tree class_name, tree super_name, else if (code == CLASS_INTERFACE_TYPE) { if (lookup_interface (class_name)) - warning ("duplicate interface declaration for class `%s'", - IDENTIFIER_POINTER (class_name)); +#ifdef OBJCPLUS + error ("duplicate interface declaration for class `%s'", +#else + warning ("duplicate interface declaration for class `%s'", +#endif + IDENTIFIER_POINTER (class_name)); else add_class (class); @@ -6032,17 +6846,6 @@ start_class (enum tree_code code, tree class_name, tree super_name, else if (code == CATEGORY_IMPLEMENTATION_TYPE) { - /* Pre-build the following entities for speed/convenience. */ - if (!self_id) - self_id = get_identifier ("self"); - if (!ucmd_id) - ucmd_id = get_identifier ("_cmd"); - if (!unused_list) - unused_list - = build_tree_list (get_identifier ("__unused__"), NULL_TREE); - if (!objc_super_template) - objc_super_template = build_super_template (); - /* Reset for multiple classes per file. */ method_slot = 0; @@ -6083,7 +6886,7 @@ continue_class (tree class) if (!objc_class_template) build_class_template (); - imp_entry = ggc_alloc (sizeof (struct imp_entry)); + imp_entry = (struct imp_entry *) ggc_alloc (sizeof (struct imp_entry)); imp_entry->next = imp_list; imp_entry->imp_context = class; @@ -6105,11 +6908,10 @@ continue_class (tree class) else if (TREE_CODE (class) == CLASS_INTERFACE_TYPE) { - tree record = xref_tag (RECORD_TYPE, CLASS_NAME (class)); - - if (!TYPE_FIELDS (record)) + if (!CLASS_STATIC_TEMPLATE (class)) { - finish_struct (record, get_class_ivars (class), NULL_TREE); + tree record = start_struct (RECORD_TYPE, CLASS_NAME (class)); + finish_struct (record, get_class_ivars (class, 0), NULL_TREE); CLASS_STATIC_TEMPLATE (class) = record; /* Mark this record as a class template for static typing. */ @@ -6178,7 +6980,7 @@ finish_class (tree class) { tree decl_specs; const char *class_name = IDENTIFIER_POINTER (CLASS_NAME (class)); - char *string = alloca (strlen (class_name) + 3); + char *string = (char *) alloca (strlen (class_name) + 3); /* extern struct objc_object *_<my_name>; */ @@ -6220,6 +7022,12 @@ objc_declare_protocols (tree names) { tree list; +#ifdef OBJCPLUS + if (current_namespace != global_namespace) { + error ("Objective-C declarations may only appear in global scope"); + } +#endif /* OBJCPLUS */ + for (list = names; list; list = TREE_CHAIN (list)) { tree name = TREE_VALUE (list); @@ -6243,6 +7051,12 @@ start_protocol (enum tree_code code, tree name, tree list) { tree protocol; +#ifdef OBJCPLUS + if (current_namespace != global_namespace) { + error ("Objective-C declarations may only appear in global scope"); + } +#endif /* OBJCPLUS */ + /* This is as good a place as any. Need to invoke push_tag_toplevel. */ if (!objc_protocol_template) @@ -6320,10 +7134,10 @@ encode_pointer (tree type, int curtype, int format) if (TREE_CODE (pointer_to) == RECORD_TYPE) { - if (TYPE_NAME (pointer_to) - && TREE_CODE (TYPE_NAME (pointer_to)) == IDENTIFIER_NODE) + if (OBJC_TYPE_NAME (pointer_to) + && TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE) { - const char *name = IDENTIFIER_POINTER (TYPE_NAME (pointer_to)); + const char *name = IDENTIFIER_POINTER (OBJC_TYPE_NAME (pointer_to)); if (strcmp (name, TAG_OBJECT) == 0) /* '@' */ { @@ -6361,8 +7175,15 @@ encode_pointer (tree type, int curtype, int format) else if (TREE_CODE (pointer_to) == INTEGER_TYPE && TYPE_MODE (pointer_to) == QImode) { - obstack_1grow (&util_obstack, '*'); - return; + tree pname = TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE + ? OBJC_TYPE_NAME (pointer_to) + : DECL_NAME (OBJC_TYPE_NAME (pointer_to)); + + if (!flag_next_runtime || strcmp (IDENTIFIER_POINTER (pname), "BOOL")) + { + obstack_1grow (&util_obstack, '*'); + return; + } } /* We have a type that does not get special treatment. */ @@ -6400,117 +7221,68 @@ static void encode_aggregate_within (tree type, int curtype, int format, int left, int right) { - /* The RECORD_TYPE may in fact be a typedef! For purposes - of encoding, we need the real underlying enchilada. */ - if (TYPE_MAIN_VARIANT (type)) - type = TYPE_MAIN_VARIANT (type); - - if (obstack_object_size (&util_obstack) > 0 - && *(obstack_next_free (&util_obstack) - 1) == '^') - { - tree name = TYPE_NAME (type); - - /* we have a reference; this is a NeXT extension. */ - - if (obstack_object_size (&util_obstack) - curtype == 1 - && format == OBJC_ENCODE_INLINE_DEFS) - { - /* Output format of struct for first level only. */ - tree fields = TYPE_FIELDS (type); - - if (name && TREE_CODE (name) == IDENTIFIER_NODE) - { - obstack_1grow (&util_obstack, left); - obstack_grow (&util_obstack, - IDENTIFIER_POINTER (name), - strlen (IDENTIFIER_POINTER (name))); - obstack_1grow (&util_obstack, '='); - } - else - { - obstack_1grow (&util_obstack, left); - obstack_grow (&util_obstack, "?=", 2); - } - - for ( ; fields; fields = TREE_CHAIN (fields)) - encode_field_decl (fields, curtype, format); - - obstack_1grow (&util_obstack, right); - } - - else if (name && TREE_CODE (name) == IDENTIFIER_NODE) - { - obstack_1grow (&util_obstack, left); - obstack_grow (&util_obstack, - IDENTIFIER_POINTER (name), - strlen (IDENTIFIER_POINTER (name))); - obstack_1grow (&util_obstack, right); - } - - else - { - /* We have an untagged structure or a typedef. */ - obstack_1grow (&util_obstack, left); - obstack_1grow (&util_obstack, '?'); - obstack_1grow (&util_obstack, right); - } - } - + tree name; + /* NB: aggregates that are pointed to have slightly different encoding + rules in that you never encode the names of instance variables. */ + int pointed_to + = (obstack_object_size (&util_obstack) > 0 + && *(obstack_next_free (&util_obstack) - 1) == '^'); + int inline_contents + = ((format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables) + && (!pointed_to || obstack_object_size (&util_obstack) - curtype == 1)); + + /* Traverse struct aliases; it is important to get the + original struct and its tag name (if any). */ + type = TYPE_MAIN_VARIANT (type); + name = OBJC_TYPE_NAME (type); + /* Open parenth/bracket. */ + obstack_1grow (&util_obstack, left); + + /* Encode the struct/union tag name, or '?' if a tag was + not provided. Typedef aliases do not qualify. */ + if (name && TREE_CODE (name) == IDENTIFIER_NODE +#ifdef OBJCPLUS + /* Did this struct have a tag? */ + && !TYPE_WAS_ANONYMOUS (type) +#endif + ) + obstack_grow (&util_obstack, + IDENTIFIER_POINTER (name), + strlen (IDENTIFIER_POINTER (name))); else + obstack_1grow (&util_obstack, '?'); + + /* Encode the types (and possibly names) of the inner fields, + if required. */ + if (inline_contents) { - tree name = TYPE_NAME (type); tree fields = TYPE_FIELDS (type); - if (format == OBJC_ENCODE_INLINE_DEFS - || generating_instance_variables) + obstack_1grow (&util_obstack, '='); + for (; fields; fields = TREE_CHAIN (fields)) { - obstack_1grow (&util_obstack, left); - if (name && TREE_CODE (name) == IDENTIFIER_NODE) - obstack_grow (&util_obstack, - IDENTIFIER_POINTER (name), - strlen (IDENTIFIER_POINTER (name))); - else - obstack_1grow (&util_obstack, '?'); - - obstack_1grow (&util_obstack, '='); - - for (; fields; fields = TREE_CHAIN (fields)) +#ifdef OBJCPLUS + /* C++ static members, and things that are not fields at all, + should not appear in the encoding. */ + if (TREE_CODE (fields) != FIELD_DECL || TREE_STATIC (fields)) + continue; +#endif + if (generating_instance_variables && !pointed_to) { - if (generating_instance_variables) - { - tree fname = DECL_NAME (fields); - - obstack_1grow (&util_obstack, '"'); - if (fname && TREE_CODE (fname) == IDENTIFIER_NODE) - { - obstack_grow (&util_obstack, - IDENTIFIER_POINTER (fname), - strlen (IDENTIFIER_POINTER (fname))); - } - - obstack_1grow (&util_obstack, '"'); - } - - encode_field_decl (fields, curtype, format); + tree fname = DECL_NAME (fields); + + obstack_1grow (&util_obstack, '"'); + if (fname && TREE_CODE (fname) == IDENTIFIER_NODE) + obstack_grow (&util_obstack, + IDENTIFIER_POINTER (fname), + strlen (IDENTIFIER_POINTER (fname))); + obstack_1grow (&util_obstack, '"'); } - - obstack_1grow (&util_obstack, right); - } - - else - { - obstack_1grow (&util_obstack, left); - if (name && TREE_CODE (name) == IDENTIFIER_NODE) - obstack_grow (&util_obstack, - IDENTIFIER_POINTER (name), - strlen (IDENTIFIER_POINTER (name))); - else - /* We have an untagged structure or a typedef. */ - obstack_1grow (&util_obstack, '?'); - - obstack_1grow (&util_obstack, right); + encode_field_decl (fields, curtype, format); } } + /* Close parenth/bracket. */ + obstack_1grow (&util_obstack, right); } static void @@ -6522,12 +7294,12 @@ encode_aggregate (tree type, int curtype, int format) { case RECORD_TYPE: { - encode_aggregate_within(type, curtype, format, '{', '}'); + encode_aggregate_within (type, curtype, format, '{', '}'); break; } case UNION_TYPE: { - encode_aggregate_within(type, curtype, format, '(', ')'); + encode_aggregate_within (type, curtype, format, '(', ')'); break; } @@ -6540,18 +7312,11 @@ encode_aggregate (tree type, int curtype, int format) } } -/* Support bitfields. The current version of Objective-C does not support - them. The string will consist of one or more "b:n"'s where n is an - integer describing the width of the bitfield. Currently, classes in - the kit implement a method "-(char *)describeBitfieldStruct:" that - simulates this. If they do not implement this method, the archiver - assumes the bitfield is 16 bits wide (padded if necessary) and packed - according to the GNU compiler. After looking at the "kit", it appears - that all classes currently rely on this default behavior, rather than - hand generating this string (which is tedious). */ +/* Encode a bitfield NeXT-style (i.e., without a bit offset or the underlying + field type. */ static void -encode_bitfield (int width) +encode_next_bitfield (int width) { char buffer[40]; sprintf (buffer, "b%d", width); @@ -6620,6 +7385,9 @@ encode_type (tree type, int curtype, int format) else if (code == VOID_TYPE) obstack_1grow (&util_obstack, 'v'); + else if (code == BOOLEAN_TYPE) + obstack_1grow (&util_obstack, 'B'); + else if (code == ARRAY_TYPE) encode_array (type, curtype, format); @@ -6634,7 +7402,7 @@ encode_type (tree type, int curtype, int format) } static void -encode_complete_bitfield (int position, tree type, int size) +encode_gnu_bitfield (int position, tree type, int size) { enum tree_code code = TREE_CODE (type); char buffer[40]; @@ -6694,27 +7462,29 @@ encode_field_decl (tree field_decl, int curtype, int format) { tree type; +#ifdef OBJCPLUS + /* C++ static members, and things that are not fields at all, + should not appear in the encoding. */ + if (TREE_CODE (field_decl) != FIELD_DECL || TREE_STATIC (field_decl)) + return; +#endif + type = TREE_TYPE (field_decl); - /* If this field is obviously a bitfield, or is a bitfield that has been - clobbered to look like a ordinary integer mode, go ahead and generate - the bitfield typing information. */ - if (flag_next_runtime) + /* Generate the bitfield typing information, if needed. Note the difference + between GNU and NeXT runtimes. */ + if (DECL_BIT_FIELD_TYPE (field_decl)) { - if (DECL_BIT_FIELD_TYPE (field_decl)) - encode_bitfield (tree_low_cst (DECL_SIZE (field_decl), 1)); + int size = tree_low_cst (DECL_SIZE (field_decl), 1); + + if (flag_next_runtime) + encode_next_bitfield (size); else - encode_type (TREE_TYPE (field_decl), curtype, format); + encode_gnu_bitfield (int_bit_position (field_decl), + DECL_BIT_FIELD_TYPE (field_decl), size); } else - { - if (DECL_BIT_FIELD_TYPE (field_decl)) - encode_complete_bitfield (int_bit_position (field_decl), - DECL_BIT_FIELD_TYPE (field_decl), - tree_low_cst (DECL_SIZE (field_decl), 1)); - else - encode_type (TREE_TYPE (field_decl), curtype, format); - } + encode_type (TREE_TYPE (field_decl), curtype, format); } static tree @@ -6728,25 +7498,14 @@ objc_expr_last (tree complex_expr) return complex_expr; } - -/* Transform a method definition into a function definition as follows: - - synthesize the first two arguments, "self" and "_cmd". */ -void -start_method_def (tree method) +static void +synth_self_and_ucmd_args (void) { tree decl_specs; - /* Required to implement _msgSuper. */ - objc_method_context = method; - UOBJC_SUPER_decl = NULL_TREE; - - /* Must be called BEFORE start_function. */ - pushlevel (0); - - /* Generate prototype declarations for arguments..."new-style". */ - - if (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL) + if (objc_method_context + && TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL) decl_specs = build_tree_list (NULL_TREE, uprivate_record); else /* Really a `struct objc_class *'. However, we allow people to @@ -6765,6 +7524,23 @@ start_method_def (tree method) (build_tree_list (decl_specs, build1 (INDIRECT_REF, NULL_TREE, ucmd_id)), unused_list)); +} + +/* Transform a method definition into a function definition as follows: + - synthesize the first two arguments, "self" and "_cmd". */ + +void +start_method_def (tree method) +{ + /* Required to implement _msgSuper. */ + objc_method_context = method; + UOBJC_SUPER_decl = NULL_TREE; + + /* Must be called BEFORE start_function. */ + pushlevel (0); + + /* Generate prototype declarations for arguments..."new-style". */ + synth_self_and_ucmd_args (); /* Generate argument declarations if a keyword_decl. */ if (METHOD_SEL_ARGS (method)) @@ -6785,8 +7561,10 @@ start_method_def (tree method) (build_tree_list (arg_spec, arg_decl), NULL_TREE)); +#ifndef OBJCPLUS /* Unhook: restore the abstract declarator. */ TREE_OPERAND (last_expr, 0) = NULL_TREE; +#endif } else @@ -6820,8 +7598,8 @@ 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, errbuf)); + warning ("%J%s `%c%s'", method, + message, mtype, gen_method_decl (method, errbuf)); } /* Return 1 if METHOD is consistent with PROTO. */ @@ -6843,26 +7621,57 @@ comp_method_with_proto (tree method, tree proto) false); } -/* Return 1 if PROTO1 is consistent with PROTO2. */ +/* Return 1 if TYPE1 is equivalent to TYPE2. */ static int -comp_proto_with_proto (tree proto0, tree proto1) +objc_types_are_equivalent (tree type1, tree type2) { - /* Create a couple of function_template nodes at most once. */ - if (!function1_template) - function1_template = make_node (FUNCTION_TYPE); - if (!function2_template) - function2_template = make_node (FUNCTION_TYPE); + if (type1 == type2) + return 1; + if (TYPE_MAIN_VARIANT (type1) != TYPE_MAIN_VARIANT (type2)) + return 0; + type1 = TYPE_PROTOCOL_LIST (type1); + type2 = TYPE_PROTOCOL_LIST (type2); + if (list_length (type1) == list_length (type2)) + { + for (; type2; type2 = TREE_CHAIN (type2)) + if (!lookup_protocol_in_reflist (type1, TREE_VALUE (type2))) + return 0; + return 1; + } + return 0; +} + +/* Return 1 if PROTO1 is equivalent to PROTO2. */ + +static int +comp_proto_with_proto (tree proto1, tree proto2) +{ + tree type1, type2; - /* Install argument types; normally set by build_function_type. */ - TYPE_ARG_TYPES (function1_template) = get_arg_type_list (proto0, METHOD_REF, 0); - TYPE_ARG_TYPES (function2_template) = get_arg_type_list (proto1, METHOD_REF, 0); + /* The following test is needed in case there are hashing + collisions. */ + if (METHOD_SEL_NAME (proto1) != METHOD_SEL_NAME (proto2)) + return 0; - /* Install return type. */ - TREE_TYPE (function1_template) = groktypename (TREE_TYPE (proto0)); - TREE_TYPE (function2_template) = groktypename (TREE_TYPE (proto1)); + /* Compare return types. */ + type1 = groktypename (TREE_TYPE (proto1)); + type2 = groktypename (TREE_TYPE (proto2)); - return comptypes (function1_template, function2_template, false); + if (!objc_types_are_equivalent (type1, type2)) + return 0; + + /* Compare argument types. */ + for (type1 = get_arg_type_list (proto1, METHOD_REF, 0), + type2 = get_arg_type_list (proto2, METHOD_REF, 0); + type1 && type2; + type1 = TREE_CHAIN (type1), type2 = TREE_CHAIN (type2)) + { + if (!objc_types_are_equivalent (TREE_VALUE (type1), TREE_VALUE (type2))) + return 0; + } + + return (!type1 && !type2); } /* - Generate an identifier for the function. the format is "_n_cls", @@ -6893,14 +7702,20 @@ really_start_method (tree method, tree parmlist) method_slot++; /* Make sure this is big enough for any plausible method label. */ - buf = alloca (50 + strlen (sel_name) + strlen (class_name) - + (cat_name ? strlen (cat_name) : 0)); + buf = (char *) alloca (50 + strlen (sel_name) + strlen (class_name) + + (cat_name ? strlen (cat_name) : 0)); OBJC_GEN_METHOD_LABEL (buf, TREE_CODE (method) == INSTANCE_METHOD_DECL, class_name, cat_name, sel_name, method_slot); method_id = get_identifier (buf); +#ifdef OBJCPLUS + /* Objective-C methods cannot be overloaded, so we don't need + the type encoding appended. It looks bad anyway... */ + push_lang_context (lang_name_c); +#endif + method_decl = build_nt (CALL_EXPR, method_id, parmlist, NULL_TREE); /* Check the declarator portion of the return type for the method. */ @@ -6931,20 +7746,32 @@ really_start_method (tree method, tree parmlist) TREE_VALUE (TREE_TYPE (method)) = NULL_TREE; } +#ifdef OBJCPLUS + /* set self_decl from the first argument...this global is used by + * build_ivar_reference().build_indirect_ref(). + */ + self_decl = DECL_ARGUMENTS (current_function_decl); + + /* snaroff (3/28/96): when compiling with -Wall, this suppresses + * the following: warning:unused parameter `struct objc_selector * _cmd' + */ + TREE_USED (self_decl) = 1; + TREE_USED (TREE_CHAIN (self_decl)) = 1; + /* Ditto for the underlying (static) C function. */ + TREE_USED (current_function_decl) = 1; + pop_lang_context (); +#endif + METHOD_DEFINITION (method) = current_function_decl; /* Check consistency...start_function, pushdecl, duplicate_decls. */ if (implementation_template != objc_implementation_context) { - tree proto; - - if (TREE_CODE (method) == INSTANCE_METHOD_DECL) - proto = lookup_instance_method_static (implementation_template, - METHOD_SEL_NAME (method)); - else - proto = lookup_class_method_static (implementation_template, - METHOD_SEL_NAME (method)); + tree proto + = lookup_method_static (implementation_template, + METHOD_SEL_NAME (method), + TREE_CODE (method) == CLASS_METHOD_DECL); if (proto && ! comp_method_with_proto (method, proto)) { @@ -6972,34 +7799,18 @@ continue_method_def (void) else parmlist = get_parm_info (1); /* place a `void_at_end' */ +#ifndef OBJCPLUS /* Set self_decl from the first argument...this global is used by build_ivar_reference calling build_indirect_ref. */ self_decl = TREE_PURPOSE (parmlist); +#endif /* !OBJCPLUS */ poplevel (0, 0, 0); really_start_method (objc_method_context, parmlist); store_parm_decls (); } -/* Called by the parser, from the `pushlevel' production. */ - -void -add_objc_decls (void) -{ - if (!UOBJC_SUPER_decl) - { - UOBJC_SUPER_decl = start_decl (get_identifier (UTAG_SUPER), - build_tree_list (NULL_TREE, - objc_super_template), - 0, NULL_TREE); - - finish_decl (UOBJC_SUPER_decl, NULL_TREE, NULL_TREE); - - /* This prevents `unused variable' warnings when compiling with -Wall. */ - TREE_USED (UOBJC_SUPER_decl) = 1; - DECL_ARTIFICIAL (UOBJC_SUPER_decl) = 1; - } -} +static void *UOBJC_SUPER_scope = 0; /* _n_Method (id self, SEL sel, ...) { @@ -7014,6 +7825,22 @@ get_super_receiver (void) { tree super_expr, super_expr_list; + if (!UOBJC_SUPER_decl) + { + UOBJC_SUPER_decl = start_decl (get_identifier (TAG_SUPER), + build_tree_list (NULL_TREE, + objc_super_template), + 0, NULL_TREE); + + finish_decl (UOBJC_SUPER_decl, NULL_TREE, NULL_TREE); + + /* This prevents `unused variable' warnings when compiling with -Wall. */ + TREE_USED (UOBJC_SUPER_decl) = 1; + DECL_ARTIFICIAL (UOBJC_SUPER_decl) = 1; + + UOBJC_SUPER_scope = 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); @@ -7049,17 +7876,18 @@ get_super_receiver (void) return error_mark_node; } - if (flag_next_runtime) + if (flag_next_runtime && !flag_zero_link) { super_class = get_class_reference (super_name); if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL) - /* Cast the super class to 'id', since the user may not have - included <objc/objc-class.h>, leaving 'struct objc_class' - an incomplete type. */ + /* If we are in a class method, we must retrieve the + _metaclass_ for the current class, pointed at by + the class's "isa" pointer. The following assumes that + "isa" is the first ivar in a class (which it must be). */ super_class - = build_component_ref (build_indirect_ref - (build_c_cast (id_type, super_class), "->"), - get_identifier ("isa")); + = build_indirect_ref + (build_c_cast (build_pointer_type (objc_class_type), + super_class), "unary *"); } else { @@ -7076,8 +7904,10 @@ get_super_receiver (void) IDENTIFIER_POINTER (super_name)))); } - TREE_TYPE (super_class) = TREE_TYPE (ucls_super_ref); - super_expr = build_modify_expr (super_expr, NOP_EXPR, super_class); + super_expr + = build_modify_expr (super_expr, NOP_EXPR, + build_c_cast (TREE_TYPE (super_expr), + super_class)); } chainon (super_expr_list, build_tree_list (NULL_TREE, super_expr)); @@ -7094,72 +7924,44 @@ get_super_receiver (void) } } -static tree -encode_method_def (tree func_decl) -{ - tree parms; - int stack_size; - HOST_WIDE_INT max_parm_end = 0; - char buffer[40]; - tree result; +/* When exiting a scope, sever links to a 'super' declaration (if any) + therein contained. */ - /* Return type. */ - encode_type (TREE_TYPE (TREE_TYPE (func_decl)), - obstack_object_size (&util_obstack), - OBJC_ENCODE_INLINE_DEFS); - - /* Stack size. */ - for (parms = DECL_ARGUMENTS (func_decl); parms; - parms = TREE_CHAIN (parms)) - { - HOST_WIDE_INT parm_end = (forwarding_offset (parms) - + int_size_in_bytes (TREE_TYPE (parms))); - - if (! offset_is_register && parm_end > max_parm_end) - max_parm_end = parm_end; - } - - stack_size = max_parm_end - OBJC_FORWARDING_MIN_OFFSET; - - sprintf (buffer, "%d", stack_size); - obstack_grow (&util_obstack, buffer, strlen (buffer)); - - /* Argument types. */ - for (parms = DECL_ARGUMENTS (func_decl); parms; - parms = TREE_CHAIN (parms)) - { - /* Type. */ - encode_type (TREE_TYPE (parms), - obstack_object_size (&util_obstack), - OBJC_ENCODE_INLINE_DEFS); - - /* Compute offset. */ - sprintf (buffer, "%d", forwarding_offset (parms)); - - /* Indicate register. */ - if (offset_is_register) - obstack_1grow (&util_obstack, '+'); - - obstack_grow (&util_obstack, buffer, strlen (buffer)); - } - - /* Null terminate string. */ - obstack_1grow (&util_obstack, 0); - result = get_identifier (obstack_finish (&util_obstack)); - obstack_free (&util_obstack, util_firstobj); - return result; +void +objc_clear_super_receiver (void) +{ + if (objc_method_context + && UOBJC_SUPER_scope == get_current_scope ()) { + UOBJC_SUPER_decl = 0; + UOBJC_SUPER_scope = 0; + } } static void objc_expand_function_end (void) { - METHOD_ENCODING (objc_method_context) = encode_method_def (current_function_decl); + /* This routine may also get called for C functions, including those + nested within ObjC methods. In such cases, method encoding is + meaningless. */ + if (objc_method_context == NULL_TREE + || DECL_INITIAL (objc_method_context) != current_function_decl) + return; + + METHOD_ENCODING (objc_method_context) + = encode_method_prototype (objc_method_context); } void finish_method_def (void) { lang_expand_function_end = objc_expand_function_end; + /* We cannot validly inline ObjC methods, at least not without a language + extension to declare that a method need not be dynamically + dispatched, so suppress all thoughts of doing so. */ + DECL_INLINE (current_function_decl) = 0; + DECL_UNINLINABLE (current_function_decl) = 1; + current_function_cannot_inline = "methods cannot be inlined"; + finish_function (); lang_expand_function_end = NULL; @@ -7402,13 +8204,13 @@ gen_declspecs (tree declspecs, char *buf, int raw) strcat (buf, IDENTIFIER_POINTER (aspec)); else if (TREE_CODE (aspec) == RECORD_TYPE) { - if (TYPE_NAME (aspec)) + if (OBJC_TYPE_NAME (aspec)) { tree protocol_list = TYPE_PROTOCOL_LIST (aspec); if (! TREE_STATIC_TEMPLATE (aspec)) strcat (buf, "struct "); - strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (aspec))); + strcat (buf, IDENTIFIER_POINTER (OBJC_TYPE_NAME (aspec))); /* NEW!!! */ if (protocol_list) @@ -7435,11 +8237,11 @@ gen_declspecs (tree declspecs, char *buf, int raw) else if (TREE_CODE (aspec) == UNION_TYPE) { - if (TYPE_NAME (aspec)) + if (OBJC_TYPE_NAME (aspec)) { if (! TREE_STATIC_TEMPLATE (aspec)) strcat (buf, "union "); - strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (aspec))); + strcat (buf, IDENTIFIER_POINTER (OBJC_TYPE_NAME (aspec))); } else strcat (buf, "untagged union"); @@ -7447,11 +8249,11 @@ gen_declspecs (tree declspecs, char *buf, int raw) else if (TREE_CODE (aspec) == ENUMERAL_TYPE) { - if (TYPE_NAME (aspec)) + if (OBJC_TYPE_NAME (aspec)) { if (! TREE_STATIC_TEMPLATE (aspec)) strcat (buf, "enum "); - strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (aspec))); + strcat (buf, IDENTIFIER_POINTER (OBJC_TYPE_NAME (aspec))); } else strcat (buf, "untagged enum"); @@ -7541,14 +8343,14 @@ gen_declspecs (tree declspecs, char *buf, int raw) break; case RECORD_TYPE: - if (TYPE_NAME (declspecs) - && TREE_CODE (TYPE_NAME (declspecs)) == IDENTIFIER_NODE) + if (OBJC_TYPE_NAME (declspecs) + && TREE_CODE (OBJC_TYPE_NAME (declspecs)) == IDENTIFIER_NODE) { tree protocol_list = TYPE_PROTOCOL_LIST (declspecs); if (! TREE_STATIC_TEMPLATE (declspecs)) strcat (buf, "struct "); - strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (declspecs))); + strcat (buf, IDENTIFIER_POINTER (OBJC_TYPE_NAME (declspecs))); if (protocol_list) { @@ -7575,11 +8377,11 @@ gen_declspecs (tree declspecs, char *buf, int raw) break; case UNION_TYPE: - if (TYPE_NAME (declspecs) - && TREE_CODE (TYPE_NAME (declspecs)) == IDENTIFIER_NODE) + if (OBJC_TYPE_NAME (declspecs) + && TREE_CODE (OBJC_TYPE_NAME (declspecs)) == IDENTIFIER_NODE) { strcat (buf, "union "); - strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (declspecs))); + strcat (buf, IDENTIFIER_POINTER (OBJC_TYPE_NAME (declspecs))); strcat (buf, " "); } @@ -7588,11 +8390,11 @@ gen_declspecs (tree declspecs, char *buf, int raw) break; case ENUMERAL_TYPE: - if (TYPE_NAME (declspecs) - && TREE_CODE (TYPE_NAME (declspecs)) == IDENTIFIER_NODE) + if (OBJC_TYPE_NAME (declspecs) + && TREE_CODE (OBJC_TYPE_NAME (declspecs)) == IDENTIFIER_NODE) { strcat (buf, "enum "); - strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (declspecs))); + strcat (buf, IDENTIFIER_POINTER (OBJC_TYPE_NAME (declspecs))); strcat (buf, " "); } @@ -7658,9 +8460,17 @@ gen_declaration_1 (tree atype_or_adecl, char *buf) { tree declspecs; /* "identifier_node", "record_type" */ tree declarator; /* "array_ref", "indirect_ref", "call_expr"... */ + tree width = NULL_TREE; /* for bitfields */ /* We have a "raw", abstract declarator (typename). */ declarator = TREE_VALUE (atype_or_adecl); + /* In the case of raw ivars, the declarator itself is a list, + and contains bitfield widths. */ + if (declarator && TREE_CODE (declarator) == TREE_LIST) + { + width = TREE_VALUE (declarator); + declarator = TREE_PURPOSE (declarator); + } declspecs = TREE_PURPOSE (atype_or_adecl); gen_declspecs (declspecs, buf, 1); @@ -7669,6 +8479,8 @@ gen_declaration_1 (tree atype_or_adecl, char *buf) strcat (buf, " "); strcat (buf, gen_declarator (declarator, declbuf, "")); } + if (width) + sprintf (buf + strlen (buf), ": %lu", TREE_INT_CST_LOW (width)); } else @@ -7812,7 +8624,7 @@ dump_interface (FILE *fp, tree chain) declaration is so long that it doesn't fit in the buffer. The code and all the related functions should be rewritten to avoid using fixed size buffers. */ - char *buf = xmalloc (1024 * 10); + char *buf = (char *) xmalloc (1024 * 10); const char *my_name = IDENTIFIER_POINTER (CLASS_NAME (chain)); tree ivar_decls = CLASS_RAW_IVARS (chain); tree nst_methods = CLASS_NST_METHODS (chain); @@ -7935,7 +8747,7 @@ init_objc (void) gcc_obstack_init (&util_obstack); util_firstobj = (char *) obstack_finish (&util_obstack); - errbuf = xmalloc (BUFSIZE); + errbuf = (char *) xmalloc (BUFSIZE); hash_init (); synth_module_prologue (); } @@ -8009,6 +8821,9 @@ finish_objc (void) if (protocol_chain) generate_protocols (); + if (flag_replace_objc_classes && imp_list) + generate_objc_image_info (); + if (objc_implementation_context || class_names_chain || objc_static_instances || meth_var_names_chain || meth_var_types_chain || sel_ref_chain) { @@ -8046,36 +8861,12 @@ finish_objc (void) selector which has multiple methods. */ for (slot = 0; slot < SIZEHASHTABLE; slot++) - for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next) - if (hsh->list) - { - tree meth = hsh->key; - char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL - ? '-' : '+'); - attr loop; - - warning ("potential selector conflict for method `%s'", - IDENTIFIER_POINTER (METHOD_SEL_NAME (meth))); - warn_with_method ("found", type, meth); - for (loop = hsh->list; loop; loop = loop->next) - warn_with_method ("found", type, loop->value); - } - - for (slot = 0; slot < SIZEHASHTABLE; slot++) - for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next) - if (hsh->list) - { - tree meth = hsh->key; - char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL - ? '-' : '+'); - attr loop; - - warning ("potential selector conflict for method `%s'", - IDENTIFIER_POINTER (METHOD_SEL_NAME (meth))); - warn_with_method ("found", type, meth); - for (loop = hsh->list; loop; loop = loop->next) - warn_with_method ("found", type, loop->value); - } + { + for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next) + check_duplicates (hsh, 0); + for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next) + check_duplicates (hsh, 0); + } } warn_missing_braces = save_warn_missing_braces; @@ -8113,7 +8904,7 @@ static void handle_class_ref (tree chain) { const char *name = IDENTIFIER_POINTER (TREE_VALUE (chain)); - char *string = alloca (strlen (name) + 30); + char *string = (char *) alloca (strlen (name) + 30); tree decl; tree exp; @@ -8162,7 +8953,7 @@ handle_impent (struct imp_entry *impent) const char *const class_name = IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)); - string = alloca (strlen (class_name) + 30); + string = (char *) alloca (strlen (class_name) + 30); sprintf (string, "%sobjc_class_name_%s", (flag_next_runtime ? "." : "__"), class_name); @@ -8174,7 +8965,7 @@ handle_impent (struct imp_entry *impent) const char *const class_super_name = IDENTIFIER_POINTER (CLASS_SUPER_NAME (impent->imp_context)); - string = alloca (strlen (class_name) + string = (char *) alloca (strlen (class_name) + strlen (class_super_name) + 30); /* Do the same for categories. Even though no references to @@ -8211,7 +9002,39 @@ handle_impent (struct imp_entry *impent) } } +/* The Fix-and-Countinue functionality available in Mac OS X 10.3 and + later requires that ObjC translation units participating in F&C be + specially marked. The following routine accomplishes this. */ + +/* static int _OBJC_IMAGE_INFO[2] = { 0, 1 }; */ + +static void +generate_objc_image_info (void) +{ + tree sc_spec, decl, initlist; + + sc_spec = build_tree_list (NULL_TREE, ridpointers[(int) RID_STATIC]); + decl + = start_decl (get_identifier ("_OBJC_IMAGE_INFO"), + tree_cons (NULL_TREE, + build_array_type + (integer_type_node, + build_index_type (build_int_2 (1, 0))), + sc_spec), + 1, + NULL_TREE); + + initlist = build_tree_list (NULL_TREE, build_int_2 (0, 0)); + initlist = tree_cons (NULL_TREE, build_int_2 (1, 0), initlist); + initlist = build_constructor (TREE_TYPE (decl), nreverse (initlist)); + + TREE_USED (decl) = DECL_IGNORED_P (decl) = DECL_ARTIFICIAL (decl) = 1; + TREE_CONSTANT (initlist) = TREE_STATIC (initlist) = 1; + finish_decl (decl, initlist, NULL_TREE); +} + /* Look up ID as an instance variable. */ + tree lookup_objc_ivar (tree id) { diff --git a/gcc/objc/objc-act.h b/gcc/objc/objc-act.h index e167f8e..0dade33 100644 --- a/gcc/objc/objc-act.h +++ b/gcc/objc/objc-act.h @@ -38,16 +38,26 @@ void continue_method_def (void); void finish_method_def (void); tree start_protocol (enum tree_code, tree, tree); void finish_protocol (tree); -void add_objc_decls (void); + +tree objc_build_throw_stmt (tree); +tree objc_build_try_catch_finally_stmt (int, int); +void objc_build_synchronized_prologue (tree); +tree objc_build_synchronized_epilogue (void); +tree objc_build_try_prologue (void); +void objc_build_try_epilogue (int); +void objc_build_catch_stmt (tree); +void objc_build_catch_epilogue (void); +tree objc_build_finally_prologue (void); +tree objc_build_finally_epilogue (void); tree is_ivar (tree, tree); int is_private (tree); int is_public (tree, tree); tree add_instance_variable (tree, int, tree, tree, tree); -tree add_class_method (tree, tree); -tree add_instance_method (tree, tree); +tree add_method (tree, tree, int); tree get_super_receiver (void); -tree get_class_ivars (tree); +void objc_clear_super_receiver (void); +tree get_class_ivars_from_name (tree); tree get_class_reference (tree); tree get_static_reference (tree, tree); tree get_object_reference (tree); @@ -75,6 +85,9 @@ tree build_encode_expr (tree); /* Objective-C structures */ +#define CLASS_BINFO_ELTS 6 +#define PROTOCOL_BINFO_ELTS 2 + /* KEYWORD_DECL */ #define KEYWORD_KEY_NAME(DECL) ((DECL)->decl.name) #define KEYWORD_ARG_NAME(DECL) ((DECL)->decl.arguments) @@ -105,10 +118,12 @@ tree build_encode_expr (tree); #define PROTOCOL_CLS_METHODS(CLASS) ((CLASS)->type.maxval) #define PROTOCOL_FORWARD_DECL(CLASS) TREE_VEC_ELT (TYPE_BINFO (CLASS), 1) #define PROTOCOL_DEFINED(CLASS) TREE_USED (CLASS) -#define TYPE_PROTOCOL_LIST(TYPE) \ - ((!TYPE_CHECK (TYPE)->type.context \ - || TREE_CODE ((TYPE)->type.context) == TRANSLATION_UNIT_DECL) \ - ? NULL_TREE : (TYPE)->type.context) +/* We need to distinguish TYPE_PROTOCOL_LISTs from TYPE_CONTEXTs, both of which + are stored in the same accessor slot. */ +#define TYPE_PROTOCOL_LIST(TYPE) \ + ((TYPE_CHECK (TYPE)->type.context \ + && TREE_CODE ((TYPE)->type.context) == TREE_LIST) \ + ? (TYPE)->type.context : NULL_TREE) #define SET_TYPE_PROTOCOL_LIST(TYPE, P) (TYPE_CHECK (TYPE)->type.context = (P)) /* Set by `continue_class' and checked by `is_public'. */ @@ -116,15 +131,20 @@ tree build_encode_expr (tree); #define TREE_STATIC_TEMPLATE(record_type) (TREE_PUBLIC (record_type)) #define TYPED_OBJECT(type) \ (TREE_CODE (type) == RECORD_TYPE && TREE_STATIC_TEMPLATE (type)) +#define OBJC_TYPE_NAME(type) TYPE_NAME(type) /* Define the Objective-C or Objective-C++ language-specific tree codes. */ #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) SYM, enum objc_tree_code { -#ifdef OBJCPLUS +#if defined (GCC_CP_TREE_H) LAST_BASE_TREE_CODE = LAST_CPLUS_TREE_CODE, -#else +#else +#if defined (GCC_C_TREE_H) LAST_BASE_TREE_CODE = LAST_C_TREE_CODE, +#else + #error You must include <c-tree.h> or <cp/cp-tree.h> before <objc/objc-act.h> +#endif #endif #include "objc-tree.def" LAST_OBJC_TREE_CODE @@ -182,6 +202,8 @@ enum objc_tree_index OCTI_SELF_DECL, OCTI_UMSG_DECL, OCTI_UMSG_SUPER_DECL, + OCTI_UMSG_STRET_DECL, + OCTI_UMSG_SUPER_STRET_DECL, OCTI_GET_CLASS_DECL, OCTI_GET_MCLASS_DECL, OCTI_SUPER_TYPE, @@ -245,6 +267,24 @@ enum objc_tree_index OCTI_CNST_STR_GLOB_ID, OCTI_STRING_CLASS_DECL, OCTI_SUPER_DECL, + OCTI_UMSG_NONNIL_DECL, + OCTI_UMSG_NONNIL_STRET_DECL, + OCTI_STORAGE_CLS, + OCTI_EXCEPTION_EXTRACT_DECL, + OCTI_EXCEPTION_TRY_ENTER_DECL, + OCTI_EXCEPTION_TRY_EXIT_DECL, + OCTI_EXCEPTION_MATCH_DECL, + OCTI_EXCEPTION_THROW_DECL, + OCTI_SYNC_ENTER_DECL, + OCTI_SYNC_EXIT_DECL, + OCTI_SETJMP_DECL, + OCTI_EXCDATA_TEMPL, + OCTI_STACK_EXCEPTION_DATA_DECL, + OCTI_LOCAL_EXCEPTION_DECL, + OCTI_RETHROW_EXCEPTION_DECL, + OCTI_EVAL_ONCE_DECL, + OCTI_EXCEPTION_BLK_STACK, + OCTI_CATCH_TYPE, OCTI_MAX }; @@ -267,6 +307,8 @@ extern GTY(()) tree objc_global_trees[OCTI_MAX]; #define self_decl objc_global_trees[OCTI_SELF_DECL] #define umsg_decl objc_global_trees[OCTI_UMSG_DECL] #define umsg_super_decl objc_global_trees[OCTI_UMSG_SUPER_DECL] +#define umsg_stret_decl objc_global_trees[OCTI_UMSG_STRET_DECL] +#define umsg_super_stret_decl objc_global_trees[OCTI_UMSG_SUPER_STRET_DECL] #define objc_get_class_decl objc_global_trees[OCTI_GET_CLASS_DECL] #define objc_get_meta_class_decl \ objc_global_trees[OCTI_GET_MCLASS_DECL] @@ -285,7 +327,7 @@ extern GTY(()) tree objc_global_trees[OCTI_MAX]; #define IS_PROTOCOL_QUALIFIED_ID(TYPE) \ (IS_ID (TYPE) && TYPE_PROTOCOL_LIST (TYPE)) #define IS_SUPER(TYPE) \ - (super_type && TYPE_MAIN_VARIANT (TYPE) == TYPE_MAIN_VARIANT (super_type)) + (TREE_CODE (TYPE) == POINTER_TYPE && TREE_TYPE (TYPE) == objc_super_template) #define class_chain objc_global_trees[OCTI_CLS_CHAIN] #define alias_chain objc_global_trees[OCTI_ALIAS_CHAIN] @@ -339,6 +381,33 @@ extern GTY(()) tree objc_global_trees[OCTI_MAX]; #define ucls_super_ref objc_global_trees[OCTI_UCLS_SUPER_REF] #define uucls_super_ref objc_global_trees[OCTI_UUCLS_SUPER_REF] +#define umsg_nonnil_decl objc_global_trees[OCTI_UMSG_NONNIL_DECL] +#define umsg_nonnil_stret_decl objc_global_trees[OCTI_UMSG_NONNIL_STRET_DECL] +#define objc_storage_class objc_global_trees[OCTI_STORAGE_CLS] +#define objc_exception_extract_decl \ + objc_global_trees[OCTI_EXCEPTION_EXTRACT_DECL] +#define objc_exception_try_enter_decl \ + objc_global_trees[OCTI_EXCEPTION_TRY_ENTER_DECL] +#define objc_exception_try_exit_decl \ + objc_global_trees[OCTI_EXCEPTION_TRY_EXIT_DECL] +#define objc_exception_match_decl \ + objc_global_trees[OCTI_EXCEPTION_MATCH_DECL] +#define objc_exception_throw_decl \ + objc_global_trees[OCTI_EXCEPTION_THROW_DECL] +#define objc_sync_enter_decl objc_global_trees[OCTI_SYNC_ENTER_DECL] +#define objc_sync_exit_decl objc_global_trees[OCTI_SYNC_EXIT_DECL] +#define objc_exception_data_template \ + objc_global_trees[OCTI_EXCDATA_TEMPL] +#define objc_setjmp_decl objc_global_trees[OCTI_SETJMP_DECL] +#define objc_stack_exception_data \ + objc_global_trees[OCTI_STACK_EXCEPTION_DATA_DECL] +#define objc_caught_exception objc_global_trees[OCTI_LOCAL_EXCEPTION_DECL] +#define objc_rethrow_exception objc_global_trees[OCTI_RETHROW_EXCEPTION_DECL] +#define objc_eval_once objc_global_trees[OCTI_EVAL_ONCE_DECL] +#define objc_exception_block_stack \ + objc_global_trees[OCTI_EXCEPTION_BLK_STACK] +#define objc_catch_type objc_global_trees[OCTI_CATCH_TYPE] + #define objc_method_template objc_global_trees[OCTI_METH_TEMPL] #define objc_ivar_template objc_global_trees[OCTI_IVAR_TEMPL] #define objc_symtab_template objc_global_trees[OCTI_SYMTAB_TEMPL] diff --git a/gcc/objc/objc-tree.def b/gcc/objc/objc-tree.def index 2d0d337..aa2e40f 100644 --- a/gcc/objc/objc-tree.def +++ b/gcc/objc/objc-tree.def @@ -33,3 +33,7 @@ DEFTREECODE (PROTOCOL_INTERFACE_TYPE, "protocol_interface_type", 't', 0) DEFTREECODE (KEYWORD_DECL, "keyword_decl", 'd', 0) DEFTREECODE (INSTANCE_METHOD_DECL, "instance_method_decl", 'd', 0) DEFTREECODE (CLASS_METHOD_DECL, "class_method_decl", 'd', 0) + +/* Objective-C expressions. */ +DEFTREECODE (MESSAGE_SEND_EXPR, "message_send_expr", 'e', 3) +DEFTREECODE (CLASS_REFERENCE_EXPR, "class_reference_expr", 'e', 1) diff --git a/gcc/stub-objc.c b/gcc/stub-objc.c new file mode 100644 index 0000000..4e7a198 --- /dev/null +++ b/gcc/stub-objc.c @@ -0,0 +1,71 @@ +/* Stub functions for Objective-C and Objective-C++ routines + that are called from within the C and C++ front-ends, + respectively. + Copyright (C) 1991, 1995, 1997, 1998, + 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + +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) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "c-common.h" + +tree +lookup_interface (tree arg ATTRIBUTE_UNUSED) +{ + return 0; +} + +tree +is_class_name (tree arg ATTRIBUTE_UNUSED) +{ + return 0; +} + +tree +objc_is_object_ptr (tree arg ATTRIBUTE_UNUSED) +{ + return 0; +} + +tree +lookup_objc_ivar (tree arg ATTRIBUTE_UNUSED) +{ + return 0; +} + +void +objc_check_decl (tree decl ATTRIBUTE_UNUSED) +{ +} + +int +objc_comptypes (tree lhs ATTRIBUTE_UNUSED, tree rhs ATTRIBUTE_UNUSED, + int reflexive ATTRIBUTE_UNUSED) +{ + return -1; +} + +tree +objc_message_selector (void) +{ + return 0; +} + diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c1142f0..dd4c187 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,31 @@ +2003-09-24 Ziemowit Laski <zlaski@apple.com> + + MERGE OF objc-improvements-branch into MAINLINE: + * lib/objc.exp (objc_target_compile): Do not point at libobjc headers + if libobjc has not been built. + * objc/execute/IMP.m, objc/execute/_cmd.m, objc/execute/bf-common.h, + objc/execute/bycopy-3.m, objc/execute/class-{1-14}.m, objc/execute/class-self-2.m, + objc/execute/many_args_method.m, objc/execute/nested-3.m, objc/execute/np-2.m, + objc/execute/object_is_class.m, objc/execute/object_is_meta_class.m, + objc/execute/redefining_self.m, objc/execute/root_methods.m, + objc/execute/static-{1-2}.m, objc/execute/string-{1-4}.m, objc/execute/va_method.m, + objc.dg/comp-types-4.m, objc.dg/headers.m, objc.dg/special/unclaimed-category-1.h, + objc.dg/special/unclaimed-category-1.m: Make usable with NeXT as well as GNU runtime. + * execute/next_mapping.h: New header, for GNU->NeXT impedance matching. + * execute/cascading-1.m, execute/function-message-1.m, objc.dg/anon-1.m, + objc.dg/bitfield-{3-4}.m, objc.dg/call-super-{1-3}.m, objc.dg/category-1.m, + objc.dg/const-str-{3-6}.m, objc.dg/encode-{1-4}.m, objc.dg/func-ptr-1.m, + objc.dg/gnu-runtime-1.m, objc.dg/image-info.m, objc.dg/method-{3-12}.m, + objc.dg/missing-proto-{1-3}.m, objc.dg/nested-func-1.m, objc.dg/proto-lossage-2.m, + objc.dg/proto-qual-1.m, objc.dg/sizeof-1.m, objc.dg/static-1.m, objc.dg/symtab-1.m, + objc.dg/try-catch-{1-4}.m, objc.dg/type-size-{1-2}.m, objc.dg/zero-link-{1-2}.m: + New test cases. + * objc.dg/bitfield-2.m: Run only on Darwin. + * objc.dg/class-2.m, objc.dg/comp-types-1.m, objc.dg/desig-init-1.m, + objc.dg/method-{1-2}.m, objc.dg/proto-hier-1.m, objc.dg/proto-lossage-1.m: + Adjust for message wording changes. + * objc.dg/const-str-1.m: Fix constant string layout. + 2003-09-24 Alexandre Oliva <aoliva@redhat.com> * gcc.dg/cpp/Wunknown-pragmas-1.c: New test. diff --git a/gcc/testsuite/lib/objc.exp b/gcc/testsuite/lib/objc.exp index 9e7c445..1817c70 100644 --- a/gcc/testsuite/lib/objc.exp +++ b/gcc/testsuite/lib/objc.exp @@ -168,13 +168,15 @@ proc objc_target_compile { source dest type options } { set options [concat "additional_flags=$TOOL_OPTIONS" $options]; } - # Point to the ObjC headers in libobjc. - set objc_include_dir "${srcdir}/../../libobjc" - lappend options "additional_flags=-I${objc_include_dir}" + # If we have built libobjc along with the compiler (which usually + # _is not_ the case on Mac OS X systems), point the test harness + # at it (and associated headers). set objcpath "[get_multilibs]" set libobjc_dir [lookfor_file ${objcpath} libobjc/.libs/libobjc.a] if { $libobjc_dir != "" } { + set objc_include_dir "${srcdir}/../../libobjc" + lappend options "additional_flags=-I${objc_include_dir}" set libobjc_dir [file dirname ${libobjc_dir}] set objc_link_flags "-L${libobjc_dir}" lappend options "additional_flags=${objc_link_flags}" diff --git a/gcc/testsuite/objc.dg/anon-1.m b/gcc/testsuite/objc.dg/anon-1.m new file mode 100644 index 0000000..5f10f7d --- /dev/null +++ b/gcc/testsuite/objc.dg/anon-1.m @@ -0,0 +1,14 @@ +/* Test for graceful handling of anonymous ivars. */ +/* { dg-do compile } */ + +@interface Foo { + unsigned char : 1; + int e: 3; + signed: 2; + float f; +} +@end + +@implementation Foo +@end + diff --git a/gcc/testsuite/objc.dg/bitfield-2.m b/gcc/testsuite/objc.dg/bitfield-2.m index 0a401dd..83b3174 100644 --- a/gcc/testsuite/objc.dg/bitfield-2.m +++ b/gcc/testsuite/objc.dg/bitfield-2.m @@ -2,7 +2,7 @@ the NeXT runtime is used. */ /* Contributed by Ziemowit Laski <zlaski@apple.com>. */ /* { dg-options "-fnext-runtime -fsigned-char" } */ -/* { dg-do run } */ +/* { dg-do run { target *-*-darwin* } } */ struct objc_object { struct objc_class *class_pointer; } *id; diff --git a/gcc/testsuite/objc.dg/bitfield-3.m b/gcc/testsuite/objc.dg/bitfield-3.m new file mode 100644 index 0000000..f427a30 --- /dev/null +++ b/gcc/testsuite/objc.dg/bitfield-3.m @@ -0,0 +1,50 @@ +/* Check if the @defs() construct preserves the correct + layout of bitfields. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-lobjc -Wpadded" } */ +/* { dg-do run } */ + +#include <objc/objc.h> +#include <objc/Object.h> + +extern void abort(void); +extern int strcmp(const char *str1, const char *str2); +#define CHECK_IF(expr) if(!(expr)) abort() + +enum Enum { one, two, three, four }; + +@interface Base: Object { + unsigned a: 2; + int b: 3; + enum Enum c: 4; + unsigned d: 5; +} /* { dg-warning "padding struct size to alignment boundary" } */ +@end + +@interface Derived: Base { + signed e: 5; + int f: 4; + enum Enum g: 3; +} /* { dg-warning "padding struct size to alignment boundary" } */ +@end + +/* Note that the semicolon after @defs(...) is optional. */ + +typedef struct { @defs(Base) } Base_t; /* { dg-warning "padding struct size to alignment boundary" } */ +typedef struct { @defs(Derived); } Derived_t; /* { dg-warning "padding struct size to alignment boundary" } */ + +int main(void) +{ + CHECK_IF(sizeof(Base_t) == sizeof(Base)); + CHECK_IF(sizeof(Derived_t) == sizeof(Derived)); + +#ifdef __NEXT_RUNTIME__ + CHECK_IF(!strcmp(@encode(Base), "{Base=#b2b3b4b5}")); + CHECK_IF(!strcmp(@encode(Derived), "{Derived=#b2b3b4b5b5b4b3}")); + + CHECK_IF(!strcmp(@encode(Base_t), "{?=#b2b3b4b5}")); + CHECK_IF(!strcmp(@encode(Derived_t), "{?=#b2b3b4b5b5b4b3}")); +#endif /* __NEXT_RUNTIME__ */ + + return 0; +} diff --git a/gcc/testsuite/objc.dg/bitfield-4.m b/gcc/testsuite/objc.dg/bitfield-4.m new file mode 100644 index 0000000..858bac2 --- /dev/null +++ b/gcc/testsuite/objc.dg/bitfield-4.m @@ -0,0 +1,29 @@ +/* Make sure that bitfield types are printed correctly, and that ivar redeclaration + (@interface vs. @implementation) checks take the bitfield width into account. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do compile } */ + +@interface Base { + int i; +} +@end + +@interface WithBitfields: Base { + void *isa; + unsigned a: 3; + signed b: 4; + int c: 5; +} +@end + +@implementation WithBitfields { + char *isa; /* { dg-error "conflicting instance variable type .char \\*isa." } */ + /* { dg-error "previous declaration of .void \\*isa." "" { target *-*-* } 12 } */ + unsigned a: 5; /* { dg-error "conflicting instance variable type .unsigned a: 5." } */ + /* { dg-error "previous declaration of .unsigned a: 3." "" { target *-*-* } 13 } */ + signed b: 4; /* This one is fine. */ + int c: 3; /* { dg-error "conflicting instance variable type .int c: 3." } */ + /* { dg-error "previous declaration of .int c: 5." "" { target *-*-* } 15 } */ +} +@end + diff --git a/gcc/testsuite/objc.dg/call-super-1.m b/gcc/testsuite/objc.dg/call-super-1.m new file mode 100644 index 0000000..19e0d49 --- /dev/null +++ b/gcc/testsuite/objc.dg/call-super-1.m @@ -0,0 +1,76 @@ +/* Check if objc_super stack variables are created correctly (and + not clobbered by other values). */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-std=c99 -lobjc" } */ +/* { dg-do run } */ + +#include <objc/objc.h> +#include <objc/Object.h> + +extern void abort(void); + +#define CHECK_IF(expr) if(!(expr)) abort(); + +typedef struct _Point { + float x; + float y; +} Point; + +Point MakePoint ( float x , float y ) { + Point p; + p.x = x; + p.y = y; + return p; +} + +@interface Base: Object +- ( void ) translateOriginToPoint : ( Point ) translation ; +@end + +@interface Derived : Base +- ( void ) scrollToPoint : ( Point ) newOrigin ; +- ( void ) translateOriginToPoint : ( Point ) translation ; +@end + +int blort; +float result; + +@implementation Base +- ( void ) translateOriginToPoint : ( Point ) translation { + result = translation.x + translation.y; +} +@end + +@implementation Derived +- ( void ) scrollToPoint : ( Point ) newOrigin { + float transDeltaX =newOrigin.x, transDeltaY =newOrigin.y ; + Point w; + if ( ! blort ) { + w.x = transDeltaX ; w.y = transDeltaY ; + [ super translateOriginToPoint : w ] ; + return; + } + [ super translateOriginToPoint : MakePoint ( transDeltaX , transDeltaY ) ] ; + return; +} +- (void) translateOriginToPoint : ( Point ) translation { + /* This should never be called. */ + CHECK_IF(0); +} +@end + +int main(void) { + Derived *v = [Derived new]; + float r0 = 1.5 + 1.5; + blort = 1; + [v scrollToPoint: MakePoint(1.5, 1.5)]; + CHECK_IF(result == r0); + blort = 0; + [v scrollToPoint: MakePoint(1.5, 1.5)]; + CHECK_IF(result == r0); + blort = 1; + [v scrollToPoint: MakePoint(1.5, 1.5)]; + CHECK_IF(result == r0); + [v free]; + return 0; +} diff --git a/gcc/testsuite/objc.dg/call-super-2.m b/gcc/testsuite/objc.dg/call-super-2.m new file mode 100644 index 0000000..cd7db41 --- /dev/null +++ b/gcc/testsuite/objc.dg/call-super-2.m @@ -0,0 +1,139 @@ +/* Check if casting 'self' or 'super' affects message lookup in the + correct way. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +#include <objc/objc.h> +#include <objc/Object.h> + +#ifdef __NEXT_RUNTIME__ +#define OBJC_GETCLASS objc_getClass +#else +#define OBJC_GETCLASS objc_get_class +#endif + +@protocol Func ++ (int) class_func0; +- (int) instance_func0; +@end + +@interface Derived: Object ++ (int) class_func1; ++ (int) class_func2; ++ (int) class_func3; ++ (int) class_func4; ++ (int) class_func5; ++ (int) class_func6; ++ (int) class_func7; +- (int) instance_func1; +- (int) instance_func2; +- (int) instance_func3; +- (int) instance_func4; +- (int) instance_func5; +- (int) instance_func6; +- (int) instance_func7; +@end + +@interface Derived (Categ) ++ (int) categ_class_func1; ++ (int) categ_class_func2; +- (int) categ_instance_func1; +- (int) categ_instance_func2; +@end + +@implementation Derived ++ (int) class_func1 +{ + int i = (int)[self class_func0]; /* { dg-warning ".Derived. may not respond to .\\+class_func0." } */ + /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 47 } */ + /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 47 } */ + /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 47 } */ + return i + (int)[super class_func0]; /* { dg-warning ".Object. may not respond to .\\+class_func0." } */ +} ++ (int) class_func2 +{ + int i = [(id <Func>)self class_func0]; + return i + [(id <Func>)super class_func0]; +} ++ (int) class_func3 +{ + return [(Object <Func> *)super class_func0]; +} ++ (int) class_func4 +{ + return [(Derived <Func> *)super class_func0]; +} ++ (int) class_func5 +{ + int i = (int)[Derived class_func0]; /* { dg-warning ".Derived. may not respond to .\\+class_func0." } */ + return i + (int)[Object class_func0]; /* { dg-warning ".Object. may not respond to .\\+class_func0." } */ +} ++ (int) class_func6 +{ + return (int)[OBJC_GETCLASS("Object") class_func1]; /* { dg-warning ".Object. may not respond to .\\+class_func1." } */ +} ++ (int) class_func7 +{ + return [OBJC_GETCLASS("Derived") class_func1]; +} +- (int) instance_func1 +{ + int i = (int)[self instance_func0]; /* { dg-warning ".Derived. may not respond to .\\-instance_func0." } */ + return i + (int)[super instance_func0]; /* { dg-warning ".Object. may not respond to .\\-instance_func0." } */ +} +- (int) instance_func2 +{ + return [(id <Func>)super instance_func0]; +} +- (int) instance_func3 +{ + return [(Object <Func> *)super instance_func0]; +} +- (int) instance_func4 +{ + return [(Derived <Func> *)super instance_func0]; +} +- (int) instance_func5 +{ + int i = (int)[Derived instance_func1]; /* { dg-warning ".Derived. may not respond to .\\+instance_func1." } */ + return i + (int)[Object instance_func1]; /* { dg-warning ".Object. may not respond to .\\+instance_func1." } */ +} +- (int) instance_func6 +{ + return (int)[OBJC_GETCLASS("Object") class_func1]; /* { dg-warning ".Object. may not respond to .\\+class_func1." } */ +} +- (int) instance_func7 +{ + return [OBJC_GETCLASS("Derived") class_func1]; +} +@end + +@implementation Derived (Categ) ++ (int) categ_class_func1 +{ + int i = (int)[self class_func0]; /* { dg-warning ".Derived. may not respond to .\\+class_func0." } */ + i += [self class_func1]; + i += [self categ_class_func2]; + i += (int)[self categ_instance_func1]; /* { dg-warning ".Derived. may not respond to .\\+categ_instance_func1." } */ + return i + (int)[super class_func0]; /* { dg-warning ".Object. may not respond to .\\+class_func0." } */ +} ++ (int) categ_class_func2 +{ + int i = [(id <Func>)self class_func0]; + return i + [(id <Func>)super class_func0]; +} +- (int) categ_instance_func1 +{ + int i = (int)[self instance_func0]; /* { dg-warning ".Derived. may not respond to .\\-instance_func0." } */ + i += [(Derived <Func> *)self categ_instance_func2]; + i += (int)[(Object <Func> *)self categ_instance_func2]; /* { dg-warning ".Object. may not respond to .\\-categ_instance_func2." } */ + /* { dg-warning ".\\-categ_instance_func2. not implemented by protocol" "" { target *-*-* } 129 } */ + i += (int)[(id <Func>)self categ_instance_func2]; /* { dg-warning ".\\-categ_instance_func2. not implemented by protocol" } */ + i += [(id)self categ_instance_func2]; + return i + (int)[super instance_func0]; /* { dg-warning ".Object. may not respond to .\\-instance_func0." } */ +} +- (int) categ_instance_func2 +{ + return [(id <Func>)super instance_func0]; +} +@end diff --git a/gcc/testsuite/objc.dg/call-super-3.m b/gcc/testsuite/objc.dg/call-super-3.m new file mode 100644 index 0000000..05b6233 --- /dev/null +++ b/gcc/testsuite/objc.dg/call-super-3.m @@ -0,0 +1,54 @@ +/* Check if sending messages to super does not interfere with sending messages + to classes. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do run } */ +/* { dg-options "-lobjc" } */ + +#include <objc/Object.h> + +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort() + +@interface Base: Object ++ (int) class_func1; +- (int) instance_func1; +@end + +@interface Derived: Base ++ (int) class_func1; +@end + +@interface Derived (Categ) +- (int) instance_func1; +@end + +@implementation Base ++ (int) class_func1 { return 234; } +- (int) instance_func1 { return 345; } +@end + +@implementation Derived ++ (int) class_func1 { + int i = [super class_func1]; + i += [Base class_func1]; + return i; +} +@end + +@implementation Derived (Categ) +- (int) instance_func1 { + int i = [super instance_func1]; + i += [Base class_func1]; /* { dg-bogus "invalid receiver type" } */ + return i; +} +@end + +int main(void) { + Base *base = [[Base alloc] init]; /* { dg-bogus "invalid receiver type" } */ + Derived *derived = [[Derived alloc] init]; + CHECK_IF([Base class_func1] == 234); /* { dg-bogus "invalid receiver type" } */ + CHECK_IF([Derived class_func1] == 234 + 234); + CHECK_IF([base instance_func1] == 345); + CHECK_IF([derived instance_func1] == 234 + 345); + return 0; +} diff --git a/gcc/testsuite/objc.dg/category-1.m b/gcc/testsuite/objc.dg/category-1.m new file mode 100644 index 0000000..1d29e37 --- /dev/null +++ b/gcc/testsuite/objc.dg/category-1.m @@ -0,0 +1,43 @@ +/* Test class methods inside categories. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-lobjc" } */ +/* { dg-do run } */ + +#include <objc/Object.h> + +#ifdef __NEXT_RUNTIME__ +#define SUPERCLASS superclass +#else +#define SUPERCLASS superClass +#endif + +extern int strcmp(const char *s1, const char *s2); +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort() + +@interface MyObject: Object ++ (Class)whatever1; +@end + +@implementation MyObject ++ (Class)whatever1 { return [super SUPERCLASS]; } +@end + +@interface MyObject (ThisWontCompile) ++(Class)whatever2; +@end + +@implementation MyObject (ThisWontCompile) ++(Class)whatever2 { return [super SUPERCLASS]; } +@end + +int main (int argc, const char * argv[]) +{ + Class w1 = [MyObject whatever1]; + Class w2 = [MyObject whatever2]; + + CHECK_IF(!strcmp(w1->name, "Object")); + CHECK_IF(!strcmp(w2->name, "Object")); + return 0; +} + diff --git a/gcc/testsuite/objc.dg/class-2.m b/gcc/testsuite/objc.dg/class-2.m index a4514f9..b98d117 100644 --- a/gcc/testsuite/objc.dg/class-2.m +++ b/gcc/testsuite/objc.dg/class-2.m @@ -10,6 +10,5 @@ @interface class1 : supclass1 @end -@implementation class1 : supclass2 -@end /* { dg-error "conflicting super class name" } */ -/* { dg-error "previous declaration" "" { target *-*-* } 14 } */ +@implementation class1 : supclass2 /* { dg-error "conflicting super class name" } */ +@end /* { dg-error "previous declaration" "" { target *-*-* } 13 } */ diff --git a/gcc/testsuite/objc.dg/comp-types-1.m b/gcc/testsuite/objc.dg/comp-types-1.m index 7494386..310b226 100644 --- a/gcc/testsuite/objc.dg/comp-types-1.m +++ b/gcc/testsuite/objc.dg/comp-types-1.m @@ -41,7 +41,7 @@ int main() MyProtocol), but not from an 'id' or from a 'MyOtherClass *' (which implements MyProtocol). */ obj_p = obj; /* Ok */ - obj_p = obj_c; /* { dg-warning "does not implement" } */ /*FIXME: Duplicated*/ + obj_p = obj_c; /* { dg-warning "does not implement" } */ obj_p = obj_cp; /* Ok */ obj_p = obj_C; /* { dg-warning "incompatible pointer type" } */ diff --git a/gcc/testsuite/objc.dg/comp-types-4.m b/gcc/testsuite/objc.dg/comp-types-4.m index e077804..f15390a 100644 --- a/gcc/testsuite/objc.dg/comp-types-4.m +++ b/gcc/testsuite/objc.dg/comp-types-4.m @@ -3,6 +3,11 @@ /* { dg-do compile } */ #include <objc/objc.h> +/* The NeXT runtime headers do not define NULL. */ +#ifndef NULL +#define NULL ((void *)0) +#endif + @protocol MyProtocol - (void) method; @end diff --git a/gcc/testsuite/objc.dg/const-str-1.m b/gcc/testsuite/objc.dg/const-str-1.m index 145c1b3..e4cac2e 100644 --- a/gcc/testsuite/objc.dg/const-str-1.m +++ b/gcc/testsuite/objc.dg/const-str-1.m @@ -2,12 +2,21 @@ /* { dg-do compile } */ /* { dg-options "-fgnu-runtime" } */ +#ifdef __cplusplus +extern void baz(...); +#endif + void foo() { baz(@"hiya"); /* { dg-error "annot find interface declaration" } */ } @interface NXConstantString +{ + void *isa; + char *str; + int len; +} @end void bar() diff --git a/gcc/testsuite/objc.dg/const-str-3.m b/gcc/testsuite/objc.dg/const-str-3.m new file mode 100644 index 0000000..edc03ff --- /dev/null +++ b/gcc/testsuite/objc.dg/const-str-3.m @@ -0,0 +1,46 @@ +/* Test the -fconstant-string-class=Foo option under the NeXT + runtime. */ +/* Developed by Markus Hitter <mah@jump-ing.de>. */ + +/* { dg-options "-fnext-runtime -fconstant-string-class=Foo -lobjc" } */ +/* { dg-do run { target *-*-darwin* } } */ + +#include <stdio.h> +#include <objc/objc.h> +#include <objc/Object.h> + +@interface Foo: Object { + char *cString; + unsigned int len; +} +- (char *)customString; +@end + +struct objc_class _FooClassReference; + +@implementation Foo : Object +- (char *)customString { + return cString; +} +@end + +int main () { + Foo *string = @"bla"; + Foo *string2 = @"bla"; + + if(string != string2) + abort(); + printf("Strings are being uniqued properly\n"); + + /* This memcpy has to be done before the first message is sent to a + constant string object. Can't be moved to +initialize since _that_ + is already a message. */ + + memcpy(&_FooClassReference, objc_getClass("Foo"), sizeof(_FooClassReference)); + if (strcmp ([string customString], "bla")) { + abort (); + } + + printf([@"This is a working constant string object\n" customString]); + return 0; +} diff --git a/gcc/testsuite/objc.dg/const-str-4.m b/gcc/testsuite/objc.dg/const-str-4.m new file mode 100644 index 0000000..c178bfc --- /dev/null +++ b/gcc/testsuite/objc.dg/const-str-4.m @@ -0,0 +1,31 @@ +/* Ensure that the preprocessor handles ObjC string constants gracefully. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ +/* { dg-options "-fnext-runtime -fconstant-string-class=MyString -lobjc" } */ +/* { dg-do run { target *-*-darwin* } } */ + +extern void abort(void); + +@interface MyString +{ + void *isa; + char *str; + int len; +} +@end + +#define kMyStringMacro1 "My String" +#define kMyStringMacro2 @"My String" + +void *_MyStringClassReference; + +@implementation MyString +@end + +int main(void) { + MyString* aString1 = @kMyStringMacro1; + MyString* aString2 = kMyStringMacro2; + if(aString1 != aString2) { + abort(); + } + return 0; +} diff --git a/gcc/testsuite/objc.dg/const-str-5.m b/gcc/testsuite/objc.dg/const-str-5.m new file mode 100644 index 0000000..186edcf --- /dev/null +++ b/gcc/testsuite/objc.dg/const-str-5.m @@ -0,0 +1,27 @@ +/* Positive test case for constant string layout. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-options "-fconstant-string-class=MyConstantString" } */ +/* { dg-do compile } */ + +@interface MyBase { + const char *p; +} +@end + +@interface MyConstantString: MyBase { + union { + void *u; + unsigned char *c; + } _contents; + unsigned int _count; +} +@end + +/* The NeXT runtime initializes the 'isa' pointer of string constants at + compile time. */ +#ifdef __NEXT_RUNTIME__ +extern void *_MyConstantStringClassReference; +#endif + +MyConstantString *str = @"Hello"; diff --git a/gcc/testsuite/objc.dg/const-str-6.m b/gcc/testsuite/objc.dg/const-str-6.m new file mode 100644 index 0000000..a7cbbf7 --- /dev/null +++ b/gcc/testsuite/objc.dg/const-str-6.m @@ -0,0 +1,27 @@ +/* Negative test case for constant string layout. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-options "-fconstant-string-class=MyConstantString" } */ +/* { dg-do compile } */ + +@interface MyBase { + char p; +} +@end + +@interface MyConstantString: MyBase { + union { + void *u; + unsigned char *c; + } _contents; + char _count; +} +@end + +/* The NeXT runtime initializes the 'isa' pointer of string constants at + compile time. */ +#ifdef __NEXT_RUNTIME__ +extern void *_MyConstantStringClassReference; +#endif + +MyConstantString *str = @"Hello"; /* { dg-error "interface .MyConstantString. does not have valid constant string layout" } */ diff --git a/gcc/testsuite/objc.dg/desig-init-1.m b/gcc/testsuite/objc.dg/desig-init-1.m index 72fe833..44abe44 100644 --- a/gcc/testsuite/objc.dg/desig-init-1.m +++ b/gcc/testsuite/objc.dg/desig-init-1.m @@ -22,7 +22,10 @@ 0, [Cls meth1], [2 + 1] = 3, - [2 * 2 ... 5] = [0 meth2], /* { dg-warning "invalid receiver type" } */ + [2 * 2 ... 5] = (int)[0 meth2], /* { dg-warning "invalid receiver type" } */ + /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 25 } */ + /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 25 } */ + /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 25 } */ [2] [Cls meth2] }; diff --git a/gcc/testsuite/objc.dg/encode-1.m b/gcc/testsuite/objc.dg/encode-1.m new file mode 100644 index 0000000..868c325 --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-1.m @@ -0,0 +1,25 @@ +/* Test if the Objective-C @encode machinery distinguishes between + 'BOOL *' (which should be encoded as a pointer to BOOL) and 'char *' (which + should be encoded as '*'). This is somewhat tricky wrt the NeXT runtime, + where we have 'typedef char BOOL'. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-fnext-runtime -lobjc" } */ +/* { dg-do run } */ + +#include <string.h> +#include <stdlib.h> +#include <objc/objc.h> + +int main(void) { + const char *BOOL_ptr = @encode(BOOL *); + const char *BOOL_ = @encode(BOOL); + const char *char_ptr = @encode(char *); + + if(*BOOL_ptr != '^' || strcmp(BOOL_ptr + 1, BOOL_)) + abort(); + + if(strcmp(char_ptr, "*")) + abort(); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/encode-2.m b/gcc/testsuite/objc.dg/encode-2.m new file mode 100644 index 0000000..ebfd8d3 --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-2.m @@ -0,0 +1,97 @@ +/* Test Objective-C method encodings. */ + +/* The _encoded_ parameter offsets for Objective-C methods are + computed inductively as follows: + - The first paramter (self) has offset 0; + - The k-th parameter (k > 1) has offset equal to the + sum of: + - the offset of the k-1-st paramter + - the int-promoted size of the k-1-st parameter. + + Note that the encoded offsets need not correspond + to the actual placement of parameters (relative to 'self') + on the stack! Your target's ABI may have very different + opinions on the matter. */ + +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do run } */ + +#include <objc/objc.h> +#include <objc/Object.h> + +#ifdef __NEXT_RUNTIME__ +#define METHOD Method +#define OBJC_GETCLASS objc_getClass +#define CLASS_GETINSTANCEMETHOD class_getInstanceMethod +#else +#include <objc/objc-api.h> +#define METHOD Method_t +#define OBJC_GETCLASS objc_get_class +#define CLASS_GETINSTANCEMETHOD class_get_instance_method +#endif + +extern int sscanf(const char *str, const char *format, ...); +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort() + +@interface Foo: Object +typedef struct { float x, y; } XXPoint; +typedef struct { float width, height; } XXSize; +typedef struct _XXRect { XXPoint origin; XXSize size; } XXRect; +-(id)setRect:(XXRect)r withInt:(int)i; +-(void) char:(char)c float:(float)f double:(double)d long:(long)l; +@end + +XXRect my_rect; +unsigned offs1, offs2, offs3, offs4, offs5, offs6, offs7; + +@implementation Foo +-(id)setRect:(XXRect)r withInt:(int)i { + unsigned offs = sizeof(self); + CHECK_IF(offs == offs3); + offs += sizeof(_cmd); + CHECK_IF(offs == offs4); + offs += sizeof(r); + CHECK_IF(offs == offs5); + offs += sizeof(i); + CHECK_IF(offs == offs1); + return nil; +} +-(void) char:(char)c float:(float)f double:(double)d long:(long)l { + unsigned offs = sizeof(self); + CHECK_IF(offs == offs3); + offs += sizeof(_cmd); + CHECK_IF(offs == offs4); + offs += sizeof((int)c); + CHECK_IF(offs == offs5); + offs += sizeof(f); + CHECK_IF(offs == offs6); + offs += sizeof(d); + CHECK_IF(offs == offs7); + offs += sizeof(l); + CHECK_IF(offs == offs1); +} +@end + + +int main(void) { + Foo *foo = [[Foo alloc] init]; + Class fooClass = OBJC_GETCLASS("Foo"); + METHOD meth; + + meth = CLASS_GETINSTANCEMETHOD(fooClass, @selector(setRect:withInt:)); + offs2 = 9999; + sscanf(meth->method_types, "@%u@%u:%u{_XXRect={?=ff}{?=ff}}%ui%u", &offs1, &offs2, &offs3, + &offs4, &offs5); + CHECK_IF(!offs2); + [foo setRect:my_rect withInt:123]; + + meth = CLASS_GETINSTANCEMETHOD(fooClass, @selector(char:float:double:long:)); + offs2 = 9999; + sscanf(meth->method_types, "v%u@%u:%uc%uf%ud%ul%u", &offs1, &offs2, &offs3, + &offs4, &offs5, &offs6, &offs7); + CHECK_IF(!offs2); + [foo char:'c' float:2.3 double:3.5 long:2345L]; + + return 0; +} diff --git a/gcc/testsuite/objc.dg/encode-3.m b/gcc/testsuite/objc.dg/encode-3.m new file mode 100644 index 0000000..b30b956 --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-3.m @@ -0,0 +1,66 @@ +/* Method encoding tests for stand-alone @protocol declarations. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do run } */ + +#include <objc/Protocol.h> +#ifdef __cplusplus +#define ProtoBool bool +#else +#define ProtoBool _Bool +#endif + +#ifndef __NEXT_RUNTIME__ +#include <objc/objc-api.h> +#endif + +extern int sscanf(const char *str, const char *format, ...); +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort() + +enum Enum { + zero, one, two, three +}; +typedef enum Enum Enum; +typedef signed char ObjCBool; /* as used by the NeXT runtime */ + +@protocol Proto +union __XXAngle { unsigned int alpha, beta; }; +typedef struct { float x, y; union __XXAngle a; } XXPoint; +typedef struct { double width, height; } XXSize; +typedef struct _XXRect { XXPoint origin; XXSize size; struct _XXRect *next; } XXRect; +- (void) char:(char)c float:(float)f double:(double)d unsigned:(unsigned)u short:(short)s long:(long)l; +- (void *)setRect:(XXRect)r withBool:(ProtoBool)b withInt:(int)i; ++ (Enum *)getEnum:(XXPoint *)pt enum:(enum Enum)e bool:(ObjCBool)b; ++ (ProtoBool **)getBool:(ObjCBool **)b; +@end + +Protocol *proto = @protocol(Proto); +struct objc_method_description *meth; +unsigned totsize, offs0, offs1, offs2, offs3, offs4, offs5, offs6, offs7; + +static void scan_initial(const char *pattern) { + totsize = offs0 = offs1 = offs2 = offs3 = offs4 = offs5 = offs6 = offs7 = (unsigned)-1; + sscanf(meth->types, pattern, &totsize, &offs0, &offs1, &offs2, &offs3, + &offs4, &offs5, &offs6, &offs7); + CHECK_IF(!offs0 && offs1 == sizeof(id) && offs2 == offs1 + sizeof(SEL) && totsize >= offs2); +} + +int main(void) { + meth = [proto descriptionForInstanceMethod: @selector(char:float:double:unsigned:short:long:)]; + scan_initial("v%u@%u:%uc%uf%ud%uI%us%ul%u"); + CHECK_IF(offs3 == offs2 + sizeof(int) && offs4 == offs3 + sizeof(float)); + CHECK_IF(offs5 == offs4 + sizeof(double) && offs6 == offs5 + sizeof(unsigned)); + CHECK_IF(offs7 == offs6 + sizeof(int) && totsize == offs7 + sizeof(long)); + meth = [proto descriptionForInstanceMethod: @selector(setRect:withBool:withInt:)]; + scan_initial("^v%u@%u:%u{_XXRect={?=ff(__XXAngle=II)}{?=dd}^{_XXRect}}%uB%ui%u"); + CHECK_IF(offs3 == offs2 + sizeof(XXRect) && offs4 == offs3 + sizeof(int)); + CHECK_IF(totsize == offs4 + sizeof(int)); + meth = [proto descriptionForClassMethod: @selector(getEnum:enum:bool:)]; + scan_initial("^i%u@%u:%u^{?=ff(__XXAngle=II)}%ui%uc%u"); + CHECK_IF(offs3 == offs2 + sizeof(XXPoint *) && offs4 == offs3 + sizeof(enum Enum)); + CHECK_IF(totsize == offs4 + sizeof(int)); /* 'ObjCBool' is really 'char' */ + meth = [proto descriptionForClassMethod: @selector(getBool:)]; + scan_initial("^^B%u@%u:%u^*%u"); + CHECK_IF(totsize == offs2 + sizeof(ObjCBool **)); + return 0; +} diff --git a/gcc/testsuite/objc.dg/encode-4.m b/gcc/testsuite/objc.dg/encode-4.m new file mode 100644 index 0000000..1f179e1 --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-4.m @@ -0,0 +1,73 @@ +/* Encoding tests for ObjC class layouts. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-lobjc" } */ +/* { dg-do run } */ + +#include <objc/Object.h> +#ifdef __NEXT_RUNTIME__ +#include <objc/objc-class.h> +#define OBJC_GETCLASS objc_getClass +#else +#include <objc/objc-api.h> +#define OBJC_GETCLASS objc_get_class +#endif + +extern void abort(void); +extern int strcmp(const char *s1, const char *s2); +#define CHECK_IF(expr) if(!(expr)) abort() + +@class Int1, Int2; +struct Nested; + +struct Innermost { + unsigned char a, b; + struct Nested *encl; +}; + +struct Nested { + float a, b; + Int1 *next; + struct Innermost innermost; +}; + +@interface Int1: Object { + char a, b; + Int2 *int2; + struct Nested nested; +} +@end + +@interface Int2: Int1 { + struct Innermost *innermost; + Int1 *base; +} +@end + +@implementation Int1 +@end + +@implementation Int2 +@end + +struct objc_ivar *ivar; + +static void check_ivar(const char *name, const char *type) { + CHECK_IF(!strcmp(ivar->ivar_name, name)); + CHECK_IF(!strcmp(ivar->ivar_type, type)); + ivar++; +} + +int main(void) { + ivar = ((Class)OBJC_GETCLASS("Int1"))->ivars->ivar_list; + check_ivar("a", "c"); + check_ivar("b", "c"); + check_ivar("int2", "@\"Int2\""); + check_ivar("nested", + "{Nested=\"a\"f\"b\"f\"next\"@\"Int1\"\"innermost\"{Innermost=\"a\"C\"b\"C\"encl\"^{Nested}}}"); + + ivar = ((Class)OBJC_GETCLASS("Int2"))->ivars->ivar_list; + check_ivar("innermost", "^{Innermost=CC^{Nested}}"); + check_ivar("base", "@\"Int1\""); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/func-ptr-1.m b/gcc/testsuite/objc.dg/func-ptr-1.m new file mode 100644 index 0000000..015d3ac --- /dev/null +++ b/gcc/testsuite/objc.dg/func-ptr-1.m @@ -0,0 +1,48 @@ +/* Test for handling of function pointer ivars */ +/* { dg-do run } */ + +#include <objc/Object.h> + +extern int strcmp(const char *, const char *); +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort() + +typedef float (*floatfunc)(float, float); + +@interface MyObject : Object +{ +@public + int (*ivar)(int, int, int); + floatfunc ffunc; +} +- init; +@end + +int foo(int a, int b, int c) { + return a + b + c; +} + +float bar(float a, float b) { + return a * b; +} + +@implementation MyObject +- init { + [super init]; + ivar = foo; + ffunc = bar; + return self; +} +@end + +int main () +{ + MyObject *obj = [[MyObject alloc] init]; + const char *enc = @encode(MyObject); + + CHECK_IF(obj->ivar(4, 5, 6) == 15); + CHECK_IF(obj->ffunc(34.0, 45.0) == 34.0 * 45.0); + CHECK_IF(!strcmp(enc, "{MyObject=#^?^?}")); + return(0); +} + diff --git a/gcc/testsuite/objc.dg/gnu-runtime-1.m b/gcc/testsuite/objc.dg/gnu-runtime-1.m new file mode 100644 index 0000000..dab9215 --- /dev/null +++ b/gcc/testsuite/objc.dg/gnu-runtime-1.m @@ -0,0 +1,19 @@ +/* Test that compiling for the GNU runtime works (regardless of + the system runtime used). */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do compile } */ +/* { dg-options "-fgnu-runtime" } */ + +#include <objc/Object.h> + +@interface FooBar: Object +- (void)boo; +@end + +int main () +{ + id fooBarInst = [[FooBar alloc] init]; + [fooBarInst boo]; + return 0; +} + diff --git a/gcc/testsuite/objc.dg/headers.m b/gcc/testsuite/objc.dg/headers.m index 5435a75..4c61e1e 100644 --- a/gcc/testsuite/objc.dg/headers.m +++ b/gcc/testsuite/objc.dg/headers.m @@ -3,14 +3,29 @@ // { dg-options "-Wall -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wshadow" } // { dg-do compile } +#ifdef __NEXT_RUNTIME__ +#include <Foundation/NSString.h> +#else #include <objc/NXConstStr.h> +#endif #include <objc/Object.h> #include <objc/Protocol.h> +#ifdef __NEXT_RUNTIME__ +#include <objc/objc-runtime.h> +#else #include <objc/encoding.h> #include <objc/hash.h> +#endif + #include <objc/objc-api.h> +#ifndef __NEXT_RUNTIME__ #include <objc/objc-list.h> +#endif + #include <objc/objc.h> + +#ifndef __NEXT_RUNTIME__ #include <objc/sarray.h> #include <objc/thr.h> #include <objc/typedstream.h> +#endif diff --git a/gcc/testsuite/objc.dg/image-info.m b/gcc/testsuite/objc.dg/image-info.m new file mode 100644 index 0000000..84e6ad8 --- /dev/null +++ b/gcc/testsuite/objc.dg/image-info.m @@ -0,0 +1,38 @@ +/* Check if the '-freplace-objc-classes' option causes the + __OBJC,__image_info section to be emitted. This is only + usable on MacOS X 10.3 and later. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-freplace-objc-classes" } */ +/* { dg-do compile { target *-*-darwin* } } */ + +#ifndef __NEXT_RUNTIME__ +#error Feature not currently supported by the GNU runtime +#endif + +#include <objc/objc.h> +#include <objc/Object.h> + +extern void abort(void); + +#define CHECK_IF(expr) if(!(expr)) abort(); + +@interface Base: Object { +@public + int a; + float b; + char c; +} +- init; +@end + +@implementation Base +- init { + [super init]; + a = 123; + b = 1.23; + c = 'c'; + return self; +} +@end + +/* { dg-final { scan-assembler "\n.data\n.section __OBJC, __image_info\n\t.align.*\nL_OBJC_IMAGE_INFO:\n\t.long\t0\n\t.long\t1\n.data\n.objc_module_info\n" } } */ diff --git a/gcc/testsuite/objc.dg/method-1.m b/gcc/testsuite/objc.dg/method-1.m index 8b761c6..391ee62 100644 --- a/gcc/testsuite/objc.dg/method-1.m +++ b/gcc/testsuite/objc.dg/method-1.m @@ -3,12 +3,12 @@ @interface class1 - (int) meth1; -- (void) meth1; /* { dg-error "duplicate declaration of instance method" } */ +- (void) meth1; /* { dg-error "duplicate declaration of method .\\-meth1." } */ @end @interface class2 + (void) meth1; -+ (int) meth1; /* { dg-error "duplicate declaration of class method" } */ ++ (int) meth1; /* { dg-error "duplicate declaration of method .\\+meth1." } */ @end @interface class3 @@ -17,8 +17,7 @@ @implementation class3 - (int) meth1 { return 0; } -- (int) meth1 { return 0; } /* { dg-error "duplicate definition of instance method" } */ -/* { dg-error "redefinition of" "" { target *-*-* } 20 } */ +- (int) meth1 { return 0; } /* { dg-error "redefinition of" } */ /* { dg-error "previously defined here" "" { target *-*-* } 19 } */ @end @@ -28,7 +27,6 @@ @implementation class4 + (void) meth1 {} -+ (void) meth1 {} /* { dg-error "duplicate definition of class method" } */ -/* { dg-error "redefinition of" "" { target *-*-* } 31 } */ -/* { dg-error "previously defined here" "" { target *-*-* } 30 } */ ++ (void) meth1 {} /* { dg-error "redefinition of" } */ +/* { dg-error "previously defined here" "" { target *-*-* } 29 } */ @end diff --git a/gcc/testsuite/objc.dg/method-10.m b/gcc/testsuite/objc.dg/method-10.m new file mode 100644 index 0000000..5a2a1db --- /dev/null +++ b/gcc/testsuite/objc.dg/method-10.m @@ -0,0 +1,32 @@ +/* When there is only one candidate method available, make sure the + compiler uses its argument/return types when constructing the + message sends (so that proper C/C++ argument conversions may + take place). */ +/* { dg-do run } */ + +#include <objc/Object.h> +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort() + +static double d = 4.5920234e2; + +@interface Foo : Object +-(void) brokenType: (int)x floatingPoint: (double)y; +@end + + +@implementation Foo +-(void) brokenType: (int)x floatingPoint: (double)y +{ + CHECK_IF(x == 459); + CHECK_IF(y == d); +} +@end + +int main(void) +{ + Foo *foo=[Foo new]; + [foo brokenType: d floatingPoint: d]; + return 0; +} + diff --git a/gcc/testsuite/objc.dg/method-11.m b/gcc/testsuite/objc.dg/method-11.m new file mode 100644 index 0000000..5921292 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-11.m @@ -0,0 +1,33 @@ +/* Ensure that we indeed cannot obtain the value of a message send + if the chosen method signature returns 'void'. There used to + exist a cheesy hack that allowed it. While at it, check that + the first lexically occurring method signature gets picked + when sending messages to 'id'. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@interface Object1 +- (void)initWithData:(Object1 *)data; +@end + +@interface Object2 +- (id)initWithData:(Object1 *)data; +@end + +@interface Object3 +- (id)initWithData:(Object2 *)data; +@end + +void foo(void) { + id obj1, obj2 = 0; + obj2 = [obj1 initWithData: obj2]; + /* { dg-warning "multiple methods named .\\-initWithData:. found" "" { target *-*-* } 25 } */ + /* { dg-warning "using .\\-\\(void\\)initWithData:\\(Object1 \\*\\)data." "" { target *-*-* } 12 } */ + /* { dg-warning "also found .\\-\\(id\\)initWithData:\\(Object1 \\*\\)data." "" { target *-*-* } 16 } */ + /* { dg-warning "also found .\\-\\(id\\)initWithData:\\(Object2 \\*\\)data." "" { target *-*-* } 20 } */ + + /* The following error is a consequence of picking the "wrong" method signature. */ + /* { dg-error "void value not ignored as it ought to be" "" { target *-*-* } 25 } */ +} diff --git a/gcc/testsuite/objc.dg/method-12.m b/gcc/testsuite/objc.dg/method-12.m new file mode 100644 index 0000000..d6e6ce5 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-12.m @@ -0,0 +1,25 @@ +/* Contributed by Igor Seleznev <selez@mail.ru>. */ +/* This used to be broken. */ + +#include <objc/objc-api.h> + +@interface A ++ (A *)currentContext; +@end + +@interface B ++ (B *)currentContext; +@end + +int main() +{ + [A currentContext]; /* { dg-bogus "multiple declarations" } */ + return 0; +} + +@implementation A ++ (A *)currentContext { return nil; } +@end +@implementation B ++ (B *)currentContext { return nil; } +@end diff --git a/gcc/testsuite/objc.dg/method-2.m b/gcc/testsuite/objc.dg/method-2.m index b4cd4da..8bf211f 100644 --- a/gcc/testsuite/objc.dg/method-2.m +++ b/gcc/testsuite/objc.dg/method-2.m @@ -22,10 +22,11 @@ [self rootInstanceMethod]; /* class is searched for an instance method */ [MyIntermediate rootInstanceMethod]; /* with the same name. */ - [self instanceMethod]; /* { dg-warning "cannot find class" } */ - /* { dg-warning "defaults to id" "" { target *-*-* } 25 } */ - [MyDerived instanceMethod]; /* { dg-warning "cannot find class" } */ - /* { dg-warning "defaults to id" "" { target *-*-* } 27 } */ + [self instanceMethod]; /* { dg-warning ".MyDerived. may not respond to .\\+instanceMethod." } */ + /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 25 } */ + /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 25 } */ + /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 25 } */ + [MyDerived instanceMethod]; /* { dg-warning ".MyDerived. may not respond to .\\+instanceMethod." } */ } @end diff --git a/gcc/testsuite/objc.dg/method-3.m b/gcc/testsuite/objc.dg/method-3.m new file mode 100644 index 0000000..65031b0 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-3.m @@ -0,0 +1,45 @@ +/* Test for sending messages to aliased classes (and instances thereof). */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-lobjc" } */ +/* { dg-do run } */ + +#include <objc/Object.h> + +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort() + +@interface Int1: Object ++ (int) classMeth; +- (int) instanceMeth; +@end + +@interface Int2: Object ++ (int) classMeth; +- (int) instanceMeth; +@end + +@implementation Int1 ++ (int) classMeth { return 345; } +- (int) instanceMeth { return 697; } +@end + +@implementation Int2 ++ (int) classMeth { return 1345; } +- (int) instanceMeth { return 1697; } +@end + +typedef Int1 Int1Typedef; +@compatibility_alias Int1Alias Int1Typedef; +@compatibility_alias Int2Alias Int2; +typedef Int2Alias Int2Typedef; + +int main(void) { + Int1Alias *int1alias = [[Int1Typedef alloc] init]; + Int2Typedef *int2typedef = [[Int2Alias alloc] init]; + + CHECK_IF([Int1Typedef classMeth] == 345 && [Int2Alias classMeth] == 1345); + CHECK_IF([int1alias instanceMeth] == 697 && [int2typedef instanceMeth] == 1697); + CHECK_IF([(Int2Typedef *)int1alias instanceMeth] == 697); + CHECK_IF([(Int1Alias *)int2typedef instanceMeth] == 1697); + return 0; +} diff --git a/gcc/testsuite/objc.dg/method-4.m b/gcc/testsuite/objc.dg/method-4.m new file mode 100644 index 0000000..c8d092d --- /dev/null +++ b/gcc/testsuite/objc.dg/method-4.m @@ -0,0 +1,25 @@ +/* Check if class references (generated for the NeXT runtime) are appropriately + folded. This test is safe to run on all targets. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-fnext-runtime" } */ +/* { dg-do compile } */ + +#include <objc/Object.h> + +typedef Object ObjectTypedef1; +typedef ObjectTypedef1 ObjectTypedef2; +@compatibility_alias ObjectAlias1 ObjectTypedef2; +@compatibility_alias ObjectAlias2 ObjectAlias1; +typedef ObjectAlias2 ObjectTypedef3; + +void foo(void) { + id obj = [Object new]; + obj = [ObjectTypedef1 new]; + obj = [ObjectTypedef2 new]; + obj = [ObjectTypedef3 new]; + obj = [ObjectAlias1 new]; + obj = [ObjectAlias2 new]; +} + +/* { dg-final { scan-assembler "_OBJC_CLASS_REFERENCES_0" } } */ +/* { dg-final { scan-assembler-not "_OBJC_CLASS_REFERENCES_1" } } */ diff --git a/gcc/testsuite/objc.dg/method-5.m b/gcc/testsuite/objc.dg/method-5.m new file mode 100644 index 0000000..e2332ea --- /dev/null +++ b/gcc/testsuite/objc.dg/method-5.m @@ -0,0 +1,18 @@ +/* Check if sending messages to "underspecified" objects is handled gracefully. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +@class UnderSpecified; +typedef struct NotAClass { + int a, b; +} NotAClass; + +void foo(UnderSpecified *u, NotAClass *n) { + [n nonexistent_method]; /* { dg-warning "invalid receiver type" } */ + /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 11 } */ + /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 11 } */ + /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 11 } */ + [NotAClass nonexistent_method]; /* { dg-error ".NotAClass. is not an Objective\\-C class name or alias" } */ + [u nonexistent_method]; /* { dg-warning ".UnderSpecified. may not respond to .\\-nonexistent_method." } */ + [UnderSpecified nonexistent_method]; /* { dg-warning ".UnderSpecified. may not respond to .\\+nonexistent_method." } */ +} diff --git a/gcc/testsuite/objc.dg/method-6.m b/gcc/testsuite/objc.dg/method-6.m new file mode 100644 index 0000000..212958b --- /dev/null +++ b/gcc/testsuite/objc.dg/method-6.m @@ -0,0 +1,26 @@ +/* Check that sending messages to variables of type 'Class' does not involve instance methods. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do compile } */ + +#include <objc/Protocol.h> + +@interface Base +- (unsigned)port; +- (id)starboard; +@end + +@interface Derived: Base +- (Object *)port; ++ (Protocol *)port; +@end + +id foo(void) { + Class receiver; + id p = [receiver port]; /* there should be no warnings here! */ + p = [receiver starboard]; /* { dg-warning ".Class. may not respond to .\\+starboard." } */ + /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 20 } */ + /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 20 } */ + /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 20 } */ + p = [Class port]; /* { dg-error ".Class. is not an Objective\\-C class name or alias" } */ + return p; +} diff --git a/gcc/testsuite/objc.dg/method-7.m b/gcc/testsuite/objc.dg/method-7.m new file mode 100644 index 0000000..f84759c --- /dev/null +++ b/gcc/testsuite/objc.dg/method-7.m @@ -0,0 +1,27 @@ +/* Check if finding multiple signatures for a method is handled gracefully. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do compile } */ + +#include <objc/Object.h> + +@interface Class1 +- (void)setWindow:(Object *)wdw; +@end + +@interface Class2 +- (void)setWindow:(Class1 *)window; +@end + +id foo(void) { + Object *obj = [[Object alloc] init]; + id obj2 = obj; + [obj setWindow:nil]; /* { dg-warning ".Object. may not respond to .\\-setWindow:." } */ + /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 18 } */ + /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 18 } */ + /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 18 } */ + [obj2 setWindow:nil]; /* { dg-warning "multiple methods named .\\-setWindow:. found" } */ + /* { dg-warning "using .\\-\\(void\\)setWindow:\\(Object \\*\\)wdw." "" { target *-*-* } 8 } */ + /* { dg-warning "also found .\\-\\(void\\)setWindow:\\(Class1 \\*\\)window." "" { target *-*-* } 12 } */ + + return obj; +} diff --git a/gcc/testsuite/objc.dg/method-8.m b/gcc/testsuite/objc.dg/method-8.m new file mode 100644 index 0000000..4a13b7d --- /dev/null +++ b/gcc/testsuite/objc.dg/method-8.m @@ -0,0 +1,14 @@ +/* Check if casting the receiver type causes method lookup to succeed. This was broken + in Objective-C++. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do compile } */ + +@interface A +@end + +@interface B: A +- (void)f; +@end + +void g(A *p) { [(B *)p f]; } + diff --git a/gcc/testsuite/objc.dg/method-9.m b/gcc/testsuite/objc.dg/method-9.m new file mode 100644 index 0000000..ba83284 --- /dev/null +++ b/gcc/testsuite/objc.dg/method-9.m @@ -0,0 +1,43 @@ +/* Check if finding multiple signatures for a method is handled gracefully + when method lookup succeeds (see also method-7.m). */ +/* Contributed by Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do compile } */ + +#include <objc/Object.h> + +@protocol MyObject +- (id)initWithData:(Object *)data; +@end + +@protocol SomeOther +- (id)initWithData:(int)data; +@end + +@protocol MyCoding +- (id)initWithData:(id<MyObject, MyCoding>)data; +@end + +@interface NTGridDataObject: Object <MyCoding> +{ + Object<MyCoding> *_data; +} ++ (NTGridDataObject*)dataObject:(id<MyObject, MyCoding>)data; +@end + +@implementation NTGridDataObject +- (id)initWithData:(id<MyObject, MyCoding>)data { + return data; +} ++ (NTGridDataObject*)dataObject:(id<MyObject, MyCoding>)data +{ + NTGridDataObject *result = [[NTGridDataObject alloc] initWithData:data]; + /* { dg-warning "multiple methods named .\\-initWithData:. found" "" { target *-*-* } 33 } */ + /* { dg-warning "using .\\-\\(id\\)initWithData:\\(Object \\*\\)data." "" { target *-*-* } 9 } */ + /* { dg-warning "also found .\\-\\(id\\)initWithData:\\(id <MyObject, MyCoding>\\)data." "" { target *-*-* } 17 } */ + /* { dg-warning "also found .\\-\\(id\\)initWithData:\\(int\\)data." "" { target *-*-* } 13 } */ + + /* The following warning is a consequence of picking the "wrong" method signature. */ + /* { dg-warning "passing arg 1 of .initWithData:. from incompatible pointer type" "" { target *-*-* } 33 } */ + return result; +} +@end diff --git a/gcc/testsuite/objc.dg/missing-proto-1.m b/gcc/testsuite/objc.dg/missing-proto-1.m new file mode 100644 index 0000000..7132ead4 --- /dev/null +++ b/gcc/testsuite/objc.dg/missing-proto-1.m @@ -0,0 +1,6 @@ +/* Test for graceful handling of missing protocol declarations. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +@interface Foo <Missing> /* { dg-error "cannot find protocol declaration for .Missing." } */ +@end diff --git a/gcc/testsuite/objc.dg/missing-proto-2.m b/gcc/testsuite/objc.dg/missing-proto-2.m new file mode 100644 index 0000000..cb121b4 --- /dev/null +++ b/gcc/testsuite/objc.dg/missing-proto-2.m @@ -0,0 +1,5 @@ +/* Test for graceful handling of missing protocol declarations. */ +/* Author: Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +void *protRef = @protocol(Missing); /* { dg-error "cannot find protocol declaration for .Missing." } */ diff --git a/gcc/testsuite/objc.dg/missing-proto-3.m b/gcc/testsuite/objc.dg/missing-proto-3.m new file mode 100644 index 0000000..6c610ce --- /dev/null +++ b/gcc/testsuite/objc.dg/missing-proto-3.m @@ -0,0 +1,26 @@ +/* Ensure that the compiler gracefully handles missing protocol declarations. + In addition to not crashing :-), the compiler should properly handle + valid protocol references, even when they're mixed with invalid ones. */ +/* { dg-do compile } */ + +#include <objc/objc.h> + +@protocol DefinedProtocol +- (id) missingMethod1; +@end + +@interface MyClass <UndefinedProtocol, DefinedProtocol> +/* { dg-error "cannot find protocol declaration for .UndefinedProtocol." "" { target *-*-* } 12 } */ +@end + +@implementation MyClass ++(Class)class +{ + return self; +} +@end + +/* { dg-warning "incomplete implementation of class .MyClass." "" { target *-*-* } 21 } */ +/* { dg-warning "method definition for .\\-missingMethod1. not found" "" { target *-*-* } 21 } */ +/* { dg-warning "class .MyClass. does not fully implement the .DefinedProtocol. protocol" "" { target *-*-* } 21 } */ + diff --git a/gcc/testsuite/objc.dg/nested-func-1.m b/gcc/testsuite/objc.dg/nested-func-1.m new file mode 100644 index 0000000..7a182bd --- /dev/null +++ b/gcc/testsuite/objc.dg/nested-func-1.m @@ -0,0 +1,37 @@ +/* Test basic nested C function functionality within ObjC + methods. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-lobjc" } */ +/* { dg-do run } */ +#include <stdio.h> +#include <objc/objc.h> +#include <objc/Object.h> + +int bappy (int (*blargh) (int a, int b, int c)) +{ + return blargh (4, 7, 2) + 3; +} + +@interface Foo: Object ++ (int)foo; +@end + +@implementation Foo ++ (int)foo +{ + int blargh (int a, int b, int c) + { + return a * b + c; + } + return bappy (blargh); +} +@end + +int main () +{ + int f = [Foo foo]; + if (f != 33) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/proto-hier-1.m b/gcc/testsuite/objc.dg/proto-hier-1.m index 17ea72e..154e6b6 100644 --- a/gcc/testsuite/objc.dg/proto-hier-1.m +++ b/gcc/testsuite/objc.dg/proto-hier-1.m @@ -48,7 +48,9 @@ int foo(void) { id<Booing, Fooing> stupidVar; [stupidVar boo]; [stupidVar foo]; - [stupidVar anotherMsg]; /* { dg-warning "not implemented by protocol" } */ - /* { dg-warning "return type defaults to id" "" { target *-*-* } 51 } */ + [stupidVar anotherMsg]; /* { dg-warning ".\-anotherMsg. not implemented by protocol" } */ + /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 51 } */ + /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 51 } */ + /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 51 } */ return 0; } diff --git a/gcc/testsuite/objc.dg/proto-lossage-1.m b/gcc/testsuite/objc.dg/proto-lossage-1.m index d312039..1186f8f 100644 --- a/gcc/testsuite/objc.dg/proto-lossage-1.m +++ b/gcc/testsuite/objc.dg/proto-lossage-1.m @@ -35,7 +35,12 @@ typedef struct objc_object { struct objc_class *class_pointer; } *id; return (id <NSObject>)plate1; /* { dg-bogus "does not conform" } */ } - (int) getValue { - int i = [plate1 someValue]; /* { dg-warning "not implemented by protocol" } */ + int i = [plate1 someValue]; /* { dg-warning ".\\-someValue. not implemented by protocol\\(s\\)" } */ + /* { dg-warning "\\(Messages without a matching method signature" "" { target *-*-* } 38 } */ + /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 38 } */ + /* { dg-warning ".\.\.\.. as arguments\.\\)" "" { target *-*-* } 38 } */ + /* { dg-warning "initialization makes integer from pointer without a cast" "" { target *-*-* } 38 } */ + int j = [(id <NSObject>)plate1 someValue]; /* { dg-bogus "not implemented by protocol" } */ int k = [(id)plate1 someValue]; /* { dg-bogus "not implemented by protocol" } */ return i + j + k; diff --git a/gcc/testsuite/objc.dg/proto-lossage-2.m b/gcc/testsuite/objc.dg/proto-lossage-2.m new file mode 100644 index 0000000..b3ab968 --- /dev/null +++ b/gcc/testsuite/objc.dg/proto-lossage-2.m @@ -0,0 +1,20 @@ +/* Don't forget to look in protocols if a class (and its superclasses) do not + provide a suitable method. */ +/* { dg-do compile } */ + +#include <objc/Object.h> + +@protocol Zot +-(void) zot; +@end + +@interface Foo : Object <Zot> +@end + +int foo() +{ + Foo *f=nil; + [f zot]; /* There should be no warnings here! */ + return 0; +} + diff --git a/gcc/testsuite/objc.dg/proto-qual-1.m b/gcc/testsuite/objc.dg/proto-qual-1.m new file mode 100644 index 0000000..6ae1290 --- /dev/null +++ b/gcc/testsuite/objc.dg/proto-qual-1.m @@ -0,0 +1,48 @@ +/* Check that protocol qualifiers are compiled and encoded properly. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ +/* { dg-options "-lobjc" } */ +/* { dg-do run } */ + +#include <objc/Protocol.h> +#ifndef __NEXT_RUNTIME__ +#include <objc/objc-api.h> +#endif + +extern int sscanf(const char *str, const char *format, ...); +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort() + +@protocol Retain ++ (oneway void)retainArgument:(out bycopy id)arg1 with:(in signed char **)arg2; +- (bycopy) address:(byref inout id)location with:(out short unsigned **)arg2; +@end + +@interface Foo <Retain> ++ (oneway void)retainArgument:(out bycopy id)arg with:(in signed char **)arg2; +@end + +@implementation Foo ++ (oneway void)retainArgument:(out bycopy id)arg1 with:(in signed char **)arg2 { } +- (bycopy) address:(byref inout id)location with:(out short unsigned **)arg2 { return nil; } +@end + +Protocol *proto = @protocol(Retain); +struct objc_method_description *meth; +unsigned totsize, offs0, offs1, offs2, offs3, offs4, offs5, offs6, offs7; + +static void scan_initial(const char *pattern) { + totsize = offs0 = offs1 = offs2 = offs3 = offs4 = offs5 = offs6 = offs7 = (unsigned)-1; + sscanf(meth->types, pattern, &totsize, &offs0, &offs1, &offs2, &offs3, + &offs4, &offs5, &offs6, &offs7); + CHECK_IF(!offs0 && offs1 == sizeof(id) && offs2 == offs1 + sizeof(SEL) && totsize >= offs2); +} + +int main(void) { + meth = [proto descriptionForInstanceMethod: @selector(address:with:)]; + scan_initial("O@%u@%u:%uNR@%uo^^S%u"); + CHECK_IF(offs3 == offs2 + sizeof(id) && totsize == offs3 + sizeof(unsigned)); + meth = [proto descriptionForClassMethod: @selector(retainArgument:with:)]; + scan_initial("Vv%u@%u:%uOo@%un^*%u"); + CHECK_IF(offs3 == offs2 + sizeof(id) && totsize == offs3 + sizeof(char **)); + return 0; +} diff --git a/gcc/testsuite/objc.dg/sizeof-1.m b/gcc/testsuite/objc.dg/sizeof-1.m new file mode 100644 index 0000000..5d8def1 --- /dev/null +++ b/gcc/testsuite/objc.dg/sizeof-1.m @@ -0,0 +1,33 @@ +/* Check that the sizeof() operator works with ObjC classes and their aliases. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-lobjc" } */ +/* { dg-do run } */ + +#include <objc/objc.h> +#include <objc/Object.h> + +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort(); + +@interface Foo: Object { + int a, b; + float c, d; +} +@end + +@implementation Foo +@end + +typedef Object MyObject; +typedef struct Foo Foo_type; + +@compatibility_alias AliasObject Object; + +int main(void) { + CHECK_IF(sizeof(Foo) > sizeof(Object) && sizeof(Object) > 0); + CHECK_IF(sizeof(Foo) == sizeof(Foo_type)); + CHECK_IF(sizeof(Object) == sizeof(MyObject)); + CHECK_IF(sizeof(Object) == sizeof(AliasObject)); + return 0; +} + diff --git a/gcc/testsuite/objc.dg/special/unclaimed-category-1.h b/gcc/testsuite/objc.dg/special/unclaimed-category-1.h index 6c73d28..52586f0 100644 --- a/gcc/testsuite/objc.dg/special/unclaimed-category-1.h +++ b/gcc/testsuite/objc.dg/special/unclaimed-category-1.h @@ -2,6 +2,11 @@ #include <objc/objc.h> #include <objc/Object.h> +#ifdef __NEXT_RUNTIME__ +#define objc_get_class(C) objc_getClass(C) +#define class_create_instance(C) class_createInstance(C, 0) +#endif + /* Test loading unclaimed categories - categories of a class defined separately from the class itself. */ diff --git a/gcc/testsuite/objc.dg/special/unclaimed-category-1.m b/gcc/testsuite/objc.dg/special/unclaimed-category-1.m index 3e521e9..8b8af5e 100644 --- a/gcc/testsuite/objc.dg/special/unclaimed-category-1.m +++ b/gcc/testsuite/objc.dg/special/unclaimed-category-1.m @@ -21,6 +21,9 @@ { return 4; } +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end diff --git a/gcc/testsuite/objc.dg/static-1.m b/gcc/testsuite/objc.dg/static-1.m new file mode 100644 index 0000000..d620158 --- /dev/null +++ b/gcc/testsuite/objc.dg/static-1.m @@ -0,0 +1,33 @@ +/* Test out static (non-heap) allocations of ObjC class instances. + These should elicit errors. */ +/* Developed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +@interface Object { + struct objc_class *isa; +} +@end + +@compatibility_alias MyObject Object; + +@interface Foo: Object { + int a; + Object *b; + Object c; /* { dg-error "statically allocated instance of Objective-C class .Object." } */ +} +@end + +@compatibility_alias MyFoo Foo; + +typedef Foo FooAlias1; +typedef FooAlias1 FooAlias2; +typedef Object ObjectAlias1; +typedef struct Object ObjectAlias2; +Object staticObject1; /* { dg-error "statically allocated instance of Objective-C class .Object." } */ +struct Object staticObject2; /* { dg-error "statically allocated instance of Objective-C class .Object." } */ +static ObjectAlias1 staticObject3; /* { dg-error "statically allocated instance of Objective-C class .Object." } */ +FooAlias1 staticFoo1; /* { dg-error "statically allocated instance of Objective-C class .Foo." } */ +extern FooAlias2 externFoo1; /* { dg-error "statically allocated instance of Objective-C class .Foo." } */ +static Foo staticFoo2; /* { dg-error "statically allocated instance of Objective-C class .Foo." } */ +MyObject staticMyObject1; /* { dg-error "statically allocated instance of Objective-C class .Object." } */ +MyFoo staticMyFoo1; /* { dg-error "statically allocated instance of Objective-C class .Foo." } */ diff --git a/gcc/testsuite/objc.dg/symtab-1.m b/gcc/testsuite/objc.dg/symtab-1.m new file mode 100644 index 0000000..44e7b5a --- /dev/null +++ b/gcc/testsuite/objc.dg/symtab-1.m @@ -0,0 +1,24 @@ +/* Check if the objc_symtab descriptor is being laid out correctly. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-fnext-runtime" } */ +/* { dg-do compile { target *-*-darwin* } } */ + +#include <objc/Object.h> + +@interface Base: Object +- (void)setValues; +@end + +@interface Derived: Base +- (void)checkValues; +@end + +@implementation Base +-(void)setValues { } +@end + +@implementation Derived +-(void)checkValues { } +@end + +/* { dg-final { scan-assembler "L_OBJC_SYMBOLS:\n\t.long\t0\n\t.long\t0\n\t.short\t2\n\t.short\t0\n\t.long\tL_OBJC_CLASS_Derived\n\t.long\tL_OBJC_CLASS_Base\n" } } */ diff --git a/gcc/testsuite/objc.dg/try-catch-1.m b/gcc/testsuite/objc.dg/try-catch-1.m new file mode 100644 index 0000000..e40fdf8 --- /dev/null +++ b/gcc/testsuite/objc.dg/try-catch-1.m @@ -0,0 +1,44 @@ +/* Test if the compiler accepts @throw / @try..@catch..@finally + syntax. This will only be usable on MacOS X 10.3 and later. */ +/* Developed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-fobjc-exceptions" } */ +/* { dg-do compile { target *-*-darwin* } } */ + +#include <objc/objc.h> +#include <objc/objc-runtime.h> +#include <objc/Object.h> +#include <stdio.h> +#include <setjmp.h> + +@interface Frob: Object +@end + +@implementation Frob: Object +@end + +static int exc_control = 0; + +int proc() { + if(exc_control) { + printf ("Throwing (%d)... ", exc_control); + @throw [Frob new]; + } + return 1; +} + +int foo() +{ + @try { + return proc(); + } + @catch (Frob* ex) { + if(exc_control > 1) { + printf("Rethrowing (%d)... ", exc_control); + @throw; + } + return 0; + } + @finally { + printf("In @finally block (%d)... ", exc_control); + } +} diff --git a/gcc/testsuite/objc.dg/try-catch-2.m b/gcc/testsuite/objc.dg/try-catch-2.m new file mode 100644 index 0000000..fc314f3 --- /dev/null +++ b/gcc/testsuite/objc.dg/try-catch-2.m @@ -0,0 +1,85 @@ +/* Test out '@catch(id foo) {...}', which should catch + all uncaught exceptions. */ +/* Developed by Ziemowit Laski <zlaski@apple.com>. */ + +/* { dg-options "-fobjc-exceptions -lobjc" } */ +/* { dg-do run { target *-*-darwin[789]* } } */ + +#include <objc/objc.h> +#include <objc/objc-runtime.h> +#include <objc/Object.h> +#include <stdio.h> + +/* The following is not required in actual user code; we include it + here to check that the compiler generates an internal definition of + _setjmp that is consistent with what <setjmp.h> provides. */ +#include <setjmp.h> + +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort() + +@interface Frob: Object +@end + +@implementation Frob: Object +@end + +static Frob* _connection = nil; + +//-------------------------------------------------------------------- + + +void test (Object* sendPort) +{ + int cleanupPorts = 1; + Frob* receivePort = nil; + + @try { + printf ("receivePort = %p\n", receivePort); + printf ("sendPort = %p\n", sendPort); + printf ("cleanupPorts = %d\n", cleanupPorts); + printf ("---\n"); + + receivePort = (Frob *) -1; + _connection = (Frob *) -1; + printf ("receivePort = %p\n", receivePort); + printf ("sendPort = %p\n", sendPort); + printf ("cleanupPorts = %d\n", cleanupPorts); + printf ("---\n"); + + receivePort = nil; + sendPort = nil; + cleanupPorts = 0; + + printf ("receivePort = %p\n", receivePort); + printf ("sendPort = %p\n", sendPort); + printf ("cleanupPorts = %d\n", cleanupPorts); + printf ("---\n"); + + @throw [Object new]; + } + @catch(Frob *obj) { + printf ("Exception caught by incorrect handler!\n"); + CHECK_IF(0); + } + @catch(id exc) { + printf ("Exception caught by correct handler.\n"); + printf ("receivePort = %p (expected 0x0)\n", receivePort); + printf ("sendPort = %p (expected 0x0)\n", sendPort); + printf ("cleanupPorts = %d (expected 0)\n", cleanupPorts); + printf ("---"); + CHECK_IF(!receivePort); + CHECK_IF(!sendPort); + CHECK_IF(!cleanupPorts); + } + @catch(Object *obj) { /* { dg-warning "Exception already handled by preceding .\\@catch\\(id\\)." } */ + printf ("Exception caught by incorrect handler!\n"); + CHECK_IF(0); + } +} + +int main (void) { + + test((Object *)-1); + return 0; +} diff --git a/gcc/testsuite/objc.dg/try-catch-3.m b/gcc/testsuite/objc.dg/try-catch-3.m new file mode 100644 index 0000000..f49362f --- /dev/null +++ b/gcc/testsuite/objc.dg/try-catch-3.m @@ -0,0 +1,19 @@ +/* Test if caught exception objects are accessible inside the + @catch block. (Yes, I managed to break this.) */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-options "-fobjc-exceptions" } */ + +#include <objc/Object.h> + +const char *foo(void) +{ + @try { + return "foo"; + } + @catch (Object* theException) { + return [theException name]; + } +} + diff --git a/gcc/testsuite/objc.dg/try-catch-4.m b/gcc/testsuite/objc.dg/try-catch-4.m new file mode 100644 index 0000000..54aea23 --- /dev/null +++ b/gcc/testsuite/objc.dg/try-catch-4.m @@ -0,0 +1,26 @@ +/* Check that the compiler does not incorrectly complain about + exceptions being caught by previous @catch blocks. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-options "-Wall -fobjc-exceptions" } */ + +@interface Exception +@end + +@interface FooException : Exception +@end + +extern void foo(); + +void test() +{ + @try { + foo(); + } + @catch (FooException* fe) { + } + @catch (Exception* e) { + } +} + diff --git a/gcc/testsuite/objc.dg/type-size-1.m b/gcc/testsuite/objc.dg/type-size-1.m new file mode 100644 index 0000000..f2fdae5 --- /dev/null +++ b/gcc/testsuite/objc.dg/type-size-1.m @@ -0,0 +1,17 @@ +/* Reject ivars with an unknown size. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do compile } */ + +struct unknownStruct; + +@interface ArrayTest +{ + short unknownSize[unknownValue]; /* { dg-error ".unknownValue. (undeclared|was not declared)" } */ + /* { dg-error "instance variable .unknownSize. has unknown size" "" { target *-*-* } 9 } */ + struct unknownStruct unknownObj; /* { dg-error "field .unknownObj. has incomplete type" } */ + /* { dg-error "instance variable .unknownObj. has unknown size" "" { target *-*-* } 11 } */ + long knownSize[3]; /* ok */ + char zeroSize[2 - 2]; /* ok (apparently) */ + int missingSize[]; /* { dg-error "instance variable .missingSize. has unknown size" } */ +} +@end diff --git a/gcc/testsuite/objc.dg/type-size-2.m b/gcc/testsuite/objc.dg/type-size-2.m new file mode 100644 index 0000000..446de48 --- /dev/null +++ b/gcc/testsuite/objc.dg/type-size-2.m @@ -0,0 +1,58 @@ +/* Make sure that array arguments to methods are given the size of pointers. */ +/* As in the case of ivars, arrays without size (e.g., 'int []') are + encoded as pointers as well. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-do run } */ + +#include <objc/objc.h> +#ifdef __NEXT_RUNTIME__ +#include <objc/objc-runtime.h> +#define OBJC_GETCLASS objc_getClass +#define CLASS_GETINSTANCEMETHOD class_getInstanceMethod +#else +#include <objc/objc-api.h> +#define OBJC_GETCLASS objc_get_class +#define CLASS_GETINSTANCEMETHOD class_get_instance_method +#endif + +extern int sscanf(const char *str, const char *format, ...); +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort() + +enum Enum { one, two, three, four }; + +@interface ArrayTest +- (const char *)str:(signed char [])arg1 with:(unsigned char *)arg2 and:(enum Enum[4])en; +- (int)meth1:(int [])arg1 with:(int [0])arg2 with:(int [2])arg3; +@end + +@implementation ArrayTest +- (int)meth1:(int [])arg1 with:(int [0])arg2 with:(int [2])arg3 { return 0; } +- (const char *)str:(signed char [])arg1 with:(unsigned char *)arg2 and:(enum Enum[4])en { return "str"; } +@end + +Class cls; +struct objc_method *meth; +unsigned totsize, offs0, offs1, offs2, offs3, offs4, offs5, offs6, offs7; + +static void scan_initial(const char *pattern) { + totsize = offs0 = offs1 = offs2 = offs3 = offs4 = offs5 = offs6 = offs7 = (unsigned)-1; + sscanf(meth->method_types, pattern, &totsize, &offs0, &offs1, &offs2, &offs3, + &offs4, &offs5, &offs6, &offs7); + CHECK_IF(!offs0 && offs1 == sizeof(id) && offs2 == offs1 + sizeof(SEL) && totsize >= offs2); +} + +int main(void) { + cls = OBJC_GETCLASS("ArrayTest"); + + meth = CLASS_GETINSTANCEMETHOD(cls, @selector(str:with:and:)); + scan_initial("r*%u@%u:%u*%u*%u[4i]%u"); + CHECK_IF(offs3 == offs2 + sizeof(signed char *) && offs4 == offs3 + sizeof(unsigned char *)); + CHECK_IF(totsize == offs4 + sizeof(enum Enum *)); + meth = CLASS_GETINSTANCEMETHOD(cls, @selector(meth1:with:with:)); + scan_initial("i%u@%u:%u^i%u[0i]%u[2i]%u"); + CHECK_IF(offs3 == offs2 + sizeof(int *) && offs4 == offs3 + sizeof(int *)); + CHECK_IF(totsize == offs4 + sizeof(int *)); + return 0; +} + diff --git a/gcc/testsuite/objc.dg/zero-link-1.m b/gcc/testsuite/objc.dg/zero-link-1.m new file mode 100644 index 0000000..96fd0c2 --- /dev/null +++ b/gcc/testsuite/objc.dg/zero-link-1.m @@ -0,0 +1,28 @@ +/* Check if the '-fzero-link' flag correctly emits an objc_getClass() call. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-fnext-runtime -fzero-link" } */ +/* { dg-do compile } */ + +#include <objc/objc.h> +#include <objc/Object.h> + +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort(); + +@interface Base: Object ++ (int) getValue; +@end + +@implementation Base ++ (int) getValue { return 1593; } +@end + +int main(void) { + int val = [Base getValue]; + CHECK_IF(val == 1593); + return 0; +} + +/* { dg-final { scan-assembler-not "_OBJC_CLASS_REFERENCES_0" } } */ +/* { dg-final { scan-assembler "objc_getClass" } } */ + diff --git a/gcc/testsuite/objc.dg/zero-link-2.m b/gcc/testsuite/objc.dg/zero-link-2.m new file mode 100644 index 0000000..92b4ab1 --- /dev/null +++ b/gcc/testsuite/objc.dg/zero-link-2.m @@ -0,0 +1,28 @@ +/* Check if the '-fno-zero-link' flag correctly _omits_ an objc_getClass() call. */ +/* Contributed by Ziemowit Laski <zlaski@apple.com>. */ +/* { dg-options "-fnext-runtime -fno-zero-link" } */ +/* { dg-do compile } */ + +#include <objc/objc.h> +#include <objc/Object.h> + +extern void abort(void); +#define CHECK_IF(expr) if(!(expr)) abort(); + +@interface Base: Object ++ (int) getValue; +@end + +@implementation Base ++ (int) getValue { return 1593; } +@end + +int main(void) { + int val = [Base getValue]; + CHECK_IF(val == 1593); + return 0; +} + +/* { dg-final { scan-assembler "_OBJC_CLASS_REFERENCES_0" } } */ +/* { dg-final { scan-assembler-not "objc_getClass" } } */ + diff --git a/gcc/testsuite/objc/execute/IMP.m b/gcc/testsuite/objc/execute/IMP.m index 979aebb..99f6193 100644 --- a/gcc/testsuite/objc/execute/IMP.m +++ b/gcc/testsuite/objc/execute/IMP.m @@ -2,6 +2,8 @@ #include <objc/objc.h> #include <objc/objc-api.h> +#include "next_mapping.h" + /* Test getting and calling the IMP of a method */ @interface TestClass diff --git a/gcc/testsuite/objc/execute/_cmd.m b/gcc/testsuite/objc/execute/_cmd.m index 20203b5..f2b05b6 100644 --- a/gcc/testsuite/objc/execute/_cmd.m +++ b/gcc/testsuite/objc/execute/_cmd.m @@ -2,6 +2,8 @@ #include <objc/objc.h> #include <objc/objc-api.h> +#include "next_mapping.h" + /* Test the hidden argument _cmd to method calls */ @interface TestClass @@ -16,6 +18,9 @@ { return sel_get_name (_cmd); } +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end diff --git a/gcc/testsuite/objc/execute/bf-common.h b/gcc/testsuite/objc/execute/bf-common.h index 123a454..6cf7a06 100644 --- a/gcc/testsuite/objc/execute/bf-common.h +++ b/gcc/testsuite/objc/execute/bf-common.h @@ -1,5 +1,7 @@ +#ifndef __NEXT_RUNTIME__ #include <objc/encoding.h> - +#endif +#include "next_mapping.h" void print_ivars (Class class) { @@ -59,7 +61,7 @@ int main () @defs (MyObject); }; int size1, size2; - Class class = [MyObject class]; + Class class = objc_get_class ("MyObject"); printf ("type = %s\n", @encode (struct class_vars)); print_ivars (class); diff --git a/gcc/testsuite/objc/execute/bycopy-3.m b/gcc/testsuite/objc/execute/bycopy-3.m index 9c7c0ac..60acde5 100644 --- a/gcc/testsuite/objc/execute/bycopy-3.m +++ b/gcc/testsuite/objc/execute/bycopy-3.m @@ -12,7 +12,11 @@ #include <objc/objc.h> #include <objc/Object.h> #include <objc/Protocol.h> + +#ifndef __NEXT_RUNTIME__ #include <objc/encoding.h> +#endif +#include "next_mapping.h" @protocol MyProtocol + (bycopy id<MyProtocol>) bycopyMethod; diff --git a/gcc/testsuite/objc/execute/cascading-1.m b/gcc/testsuite/objc/execute/cascading-1.m new file mode 100644 index 0000000..67988a5 --- /dev/null +++ b/gcc/testsuite/objc/execute/cascading-1.m @@ -0,0 +1,33 @@ +#include <objc/Object.h> + +@interface Foo : Object ++ foo; ++ bar; +@end + +int foocalled = 0; +int barcalled = 0; + + +@implementation Foo ++ foo +{ + if (foocalled) + abort (); + foocalled = 1; + return self; +} ++ bar +{ + if (barcalled) + abort (); + barcalled = 1; + return self; +} +@end + +int main(int argc,char **argv) +{ + [[Foo foo] bar]; + return 0; +} diff --git a/gcc/testsuite/objc/execute/class-1.m b/gcc/testsuite/objc/execute/class-1.m index a28cfc3..5fd9aa8 100644 --- a/gcc/testsuite/objc/execute/class-1.m +++ b/gcc/testsuite/objc/execute/class-1.m @@ -2,6 +2,8 @@ #include <objc/objc.h> #include <objc/objc-api.h> +#include "next_mapping.h" + /* Tests creating a RootClass */ @interface RootClass diff --git a/gcc/testsuite/objc/execute/class-10.m b/gcc/testsuite/objc/execute/class-10.m index 3d9697c..d984d62 100644 --- a/gcc/testsuite/objc/execute/class-10.m +++ b/gcc/testsuite/objc/execute/class-10.m @@ -2,6 +2,8 @@ #include <objc/objc.h> #include <objc/objc-api.h> +#include "next_mapping.h" + /* Tests creating a root class and a subclass with an ivar and accessor methods and a subclass overriding the superclass' implementation, and using self to call another method of itself */ @@ -13,6 +15,9 @@ @end @implementation RootClass +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end @interface SubClass : RootClass diff --git a/gcc/testsuite/objc/execute/class-11.m b/gcc/testsuite/objc/execute/class-11.m index 902db2b..00c488b 100644 --- a/gcc/testsuite/objc/execute/class-11.m +++ b/gcc/testsuite/objc/execute/class-11.m @@ -2,6 +2,8 @@ #include <objc/objc.h> #include <objc/objc-api.h> +#include "next_mapping.h" + /* Tests creating a root class and a subclass with an ivar and accessor methods and a subclass overriding the superclass' implementation and using self to call another method of itself - in @@ -14,6 +16,9 @@ @end @implementation RootClass +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end @interface SubClass : RootClass diff --git a/gcc/testsuite/objc/execute/class-12.m b/gcc/testsuite/objc/execute/class-12.m index e65611d..fcab65b 100644 --- a/gcc/testsuite/objc/execute/class-12.m +++ b/gcc/testsuite/objc/execute/class-12.m @@ -2,6 +2,8 @@ #include <objc/objc.h> #include <objc/objc-api.h> +#include "next_mapping.h" + /* Tests creating a root class and a subclass with a class methods */ @interface RootClass @@ -11,6 +13,9 @@ @end @implementation RootClass +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end static int class_variable = 0; diff --git a/gcc/testsuite/objc/execute/class-13.m b/gcc/testsuite/objc/execute/class-13.m index 0d87afd..98cf0cc 100644 --- a/gcc/testsuite/objc/execute/class-13.m +++ b/gcc/testsuite/objc/execute/class-13.m @@ -2,6 +2,8 @@ #include <objc/objc.h> #include <objc/objc-api.h> +#include "next_mapping.h" + /* Tests creating a root class and a subclass with a class accessor methods and a subclass overriding the superclass' implementation but reusing it with super */ @@ -13,6 +15,9 @@ @end @implementation RootClass +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end static int class_variable = 0; diff --git a/gcc/testsuite/objc/execute/class-14.m b/gcc/testsuite/objc/execute/class-14.m index 2827031..7d02c36 100644 --- a/gcc/testsuite/objc/execute/class-14.m +++ b/gcc/testsuite/objc/execute/class-14.m @@ -2,6 +2,8 @@ #include <objc/objc.h> #include <objc/objc-api.h> +#include "next_mapping.h" + /* Tests creating a root class and a subclass with a class accessor methods and a subclass overriding the superclass' implementation, and using self to call another method of itself */ @@ -13,6 +15,9 @@ @end @implementation RootClass +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end static int class_variable = 0; diff --git a/gcc/testsuite/objc/execute/class-2.m b/gcc/testsuite/objc/execute/class-2.m index cb8b47f..350a583 100644 --- a/gcc/testsuite/objc/execute/class-2.m +++ b/gcc/testsuite/objc/execute/class-2.m @@ -2,6 +2,8 @@ #include <objc/objc.h> #include <objc/objc-api.h> +#include "next_mapping.h" + /* Tests creating a root class and a subclass */ @interface RootClass diff --git a/gcc/testsuite/objc/execute/class-3.m b/gcc/testsuite/objc/execute/class-3.m index dbe68bf..5ce8337 100644 --- a/gcc/testsuite/objc/execute/class-3.m +++ b/gcc/testsuite/objc/execute/class-3.m @@ -2,6 +2,8 @@ #include <objc/objc.h> #include <objc/objc-api.h> +#include "next_mapping.h" + /* Tests creating a root class and a minimal subclass tree */ @interface RootClass diff --git a/gcc/testsuite/objc/execute/class-4.m b/gcc/testsuite/objc/execute/class-4.m index 0ae723c..34d414b 100644 --- a/gcc/testsuite/objc/execute/class-4.m +++ b/gcc/testsuite/objc/execute/class-4.m @@ -2,6 +2,8 @@ #include <objc/objc.h> #include <objc/objc-api.h> +#include "next_mapping.h" + /* Tests creating a root class and a subclass with an ivar and accessor methods */ @@ -12,6 +14,9 @@ @end @implementation RootClass +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end @interface SubClass : RootClass diff --git a/gcc/testsuite/objc/execute/class-5.m b/gcc/testsuite/objc/execute/class-5.m index 5d5297f..e2b750a 100644 --- a/gcc/testsuite/objc/execute/class-5.m +++ b/gcc/testsuite/objc/execute/class-5.m @@ -2,6 +2,8 @@ #include <objc/objc.h> #include <objc/objc-api.h> +#include "next_mapping.h" + /* Tests creating a root class and a subclass with an ivar and accessor methods and a subclass overriding the superclass' implementation */ @@ -13,6 +15,9 @@ @end @implementation RootClass +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end @interface SubClass : RootClass diff --git a/gcc/testsuite/objc/execute/class-6.m b/gcc/testsuite/objc/execute/class-6.m index f60912a..fb2d64b 100644 --- a/gcc/testsuite/objc/execute/class-6.m +++ b/gcc/testsuite/objc/execute/class-6.m @@ -2,6 +2,8 @@ #include <objc/objc.h> #include <objc/objc-api.h> +#include "next_mapping.h" + /* Tests creating a root class and a subclass with an ivar and accessor methods and a subclass overriding the superclass' implementation but reusing it with super */ @@ -13,6 +15,9 @@ @end @implementation RootClass +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end @interface SubClass : RootClass diff --git a/gcc/testsuite/objc/execute/class-7.m b/gcc/testsuite/objc/execute/class-7.m index 9a2fe0c..3fddca7 100644 --- a/gcc/testsuite/objc/execute/class-7.m +++ b/gcc/testsuite/objc/execute/class-7.m @@ -2,6 +2,8 @@ #include <objc/objc.h> #include <objc/objc-api.h> +#include "next_mapping.h" + /* Tests creating a root class and a subclass with an ivar and accessor methods; accessor methods implemented in a separate category */ @@ -13,6 +15,9 @@ @end @implementation RootClass +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end @interface SubClass : RootClass @@ -49,6 +54,13 @@ int main (void) SubClass *object; test_class_with_superclass ("SubClass", "RootClass"); + + /* The NeXT runtime's category implementation is lazy: categories are not attached + to classes until the class is initialized (at +initialize time). */ +#ifdef __NEXT_RUNTIME__ + [SubClass initialize]; +#endif + test_that_class_has_instance_method ("SubClass", @selector (setState:)); test_that_class_has_instance_method ("SubClass", @selector (state)); diff --git a/gcc/testsuite/objc/execute/class-8.m b/gcc/testsuite/objc/execute/class-8.m index fa11185..806db03 100644 --- a/gcc/testsuite/objc/execute/class-8.m +++ b/gcc/testsuite/objc/execute/class-8.m @@ -2,6 +2,8 @@ #include <objc/objc.h> #include <objc/objc-api.h> +#include "next_mapping.h" + /* Tests creating a root class and a subclass with an ivar and accessor methods and a subclass overriding the superclass' implementation - in a category */ @@ -13,6 +15,9 @@ @end @implementation RootClass +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end @interface SubClass : RootClass diff --git a/gcc/testsuite/objc/execute/class-9.m b/gcc/testsuite/objc/execute/class-9.m index bb405fb..d32362b 100644 --- a/gcc/testsuite/objc/execute/class-9.m +++ b/gcc/testsuite/objc/execute/class-9.m @@ -2,6 +2,8 @@ #include <objc/objc.h> #include <objc/objc-api.h> +#include "next_mapping.h" + /* Tests creating a root class and a subclass with an ivar and accessor methods and a subclass overriding the superclass' implementation but reusing it with super - in a category */ @@ -13,6 +15,9 @@ @end @implementation RootClass +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end @interface SubClass : RootClass diff --git a/gcc/testsuite/objc/execute/class-tests-2.h b/gcc/testsuite/objc/execute/class-tests-2.h index 6df91df..cc14abb 100644 --- a/gcc/testsuite/objc/execute/class-tests-2.h +++ b/gcc/testsuite/objc/execute/class-tests-2.h @@ -62,6 +62,6 @@ void test_accessor_method (TYPE_OF_OBJECT_WITH_ACCESSOR_METHOD object, abort (); } } -#endif CLASS_WITH_ACCESSOR_METHOD +#endif /* CLASS_WITH_ACCESSOR_METHOD */ diff --git a/gcc/testsuite/objc/execute/class_self-1.m b/gcc/testsuite/objc/execute/class_self-1.m index 4d42516..1690f8f 100644 --- a/gcc/testsuite/objc/execute/class_self-1.m +++ b/gcc/testsuite/objc/execute/class_self-1.m @@ -51,6 +51,9 @@ struct d { return 4; } +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end diff --git a/gcc/testsuite/objc/execute/class_self-2.m b/gcc/testsuite/objc/execute/class_self-2.m index e64fcf9..7fa5490 100644 --- a/gcc/testsuite/objc/execute/class_self-2.m +++ b/gcc/testsuite/objc/execute/class_self-2.m @@ -32,6 +32,9 @@ struct d return u; } +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end /* The second class */ @@ -54,6 +57,9 @@ struct d } } +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end diff --git a/gcc/testsuite/objc/execute/function-message-1.m b/gcc/testsuite/objc/execute/function-message-1.m new file mode 100644 index 0000000..2c8c002 --- /dev/null +++ b/gcc/testsuite/objc/execute/function-message-1.m @@ -0,0 +1,33 @@ +#include <objc/Object.h> + +@interface Foo : Object ++ bar; +@end + +int foocalled = 0; +int barcalled = 0; + + +id foo() +{ + if (foocalled) + abort (); + foocalled = 1; + return [Foo class]; +} + +@implementation Foo ++ bar +{ + if (barcalled) + abort (); + barcalled = 1; + return self; +} +@end + +int main(int argc,char **argv) +{ + [foo() bar]; + return 0; +} diff --git a/gcc/testsuite/objc/execute/many_args_method.m b/gcc/testsuite/objc/execute/many_args_method.m index d811082..6cc2e25 100644 --- a/gcc/testsuite/objc/execute/many_args_method.m +++ b/gcc/testsuite/objc/execute/many_args_method.m @@ -30,6 +30,9 @@ { return [self sumInteger: a withInteger: b withInteger: c]; } +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end diff --git a/gcc/testsuite/objc/execute/nested-3.m b/gcc/testsuite/objc/execute/nested-3.m index 94271c4..5462fd5 100644 --- a/gcc/testsuite/objc/execute/nested-3.m +++ b/gcc/testsuite/objc/execute/nested-3.m @@ -22,6 +22,9 @@ return test (); } +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end int main (void) diff --git a/gcc/testsuite/objc/execute/next_mapping.h b/gcc/testsuite/objc/execute/next_mapping.h new file mode 100644 index 0000000..67c2ce3 --- /dev/null +++ b/gcc/testsuite/objc/execute/next_mapping.h @@ -0,0 +1,851 @@ +/* This file "renames" various ObjC GNU runtime entry points + (and fakes the existence of several others) + if the NeXT runtime is being used. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ + +#ifdef __NEXT_RUNTIME__ +#include <objc/objc-class.h> +#include <ctype.h> + +#define objc_get_class(C) objc_getClass(C) +#define objc_get_meta_class(C) objc_getMetaClass(C) +#define class_get_class_method(C, S) class_getClassMethod(C, S) +#define class_get_instance_method(C, S) class_getInstanceMethod(C, S) +#define method_get_imp(M) (((Method)M)->method_imp) +#define sel_get_name(S) sel_getName(S) +#define class_create_instance(C) class_createInstance(C, 0) +#define class_get_class_name(C) object_getClassName(C) +#define class_get_super_class(C) (((struct objc_class *)C)->super_class) +#define object_get_super_class(O) class_get_super_class(*(struct objc_class **)O) +#define objc_lookup_class(N) objc_lookUpClass(N) +#define object_get_class(O) (*(struct objc_class **)O) +#define class_is_class(C) (CLS_GETINFO((struct objc_class *)C, CLS_CLASS)? YES: NO) +#define class_is_meta_class(C) (CLS_GETINFO((struct objc_class *)C, CLS_META)? YES: NO) +#define object_is_class(O) class_is_meta_class(*(struct objc_class **)O) +#define object_is_meta_class(O) (class_is_meta_class(O) && class_is_meta_class(*(struct objc_class **)O)) + +/* You need either an empty +initialize method or an empty -forward:: method. + The NeXT runtime unconditionally sends +initialize to classes when they are + first used, and unconditionally tries to forward methods that the class + doesn't understand (including +initialize). If you have neither +initialize + nor -forward::, the runtime complains. + + The simplest workaround is to add + + + initialize { return self; } + + to every root class @implementation. */ + +#ifndef NULL +#define NULL 0 +#endif + +/* The following is necessary to "cover" the bf*.m test cases on NeXT. */ + +#undef MAX +#define MAX(X, Y) \ + ({ typeof (X) __x = (X), __y = (Y); \ + (__x > __y ? __x : __y); }) + +#undef MIN +#define MIN(X, Y) \ + ({ typeof (X) __x = (X), __y = (Y); \ + (__x < __y ? __x : __y); }) + +#undef ROUND +#define ROUND(V, A) \ + ({ typeof (V) __v = (V); typeof (A) __a = (A); \ + __a * ((__v+__a - 1)/__a); }) + +#define BITS_PER_UNIT __CHAR_BIT__ +#define STRUCTURE_SIZE_BOUNDARY (BITS_PER_UNIT * sizeof (struct{char a;})) + +/* Not sure why the following are missing from NeXT objc headers... */ + +#ifndef _C_LNG_LNG +#define _C_LNG_LNG 'q' +#endif +#ifndef _C_ULNG_LNG +#define _C_ULNG_LNG 'Q' +#endif +#ifndef _C_ATOM +#define _C_ATOM '%' +#endif +#ifndef _C_BOOL +#define _C_BOOL 'B' +#endif + +#define _C_CONST 'r' +#define _C_IN 'n' +#define _C_INOUT 'N' +#define _C_OUT 'o' +#define _C_BYCOPY 'O' +#define _C_BYREF 'R' +#define _C_ONEWAY 'V' +#define _C_GCINVISIBLE '!' + +#define _F_CONST 0x01 +#define _F_IN 0x01 +#define _F_OUT 0x02 +#define _F_INOUT 0x03 +#define _F_BYCOPY 0x04 +#define _F_BYREF 0x08 +#define _F_ONEWAY 0x10 +#define _F_GCINVISIBLE 0x20 + +struct objc_struct_layout +{ + const char *original_type; + const char *type; + const char *prev_type; + unsigned int record_size; + unsigned int record_align; +}; + +typedef union { + char *arg_ptr; + char arg_regs[sizeof (char*)]; +} *arglist_t; /* argument frame */ + +const char *objc_skip_typespec (const char *type); +void objc_layout_structure_get_info (struct objc_struct_layout *layout, + unsigned int *offset, unsigned int *align, const char **type); +void objc_layout_structure (const char *type, + struct objc_struct_layout *layout); +BOOL objc_layout_structure_next_member (struct objc_struct_layout *layout); +void objc_layout_finish_structure (struct objc_struct_layout *layout, + unsigned int *size, unsigned int *align); + +/* + return the size of an object specified by type +*/ + +int +objc_sizeof_type (const char *type) +{ + /* Skip the variable name if any */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + + switch (*type) { + case _C_ID: + return sizeof (id); + break; + + case _C_CLASS: + return sizeof (Class); + break; + + case _C_SEL: + return sizeof (SEL); + break; + + case _C_CHR: + return sizeof (char); + break; + + case _C_UCHR: + return sizeof (unsigned char); + break; + + case _C_SHT: + return sizeof (short); + break; + + case _C_USHT: + return sizeof (unsigned short); + break; + + case _C_INT: + return sizeof (int); + break; + + case _C_UINT: + return sizeof (unsigned int); + break; + + case _C_LNG: + return sizeof (long); + break; + + case _C_ULNG: + return sizeof (unsigned long); + break; + + case _C_LNG_LNG: + return sizeof (long long); + break; + + case _C_ULNG_LNG: + return sizeof (unsigned long long); + break; + + case _C_FLT: + return sizeof (float); + break; + + case _C_DBL: + return sizeof (double); + break; + + case _C_VOID: + return sizeof (void); + break; + + case _C_PTR: + case _C_ATOM: + case _C_CHARPTR: + return sizeof (char *); + break; + + case _C_ARY_B: + { + int len = atoi (type + 1); + while (isdigit ((unsigned char)*++type)) + ; + return len * objc_aligned_size (type); + } + break; + + case _C_BFLD: + { + /* The NeXT encoding of bitfields is _still_: b 'size' */ + int size = atoi (type + 1); + /* Return an upper bound on byte size */ + return (size + BITS_PER_UNIT - 1) / BITS_PER_UNIT; + } + + case _C_STRUCT_B: + { + struct objc_struct_layout layout; + unsigned int size; + + objc_layout_structure (type, &layout); + while (objc_layout_structure_next_member (&layout)) + /* do nothing */ ; + objc_layout_finish_structure (&layout, &size, NULL); + + return size; + } + + case _C_UNION_B: + { + int max_size = 0; + while (*type != _C_UNION_E && *type++ != '=') + /* do nothing */; + while (*type != _C_UNION_E) + { + /* Skip the variable name if any */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + max_size = MAX (max_size, objc_sizeof_type (type)); + type = objc_skip_typespec (type); + } + return max_size; + } + } + return 0; /* error */ +} + + +/* + Return the alignment of an object specified by type +*/ + +int +objc_alignof_type (const char *type) +{ + /* Skip the variable name if any */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + switch (*type) { + case _C_ID: + return __alignof__ (id); + break; + + case _C_CLASS: + return __alignof__ (Class); + break; + + case _C_SEL: + return __alignof__ (SEL); + break; + + case _C_CHR: + return __alignof__ (char); + break; + + case _C_UCHR: + return __alignof__ (unsigned char); + break; + + case _C_SHT: + return __alignof__ (short); + break; + + case _C_USHT: + return __alignof__ (unsigned short); + break; + + case _C_INT: + case _C_BFLD: /* This is for the NeXT only */ + return __alignof__ (int); + break; + + case _C_UINT: + return __alignof__ (unsigned int); + break; + + case _C_LNG: + return __alignof__ (long); + break; + + case _C_ULNG: + return __alignof__ (unsigned long); + break; + + case _C_LNG_LNG: + return __alignof__ (long long); + break; + + case _C_ULNG_LNG: + return __alignof__ (unsigned long long); + break; + + case _C_FLT: + return __alignof__ (float); + break; + + case _C_DBL: + return __alignof__ (double); + break; + + case _C_PTR: + case _C_ATOM: + case _C_CHARPTR: + return __alignof__ (char *); + break; + + case _C_ARY_B: + while (isdigit ((unsigned char)*++type)) + /* do nothing */; + return objc_alignof_type (type); + + case _C_STRUCT_B: + { + struct objc_struct_layout layout; + unsigned int align; + + objc_layout_structure (type, &layout); + while (objc_layout_structure_next_member (&layout)) + /* do nothing */; + objc_layout_finish_structure (&layout, NULL, &align); + + return align; + } + + case _C_UNION_B: + { + int maxalign = 0; + while (*type != _C_UNION_E && *type++ != '=') + /* do nothing */; + while (*type != _C_UNION_E) + { + /* Skip the variable name if any */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + maxalign = MAX (maxalign, objc_alignof_type (type)); + type = objc_skip_typespec (type); + } + return maxalign; + } + } + return 0; /* error */ +} + +/* + The aligned size if the size rounded up to the nearest alignment. +*/ + +int +objc_aligned_size (const char *type) +{ + int size, align; + + /* Skip the variable name */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + + size = objc_sizeof_type (type); + align = objc_alignof_type (type); + + return ROUND (size, align); +} + +/* + The size rounded up to the nearest integral of the wordsize, taken + to be the size of a void *. +*/ + +int +objc_promoted_size (const char *type) +{ + int size, wordsize; + + /* Skip the variable name */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + + size = objc_sizeof_type (type); + wordsize = sizeof (void *); + + return ROUND (size, wordsize); +} + +/* + Skip type qualifiers. These may eventually precede typespecs + occurring in method prototype encodings. +*/ + +inline const char * +objc_skip_type_qualifiers (const char *type) +{ + while (*type == _C_CONST + || *type == _C_IN + || *type == _C_INOUT + || *type == _C_OUT + || *type == _C_BYCOPY + || *type == _C_BYREF + || *type == _C_ONEWAY + || *type == _C_GCINVISIBLE) + { + type += 1; + } + return type; +} + + +/* + Skip one typespec element. If the typespec is prepended by type + qualifiers, these are skipped as well. +*/ + +const char * +objc_skip_typespec (const char *type) +{ + /* Skip the variable name if any */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + + type = objc_skip_type_qualifiers (type); + + switch (*type) { + + case _C_ID: + /* An id may be annotated by the actual type if it is known + with the @"ClassName" syntax */ + + if (*++type != '"') + return type; + else + { + while (*++type != '"') + /* do nothing */; + return type + 1; + } + + /* The following are one character type codes */ + case _C_CLASS: + case _C_SEL: + case _C_CHR: + case _C_UCHR: + case _C_CHARPTR: + case _C_ATOM: + case _C_SHT: + case _C_USHT: + case _C_INT: + case _C_UINT: + case _C_LNG: + case _C_ULNG: + case _C_LNG_LNG: + case _C_ULNG_LNG: + case _C_FLT: + case _C_DBL: + case _C_VOID: + case _C_UNDEF: + return ++type; + break; + + case _C_ARY_B: + /* skip digits, typespec and closing ']' */ + + while (isdigit ((unsigned char)*++type)) + ; + type = objc_skip_typespec (type); + if (*type == _C_ARY_E) + return ++type; + else + break; /* error */ + + case _C_BFLD: + /* The NeXT encoding for bitfields is _still_: b 'size' */ + while (isdigit ((unsigned char)*++type)) + ; /* skip type and size */ + return type; + + case _C_STRUCT_B: + /* skip name, and elements until closing '}' */ + + while (*type != _C_STRUCT_E && *type++ != '=') + ; + while (*type != _C_STRUCT_E) + { + type = objc_skip_typespec (type); + } + return ++type; + + case _C_UNION_B: + /* skip name, and elements until closing ')' */ + + while (*type != _C_UNION_E && *type++ != '=') + ; + while (*type != _C_UNION_E) + { + type = objc_skip_typespec (type); + } + return ++type; + + case _C_PTR: + /* Just skip the following typespec */ + + return objc_skip_typespec (++type); + } + return 0; /* error */ +} + +/* + Skip an offset as part of a method encoding. This is prepended by a + '+' if the argument is passed in registers. +*/ +inline const char * +objc_skip_offset (const char *type) +{ + if (*type == '+') + type++; + while (isdigit ((unsigned char) *++type)) + ; + return type; +} + +/* + Skip an argument specification of a method encoding. +*/ +const char * +objc_skip_argspec (const char *type) +{ + type = objc_skip_typespec (type); + type = objc_skip_offset (type); + return type; +} + +/* + Return the number of arguments that the method MTH expects. + Note that all methods need two implicit arguments `self' and + `_cmd'. +*/ +int +method_get_number_of_arguments (struct objc_method *mth) +{ + int i = 0; + const char *type = mth->method_types; + while (*type) + { + type = objc_skip_argspec (type); + i += 1; + } + return i - 1; +} + +/* + Return the size of the argument block needed on the stack to invoke + the method MTH. This may be zero, if all arguments are passed in + registers. +*/ + +int +method_get_sizeof_arguments (struct objc_method *mth) +{ + const char *type = objc_skip_typespec (mth->method_types); + return atoi (type); +} + +/* + Return a pointer to the next argument of ARGFRAME. type points to + the last argument. Typical use of this look like: + + { + char *datum, *type; + for (datum = method_get_first_argument (method, argframe, &type); + datum; datum = method_get_next_argument (argframe, &type)) + { + unsigned flags = objc_get_type_qualifiers (type); + type = objc_skip_type_qualifiers (type); + if (*type != _C_PTR) + [portal encodeData: datum ofType: type]; + else + { + if ((flags & _F_IN) == _F_IN) + [portal encodeData: *(char **) datum ofType: ++type]; + } + } + } +*/ + +char * +method_get_next_argument (arglist_t argframe, const char **type) +{ + const char *t = objc_skip_argspec (*type); + + if (*t == '\0') + return 0; + + *type = t; + t = objc_skip_typespec (t); + + if (*t == '+') + return argframe->arg_regs + atoi (++t); + else + return argframe->arg_ptr + atoi (t); +} + +/* + Return a pointer to the value of the first argument of the method + described in M with the given argumentframe ARGFRAME. The type + is returned in TYPE. type must be passed to successive calls of + method_get_next_argument. +*/ +char * +method_get_first_argument (struct objc_method *m, + arglist_t argframe, + const char **type) +{ + *type = m->method_types; + return method_get_next_argument (argframe, type); +} + +/* + Return a pointer to the ARGth argument of the method + M from the frame ARGFRAME. The type of the argument + is returned in the value-result argument TYPE +*/ + +char * +method_get_nth_argument (struct objc_method *m, + arglist_t argframe, int arg, + const char **type) +{ + const char *t = objc_skip_argspec (m->method_types); + + if (arg > method_get_number_of_arguments (m)) + return 0; + + while (arg--) + t = objc_skip_argspec (t); + + *type = t; + t = objc_skip_typespec (t); + + if (*t == '+') + return argframe->arg_regs + atoi (++t); + else + return argframe->arg_ptr + atoi (t); +} + +unsigned +objc_get_type_qualifiers (const char *type) +{ + unsigned res = 0; + BOOL flag = YES; + + while (flag) + switch (*type++) + { + case _C_CONST: res |= _F_CONST; break; + case _C_IN: res |= _F_IN; break; + case _C_INOUT: res |= _F_INOUT; break; + case _C_OUT: res |= _F_OUT; break; + case _C_BYCOPY: res |= _F_BYCOPY; break; + case _C_BYREF: res |= _F_BYREF; break; + case _C_ONEWAY: res |= _F_ONEWAY; break; + case _C_GCINVISIBLE: res |= _F_GCINVISIBLE; break; + default: flag = NO; + } + + return res; +} + + +/* The following three functions can be used to determine how a + structure is laid out by the compiler. For example: + + struct objc_struct_layout layout; + int i; + + objc_layout_structure (type, &layout); + while (objc_layout_structure_next_member (&layout)) + { + int position, align; + const char *type; + + objc_layout_structure_get_info (&layout, &position, &align, &type); + printf ("element %d has offset %d, alignment %d\n", + i++, position, align); + } + + These functions are used by objc_sizeof_type and objc_alignof_type + functions to compute the size and alignment of structures. The + previous method of computing the size and alignment of a structure + was not working on some architectures, particulary on AIX, and in + the presence of bitfields inside the structure. */ +void +objc_layout_structure (const char *type, + struct objc_struct_layout *layout) +{ + const char *ntype; + + layout->original_type = ++type; + + /* Skip "<name>=" if any. Avoid embedded structures and unions. */ + ntype = type; + while (*ntype != _C_STRUCT_E && *ntype != _C_STRUCT_B && *ntype != _C_UNION_B + && *ntype++ != '=') + /* do nothing */; + + /* If there's a "<name>=", ntype - 1 points to '='; skip the the name */ + if (*(ntype - 1) == '=') + type = ntype; + + layout->type = type; + layout->prev_type = NULL; + layout->record_size = 0; + layout->record_align = MAX (BITS_PER_UNIT, STRUCTURE_SIZE_BOUNDARY); +} + + +BOOL +objc_layout_structure_next_member (struct objc_struct_layout *layout) +{ + register int desired_align = 0; + + /* The current type without the type qualifiers */ + const char *type; + + /* Add the size of the previous field to the size of the record. */ + if (layout->prev_type) + { + type = objc_skip_type_qualifiers (layout->prev_type); + + if (*type != _C_BFLD) + layout->record_size += objc_sizeof_type (type) * BITS_PER_UNIT; + else + layout->record_size += atoi (++type); + } + + if (*layout->type == _C_STRUCT_E) + return NO; + + /* Skip the variable name if any */ + if (*layout->type == '"') + { + for (layout->type++; *layout->type++ != '"';) + /* do nothing */; + } + + type = objc_skip_type_qualifiers (layout->type); + + desired_align = objc_alignof_type (type) * BITS_PER_UNIT; + + /* Record must have at least as much alignment as any field. + Otherwise, the alignment of the field within the record + is meaningless. */ + layout->record_align = MAX (layout->record_align, desired_align); + + if (*type == _C_BFLD) + { + int bfld_size = atoi (++type); + int int_align = __alignof__ (int) * BITS_PER_UNIT; + /* If this bitfield would traverse a word alignment boundary, push it out + to that boundary instead. */ + if (layout->record_size % int_align + && (layout->record_size / int_align + < (layout->record_size + bfld_size - 1) / int_align)) + layout->record_size = ROUND (layout->record_size, int_align); + } + else if (layout->record_size % desired_align != 0) + { + /* We need to skip space before this field. + Bump the cumulative size to multiple of field alignment. */ + layout->record_size = ROUND (layout->record_size, desired_align); + } + + /* Jump to the next field in record. */ + + layout->prev_type = layout->type; + layout->type = objc_skip_typespec (layout->type); /* skip component */ + + return YES; +} + + +void objc_layout_finish_structure (struct objc_struct_layout *layout, + unsigned int *size, + unsigned int *align) +{ + if (layout->type && *layout->type == _C_STRUCT_E) + { + /* Round the size up to be a multiple of the required alignment */ + layout->record_size = ROUND (layout->record_size, layout->record_align); + layout->type = NULL; + } + if (size) + *size = layout->record_size / BITS_PER_UNIT; + if (align) + *align = layout->record_align / BITS_PER_UNIT; +} + + +void objc_layout_structure_get_info (struct objc_struct_layout *layout, + unsigned int *offset, + unsigned int *align, + const char **type) +{ + if (offset) + *offset = layout->record_size / BITS_PER_UNIT; + if (align) + *align = layout->record_align / BITS_PER_UNIT; + if (type) + *type = layout->prev_type; +} + +#endif /* #ifdef __NEXT_RUNTIME__ */ diff --git a/gcc/testsuite/objc/execute/np-2.m b/gcc/testsuite/objc/execute/np-2.m index 37cf6dd..85aa203 100644 --- a/gcc/testsuite/objc/execute/np-2.m +++ b/gcc/testsuite/objc/execute/np-2.m @@ -17,6 +17,9 @@ { printf ("methodA\n"); } +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end int main (void) diff --git a/gcc/testsuite/objc/execute/object_is_class.m b/gcc/testsuite/objc/execute/object_is_class.m index a053434..87deb98 100644 --- a/gcc/testsuite/objc/execute/object_is_class.m +++ b/gcc/testsuite/objc/execute/object_is_class.m @@ -3,6 +3,8 @@ #include <objc/objc-api.h> #include <objc/Object.h> +#include "next_mapping.h" + /* This test demonstrate a failure in object_is_class which was fixed */ /* Create a class whose instance variables mirror the struct used for diff --git a/gcc/testsuite/objc/execute/object_is_meta_class.m b/gcc/testsuite/objc/execute/object_is_meta_class.m index 90cd3a9..aeb129e 100644 --- a/gcc/testsuite/objc/execute/object_is_meta_class.m +++ b/gcc/testsuite/objc/execute/object_is_meta_class.m @@ -3,6 +3,8 @@ #include <objc/objc-api.h> #include <objc/Object.h> +#include "next_mapping.h" + /* This test demonstrate a failure in object_is_meta_class which was fixed */ @interface EvilClass : Object diff --git a/gcc/testsuite/objc/execute/redefining_self.m b/gcc/testsuite/objc/execute/redefining_self.m index 93659db..ddb2eb2 100644 --- a/gcc/testsuite/objc/execute/redefining_self.m +++ b/gcc/testsuite/objc/execute/redefining_self.m @@ -17,6 +17,9 @@ return self; } +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end diff --git a/gcc/testsuite/objc/execute/root_methods.m b/gcc/testsuite/objc/execute/root_methods.m index 4f2c2fa..c18ceb0 100644 --- a/gcc/testsuite/objc/execute/root_methods.m +++ b/gcc/testsuite/objc/execute/root_methods.m @@ -1,6 +1,8 @@ /* Contributed by Nicola Pero - Thu Mar 8 16:27:46 CET 2001 */ #include <objc/objc.h> +#include "next_mapping.h" + /* Test that instance methods of root classes are available as class methods to other classes as well */ @@ -16,6 +18,9 @@ { return self; } +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end @interface NormalClass : RootClass diff --git a/gcc/testsuite/objc/execute/static-1.m b/gcc/testsuite/objc/execute/static-1.m index 761e707..a778b72 100644 --- a/gcc/testsuite/objc/execute/static-1.m +++ b/gcc/testsuite/objc/execute/static-1.m @@ -19,6 +19,9 @@ static int test = 1; return test; } +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end int main (void) diff --git a/gcc/testsuite/objc/execute/static-2.m b/gcc/testsuite/objc/execute/static-2.m index 52a03a8..4d7e744 100644 --- a/gcc/testsuite/objc/execute/static-2.m +++ b/gcc/testsuite/objc/execute/static-2.m @@ -22,6 +22,9 @@ static int test (void) return test (); } +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end int main (void) diff --git a/gcc/testsuite/objc/execute/string1.m b/gcc/testsuite/objc/execute/string1.m index fff03c7..58a603c 100644 --- a/gcc/testsuite/objc/execute/string1.m +++ b/gcc/testsuite/objc/execute/string1.m @@ -2,7 +2,12 @@ #include <string.h> #include <stdlib.h> + +#ifdef __NEXT_RUNTIME__ +#import <Foundation/NSString.h> +#else #include <objc/NXConstStr.h> +#endif int main(int argc, void **args) { diff --git a/gcc/testsuite/objc/execute/string2.m b/gcc/testsuite/objc/execute/string2.m index 66462b3..01fb85c 100644 --- a/gcc/testsuite/objc/execute/string2.m +++ b/gcc/testsuite/objc/execute/string2.m @@ -2,7 +2,12 @@ #include <string.h> #include <stdlib.h> + +#ifdef __NEXT_RUNTIME__ +#import <Foundation/NSString.h> +#else #include <objc/NXConstStr.h> +#endif int main(int argc, void **args) { diff --git a/gcc/testsuite/objc/execute/string3.m b/gcc/testsuite/objc/execute/string3.m index 21527dc..a8d2969 100644 --- a/gcc/testsuite/objc/execute/string3.m +++ b/gcc/testsuite/objc/execute/string3.m @@ -2,7 +2,12 @@ #include <string.h> #include <stdlib.h> + +#ifdef __NEXT_RUNTIME__ +#import <Foundation/NSString.h> +#else #include <objc/NXConstStr.h> +#endif #define STRING "this is a string" diff --git a/gcc/testsuite/objc/execute/string4.m b/gcc/testsuite/objc/execute/string4.m index 54550d6..16025cb 100644 --- a/gcc/testsuite/objc/execute/string4.m +++ b/gcc/testsuite/objc/execute/string4.m @@ -2,7 +2,12 @@ #include <string.h> #include <stdlib.h> + +#ifdef __NEXT_RUNTIME__ +#import <Foundation/NSString.h> +#else #include <objc/NXConstStr.h> +#endif int main(int argc, void **args) { diff --git a/gcc/testsuite/objc/execute/va_method.m b/gcc/testsuite/objc/execute/va_method.m index bcf43d2..51619b8 100644 --- a/gcc/testsuite/objc/execute/va_method.m +++ b/gcc/testsuite/objc/execute/va_method.m @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero - Thu Mar 8 16:27:46 CET 2001 */ #include <objc/objc.h> #include <objc/objc-api.h> +#include <stdarg.h> /* Test method with variable number of arguments */ @@ -31,6 +32,9 @@ return sum; } +#ifdef __NEXT_RUNTIME__ ++ initialize { return self; } +#endif @end int main (void) |