c-common.c (flag_objc_sjlj_exceptions): New.
authorRichard Henderson <rth@redhat.com>
Fri, 18 Jun 2004 01:20:53 +0000 (18:20 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Fri, 18 Jun 2004 01:20:53 +0000 (18:20 -0700)
* c-common.c (flag_objc_sjlj_exceptions): New.
* c-common.h (flag_objc_sjlj_exceptions): Declare.
* c-opts.c (c_common_handle_option): Set it.
(c_common_post_options): Handle interation of different
objective-c exception and runtime switches.
* c-decl.c (c_eh_initialized_p): New.
(finish_decl): Use it instead of local eh_initialized_p.
* c-parse.in (nested_function, notype_nested_function): Record
the result of compstmt.
(compstmt_or_error): Likewise.
(compstmt): Don't add_stmt the result.
(stmt): Don't return anything.  Rewrite objc try and sync rules.
(objc_try_stmt, objc_catch_list): Remove.
(objc_catch_block, objc_finally_block): Remove.
(objc_catch_prefix, objc_catch_clause, objc_opt_catch_list): New.
(objc_try_catch_clause, objc_finally_clause): New.
(objc_try_catch_stmt): Rewrite.
* c-tree.h (c_eh_initialized_p): Declare.
* c-opt (fobjc-sjlj-exceptions): New.
* except.c (output_function_exception_table): Don't call cgraph
on non-decls.
* objc/objc-act.c (UTAG_EXCDATA_VAR, UTAG_CAUGHTEXC_VAR,
UTAG_RETHROWEXC_VAR, UTAG_EVALONCE_VAR, struct val_stack,
catch_count_stack, exc_binding_stack, if_nesting_count,
blk_nesting_count, objc_enter_block, objc_exit_block,
objc_declare_variable, 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): Remove.
(objc_create_temporary_var, struct objc_try_context, cur_try_context,
objc_eh_runtime_type, objc_init_exceptions, objc_build_exc_ptr,
next_sjlj_build_try_exit, next_sjlj_build_enter_and_setjmp,
next_sjlj_build_exc_extract, next_sjlj_build_catch_list,
next_sjlj_build_try_catch_finally, objc_begin_try_stmt,
objc_begin_catch_clause, objc_finish_catch_clause,
objc_build_finally_clause, objc_finish_try_stmt,
objc_build_synchronized): New.
(objc_is_object_id, objc_is_class_id): New.
(objc_comptypes): Use them.
(build_next_objc_exception_stuff): Break NeXT sjlj out from
build_objc_exception_stuff.
(synth_module_prologue): Update to match.
(objc_build_throw_stmt): Use cur_try_context to decide if
we're in a @catch.
* objc/objc-act.h: Update prototypes.
(OCTI_EXCEPTION_BLK_STACK, objc_exception_block_stack): Remove.
testsuite/
        * objc.dg/sync-1.m: New.
        * objc.dg/try-catch-1.m: Don't force next runtime.
        * objc.dg/try-catch-3.m, objc.dg/try-catch-4.m: Likewise.
        * objc.dg/try-catch-2.m: Likewise.  Enable everywhere.  Remove
        shadowed catch clause.
        * objc.dg/try-catch-5.m: New.

From-SVN: r83332

18 files changed:
gcc/ChangeLog
gcc/c-common.c
gcc/c-common.h
gcc/c-decl.c
gcc/c-opts.c
gcc/c-parse.in
gcc/c-tree.h
gcc/c.opt
gcc/except.c
gcc/objc/objc-act.c
gcc/objc/objc-act.h
gcc/testsuite/ChangeLog
gcc/testsuite/objc.dg/sync-1.m [new file with mode: 0644]
gcc/testsuite/objc.dg/try-catch-1.m
gcc/testsuite/objc.dg/try-catch-2.m
gcc/testsuite/objc.dg/try-catch-3.m
gcc/testsuite/objc.dg/try-catch-4.m
gcc/testsuite/objc.dg/try-catch-5.m [new file with mode: 0644]

index 01099dc2b25ea13cf7c95b5a40d0a993b9c650c4..b1c4f8d8b410723fad80e4c1a33973473a1fc53b 100644 (file)
@@ -1,3 +1,56 @@
+2004-06-17  Richard Henderson  <rth@redhat.com>
+
+       * c-common.c (flag_objc_sjlj_exceptions): New.
+       * c-common.h (flag_objc_sjlj_exceptions): Declare.
+       * c-opts.c (c_common_handle_option): Set it.
+       (c_common_post_options): Handle interation of different
+       objective-c exception and runtime switches.
+       * c-decl.c (c_eh_initialized_p): New.
+       (finish_decl): Use it instead of local eh_initialized_p.
+       * c-parse.in (nested_function, notype_nested_function): Record
+       the result of compstmt.
+       (compstmt_or_error): Likewise.
+       (compstmt): Don't add_stmt the result.
+       (stmt): Don't return anything.  Rewrite objc try and sync rules.
+       (objc_try_stmt, objc_catch_list): Remove.
+       (objc_catch_block, objc_finally_block): Remove.
+       (objc_catch_prefix, objc_catch_clause, objc_opt_catch_list): New.
+       (objc_try_catch_clause, objc_finally_clause): New.
+       (objc_try_catch_stmt): Rewrite.
+       * c-tree.h (c_eh_initialized_p): Declare.
+       * c-opt (fobjc-sjlj-exceptions): New.
+       * except.c (output_function_exception_table): Don't call cgraph
+       on non-decls.
+       * objc/objc-act.c (UTAG_EXCDATA_VAR, UTAG_CAUGHTEXC_VAR,
+       UTAG_RETHROWEXC_VAR, UTAG_EVALONCE_VAR, struct val_stack,
+       catch_count_stack, exc_binding_stack, if_nesting_count,
+       blk_nesting_count, objc_enter_block, objc_exit_block,
+       objc_declare_variable, 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): Remove.
+       (objc_create_temporary_var, struct objc_try_context, cur_try_context,
+       objc_eh_runtime_type, objc_init_exceptions, objc_build_exc_ptr,
+       next_sjlj_build_try_exit, next_sjlj_build_enter_and_setjmp,
+       next_sjlj_build_exc_extract, next_sjlj_build_catch_list,
+       next_sjlj_build_try_catch_finally, objc_begin_try_stmt,
+       objc_begin_catch_clause, objc_finish_catch_clause,
+       objc_build_finally_clause, objc_finish_try_stmt,
+       objc_build_synchronized): New.
+       (objc_is_object_id, objc_is_class_id): New.
+       (objc_comptypes): Use them.
+       (build_next_objc_exception_stuff): Break NeXT sjlj out from
+       build_objc_exception_stuff.
+       (synth_module_prologue): Update to match.
+       (objc_build_throw_stmt): Use cur_try_context to decide if
+       we're in a @catch.
+       * objc/objc-act.h: Update prototypes.
+       (OCTI_EXCEPTION_BLK_STACK, objc_exception_block_stack): Remove.
+
 2004-06-17  Andrew Pinski <apinski@apple.com>
 
        * c-typeck.c (tagged_types_tu_compatible_p <case UNION_TYPE>):
index ac439e5848537d9ca7cbe042965d413f77224666..d25dde3a3297a68a209c4db91574e14de650532b 100644 (file)
@@ -361,6 +361,9 @@ int flag_nil_receivers = 1;
    @try, etc.) in source code.  */
 int flag_objc_exceptions = 0;
 
+/* Nonzero means that we generate NeXT setjmp based exceptions.  */
+int flag_objc_sjlj_exceptions = -1;
+
 /* 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.  */
index 2f661538e4675c55a7e2dbf6a7bab29b49eb01fb..337eb6d83d1b1b03d666118705e8710daffb9e82 100644 (file)
@@ -321,6 +321,9 @@ extern int flag_nil_receivers;
    @try, etc.) in source code.  */
 extern int flag_objc_exceptions;
 
+/* Nonzero means that we generate NeXT setjmp based exceptions.  */
+extern int flag_objc_sjlj_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.  */
index f8d5f588e4d6e22c7648b84e302cdd0700d7f561..ac8c5b7847d8694e8348676140a80bb9de5bd837 100644 (file)
@@ -71,11 +71,14 @@ enum decl_context
 \f
 /* Nonzero if we have seen an invalid cross reference
    to a struct, union, or enum, but not yet printed the message.  */
-
 tree pending_invalid_xref;
+
 /* File and line to appear in the eventual error message.  */
 location_t pending_invalid_xref_location;
 
+/* True means we've initialized exception handling.  */
+bool c_eh_initialized_p;
+
 /* While defining an enum type, this is 1 plus the last enumerator
    constant value.  Note that will do not have to save this or `enum_overflow'
    around nested function definition since such a definition could only
@@ -2982,8 +2985,6 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
       tree attr = lookup_attribute ("cleanup", DECL_ATTRIBUTES (decl));
       if (attr)
        {
-         static bool eh_initialized_p;
-
          tree cleanup_id = TREE_VALUE (TREE_VALUE (attr));
          tree cleanup_decl = lookup_name (cleanup_id);
          tree cleanup;
@@ -2998,9 +2999,9 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
          TREE_USED (cleanup_decl) = 1;
 
          /* Initialize EH, if we've been told to do so.  */
-         if (flag_exceptions && !eh_initialized_p)
+         if (flag_exceptions && !c_eh_initialized_p)
            {
-             eh_initialized_p = true;
+             c_eh_initialized_p = true;
              eh_personality_libfunc
                = init_one_libfunc (USING_SJLJ_EXCEPTIONS
                                    ? "__gcc_personality_sj0"
index b9c462a1230dd24df7e369718c20ed1fd4c6913b..8025cd7897cfff5f0ed9682c00e0165ec3385c62 100644 (file)
@@ -863,6 +863,10 @@ c_common_handle_option (size_t scode, const char *arg, int value)
       flag_objc_exceptions = value;
       break;
 
+    case OPT_fobjc_sjlj_exceptions:
+      flag_objc_sjlj_exceptions = value;
+      break;
+
     case OPT_foperator_names:
       cpp_opts->operator_names = value;
       break;
@@ -1109,6 +1113,12 @@ c_common_post_options (const char **pfilename)
       flag_inline_functions = 0;
     }
 
+  /* Default to ObjC sjlj exception handling if NeXT runtime.  */
+  if (flag_objc_sjlj_exceptions < 0)
+    flag_objc_sjlj_exceptions = flag_next_runtime;
+  if (flag_objc_exceptions && !flag_objc_sjlj_exceptions)
+    flag_exceptions = 1;
+
   /* -Wextra implies -Wsign-compare, but not if explicitly
       overridden.  */
   if (warn_sign_compare == -1)
index 118573ced5fe6ec2412a6bacd03dc242ad46614a..d3e39af6858583f1a3d2e286f6a69f4b9315bf8e 100644 (file)
@@ -251,7 +251,6 @@ do {                                                                        \
 %type <ttype> CLASSNAME OBJECTNAME OBJC_STRING
 
 %type <ttype> superclass
-%type <itype> objc_try_catch_stmt objc_finally_block
 @@end_ifobjc
 \f
 %{
@@ -1515,7 +1514,7 @@ designator:
        ;
 \f
 nested_function:
-         declarator
+       declarator
                { if (pedantic)
                    pedwarn ("ISO C forbids nested functions");
 
@@ -1527,25 +1526,25 @@ nested_function:
                      YYERROR1;
                    }
                }
-          old_style_parm_decls save_location
+       old_style_parm_decls save_location
                { tree decl = current_function_decl;
                  DECL_SOURCE_LOCATION (decl) = $4;
                  store_parm_decls (); }
-/* This used to use compstmt_or_error.
-   That caused a bug with input `f(g) int g {}',
-   where the use of YYERROR1 above caused an error
-   which then was handled by compstmt_or_error.
-   There followed a repeated execution of that same rule,
-   which called YYERROR1 again, and so on.  */
-         compstmt
+       /* This used to use compstmt_or_error.  That caused a bug with
+          input `f(g) int g {}', where the use of YYERROR1 above caused
+          an error which then was handled by compstmt_or_error.  There
+          followed a repeated execution of that same rule, which called
+          YYERROR1 again, and so on.  */
+       compstmt
                { tree decl = current_function_decl;
+                 add_stmt ($6);
                  finish_function ();
                  pop_function_context ();
                  add_decl_stmt (decl); }
        ;
 
 notype_nested_function:
-         notype_declarator
+       notype_declarator
                { if (pedantic)
                    pedwarn ("ISO C forbids nested functions");
 
@@ -1557,18 +1556,18 @@ notype_nested_function:
                      YYERROR1;
                    }
                }
-         old_style_parm_decls save_location
+       old_style_parm_decls save_location
                { tree decl = current_function_decl;
                  DECL_SOURCE_LOCATION (decl) = $4;
                  store_parm_decls (); }
-/* This used to use compstmt_or_error.
-   That caused a bug with input `f(g) int g {}',
-   where the use of YYERROR1 above caused an error
-   which then was handled by compstmt_or_error.
-   There followed a repeated execution of that same rule,
-   which called YYERROR1 again, and so on.  */
-         compstmt
+       /* This used to use compstmt_or_error.  That caused a bug with
+          input `f(g) int g {}', where the use of YYERROR1 above caused
+          an error which then was handled by compstmt_or_error.  There
+          followed a repeated execution of that same rule, which called
+          YYERROR1 again, and so on.  */
+       compstmt
                { tree decl = current_function_decl;
+                 add_stmt ($6);
                  finish_function ();
                  pop_function_context ();
                  add_decl_stmt (decl); }
@@ -2029,7 +2028,7 @@ label_decl:
    It causes syntax errors to ignore to the next openbrace.  */
 compstmt_or_error:
          compstmt
-               {}
+               { add_stmt ($1); }
        | error compstmt
        ;
 
@@ -2060,8 +2059,7 @@ compstmt_primary_start:
         ;
 
 compstmt: compstmt_start compstmt_nostart
-               { add_stmt (c_end_compound_stmt ($1, true));
-                 $$ = NULL_TREE; }
+               { $$ = c_end_compound_stmt ($1, true); }
        ;
 
 if_prefix:
@@ -2226,37 +2224,27 @@ xexpr:
 /* Parse a single real statement, not including any labels.  */
 stmt:
          compstmt
-               { stmt_count++; $$ = $1; }
+               { stmt_count++; add_stmt ($1); }
        | expr ';'
-               { stmt_count++;
-                 $$ = c_expand_expr_stmt ($1); }
+               { stmt_count++; c_expand_expr_stmt ($1); }
        | c99_block_start select_or_iter_stmt
-                { add_stmt (c_end_compound_stmt ($1, flag_isoc99));
-                 $$ = NULL_TREE; }
+                { add_stmt (c_end_compound_stmt ($1, flag_isoc99)); }
        | BREAK ';'
                { stmt_count++;
                  if (!(c_in_iteration_stmt || c_in_case_stmt))
-                   {
-                     error ("break statement not within loop or switch");
-                     $$ = NULL_TREE;
-                   }
+                   error ("break statement not within loop or switch");
                  else
-                   $$ = add_stmt (build_break_stmt ()); }
+                   add_stmt (build_break_stmt ()); }
        | CONTINUE ';'
                 { stmt_count++;
                  if (!c_in_iteration_stmt)
-                   {
-                     error ("continue statement not within a loop");
-                     $$ = NULL_TREE;
-                   }
+                   error ("continue statement not within a loop");
                  else
-                   $$ = add_stmt (build_continue_stmt ()); }
+                   add_stmt (build_continue_stmt ()); }
        | RETURN ';'
-                { stmt_count++;
-                 $$ = c_expand_return (NULL_TREE); }
+                { stmt_count++; c_expand_return (NULL_TREE); }
        | RETURN expr ';'
-                { stmt_count++;
-                 $$ = c_expand_return ($2); }
+                { stmt_count++; c_expand_return ($2); }
        | asm_stmt
        | GOTO identifier ';'
                { tree decl;
@@ -2265,71 +2253,61 @@ stmt:
                  if (decl != 0)
                    {
                      TREE_USED (decl) = 1;
-                     $$ = add_stmt (build_stmt (GOTO_EXPR, decl));
+                     add_stmt (build_stmt (GOTO_EXPR, decl));
                    }
-                 else
-                   $$ = NULL_TREE;
                }
        | GOTO '*' expr ';'
                { if (pedantic)
                    pedwarn ("ISO C forbids `goto *expr;'");
                  stmt_count++;
                  $3 = convert (ptr_type_node, $3);
-                 $$ = add_stmt (build_stmt (GOTO_EXPR, $3)); }
+                 add_stmt (build_stmt (GOTO_EXPR, $3)); }
        | ';'
-               { $$ = NULL_TREE; }
+               { }
 @@ifobjc
        | AT_THROW expr ';'
-               { stmt_count++;
-                 $$ = objc_build_throw_stmt ($2);
-               }
+               { stmt_count++; objc_build_throw_stmt ($2); }
        | AT_THROW ';'
-               { stmt_count++;
-                 $$ = objc_build_throw_stmt (NULL_TREE);
-               }
+               { 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 (); }
+               { }
+       | AT_SYNCHRONIZED '(' expr ')' save_location compstmt
+               { stmt_count++; objc_build_synchronized ($5, $3, $6); }
        ;
 
-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_catch_prefix:
+       AT_CATCH '(' parm ')'
+               { objc_begin_catch_clause ($3); }
        ;
 
+objc_catch_clause:
+         objc_catch_prefix '{' compstmt_nostart
+               { objc_finish_catch_clause (); }
+       | objc_catch_prefix '{' error '}'
+               { objc_finish_catch_clause (); }
+       ;
 
-objc_try_stmt:
-         AT_TRY
-               { objc_build_try_prologue (); }
-         compstmt
+objc_opt_catch_list:
+         /* empty */
+       | objc_opt_catch_list objc_catch_clause
        ;
 
-objc_catch_list:
-         objc_catch_list objc_catch_block
-       | objc_catch_block
+objc_try_catch_clause:
+       AT_TRY save_location compstmt
+               { stmt_count++; objc_begin_try_stmt ($2, $3); }
+       objc_opt_catch_list
        ;
 
-objc_catch_block:
-         AT_CATCH '(' parm ')'
-               { objc_build_catch_stmt ($3); }
-         compstmt
-               { stmt_count++; }
+objc_finally_clause:
+       AT_FINALLY save_location compstmt
+               { objc_build_finally_clause ($2, $3); }
        ;
 
-objc_finally_block:
-         AT_FINALLY compstmt
-           { $$ = 1; }
-       | /* NULL */
-           { $$ = 0; }
+objc_try_catch_stmt:
+         objc_try_catch_clause
+               { objc_finish_try_stmt (); }
+       | objc_try_catch_clause objc_finally_clause
+               { objc_finish_try_stmt (); }
 @@end_ifobjc
        ;
 
index a3f6ad1eb12b1c51c55cf6e7cdcfaf1513bfd798..92a5b7144784abb0b95734e2dda568e9dd1a36e1 100644 (file)
@@ -298,6 +298,9 @@ extern int system_header_p;
 
 extern bool c_override_global_bindings_to_false;
 
+/* True means we've initialized exception handling.  */
+extern bool c_eh_initialized_p;
+
 /* In c-decl.c */
 extern void c_finish_incomplete_decl (tree);
 extern void *get_current_scope (void);
index 9f3e79a049391bac87c93134bf26ccd59add4209..f162803009024b9ec6db5792283aaeda9cdbf928 100644 (file)
--- a/gcc/c.opt
+++ b/gcc/c.opt
@@ -584,6 +584,10 @@ fobjc-exceptions
 ObjC ObjC++
 Enable Objective-C exception and synchronization syntax
 
+fobjc-sjlj-exceptions
+ObjC ObjC++
+Enable Objective-C setjmp exception handling runtime
+
 foperator-names
 C++ ObjC++
 Recognize C++ kewords like \"compl\" and \"xor\"
index 3e663dbff8af8b6f6bb4562b66ed3ebef89c4faf..21ade90cb60d46ddd681086e1b0be6911f3c4f91 100644 (file)
@@ -4085,9 +4085,12 @@ output_function_exception_table (void)
          if (TREE_CODE (type) == ADDR_EXPR)
            {
              type = TREE_OPERAND (type, 0);
-             node = cgraph_varpool_node (type);
-             if (node)
-               cgraph_varpool_mark_needed_node (node);
+             if (TREE_CODE (type) == VAR_DECL)
+               {
+                 node = cgraph_varpool_node (type);
+                 if (node)
+                   cgraph_varpool_mark_needed_node (node);
+               }
            }
          else if (TREE_CODE (type) != INTEGER_CST)
            abort ();
index 8946bd02cc1d9e8d9c79c94d2ecb4d08dcb53c58..c2cfa4d6fe18c3d58e37660e91da000d6b5d9014 100644 (file)
@@ -63,6 +63,8 @@ Boston, MA 02111-1307, USA.  */
 #include "target.h"
 #include "diagnostic.h"
 #include "cgraph.h"
+#include "tree-iterator.h"
+#include "libfuncs.h"
 
 /* This is the default way of generating a method name.  */
 /* I am not sure it is really correct.
@@ -134,13 +136,7 @@ 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 void build_next_objc_exception_stuff (void);
 
 static tree build_ivar_template (void);
 static tree build_method_template (void);
@@ -365,23 +361,6 @@ static const char *default_constant_string_class_name;
 #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];
@@ -626,6 +605,20 @@ lookup_protocol_in_reflist (tree rproto_list, tree lproto)
   return 0;
 }
 
+/* Return true if TYPE is 'id'.  */
+
+static bool
+objc_is_object_id (tree type)
+{
+  return OBJC_TYPE_NAME (type) == objc_object_id;
+}
+
+static bool
+objc_is_class_id (tree type)
+{
+  return OBJC_TYPE_NAME (type) == objc_class_id;
+}
+
 /* Return 1 if LHS and RHS are compatible types for assignment or
    various other operations.  Return 0 if they are incompatible, and
    return -1 if we choose to not decide (because the types are really
@@ -777,12 +770,12 @@ objc_comptypes (tree lhs, tree rhs, int reflexive)
              return 1;
            }
          /* <Protocol> = id */
-         else if (OBJC_TYPE_NAME (TREE_TYPE (rhs)) == objc_object_id)
+         else if (objc_is_object_id (TREE_TYPE (rhs)))
            {
              return 1;
            }
          /* <Protocol> = Class */
-         else if (OBJC_TYPE_NAME (TREE_TYPE (rhs)) == objc_class_id)
+         else if (objc_is_class_id (TREE_TYPE (rhs)))
            {
              return 0;
            }
@@ -854,12 +847,12 @@ objc_comptypes (tree lhs, tree rhs, int reflexive)
                return 0;
            }
          /* id = <Protocol> */
-         else if (OBJC_TYPE_NAME (TREE_TYPE (lhs)) == objc_object_id)
+         else if (objc_is_object_id (TREE_TYPE (lhs)))
            {
              return 1;
            }
          /* Class = <Protocol> */
-         else if (OBJC_TYPE_NAME (TREE_TYPE (lhs)) == objc_class_id)
+         else if (objc_is_class_id (TREE_TYPE (lhs)))
            {
              return 0;
            }
@@ -892,16 +885,14 @@ objc_comptypes (tree lhs, tree rhs, int reflexive)
      'Object *o = [[Object alloc] init]; falls
      in the case <class> * = `id'.
   */
-  if ((OBJC_TYPE_NAME (lhs) == objc_object_id && TYPED_OBJECT (rhs))
-      || (OBJC_TYPE_NAME (rhs) == objc_object_id && TYPED_OBJECT (lhs)))
+  if ((objc_is_object_id (lhs) && TYPED_OBJECT (rhs))
+      || (objc_is_object_id (rhs) && TYPED_OBJECT (lhs)))
     return 1;
 
   /* `id' = `Class', `Class' = `id' */
 
-  else if ((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))
+  else if ((objc_is_object_id (lhs) && objc_is_class_id (rhs))
+          || (objc_is_class_id (lhs) && objc_is_object_id (rhs)))
     return 1;
 
   /* `Class' != `<class> *' && `<class> *' != `Class'!  */
@@ -1273,8 +1264,9 @@ synth_module_prologue (void)
     = builtin_function (TAG_GETMETACLASS, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE);
 
   build_super_template ();
+  build_objc_exception_stuff ();
   if (flag_next_runtime)
-    build_objc_exception_stuff ();
+    build_next_objc_exception_stuff ();
 
   /* static SEL _OBJC_SELECTOR_TABLE[]; */
 
@@ -2682,563 +2674,561 @@ get_class_ivars (tree interface, int raw)
 }
 
 static tree
-objc_enter_block (void)
+objc_create_temporary_var (tree type)
 {
-  tree block;
-
-#ifdef OBJCPLUS
-  block = begin_compound_stmt (0);
-#else
-  block = c_begin_compound_stmt (1);
-#endif
-
-  objc_exception_block_stack = tree_cons (NULL_TREE, block,
-                                         objc_exception_block_stack);
+  tree decl;
+  decl = build_decl (VAR_DECL, NULL_TREE, type);
+  TREE_USED (decl) = 1;
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_IGNORED_P (decl) = 1;
+  DECL_CONTEXT (decl) = current_function_decl;
 
-  blk_nesting_count++;
-  return block;
+  return decl;
 }
+\f
+/* Exception handling constructs.  We begin by having the parser do most
+   of the work and passing us blocks.  What we do next depends on whether
+   we're doing "native" exception handling or legacy Darwin setjmp exceptions.
+   We abstract all of this in a handful of appropriately named routines.  */
 
-static tree
-objc_exit_block (void)
+/* Stack of open try blocks.  */
+
+struct objc_try_context
 {
-  tree block = TREE_VALUE (objc_exception_block_stack);
-  objc_exception_block_stack = TREE_CHAIN (objc_exception_block_stack);        
+  struct objc_try_context *outer;
 
-  objc_clear_super_receiver ();
-#ifdef OBJCPLUS
-  finish_compound_stmt (block);
-#else
-  block = c_end_compound_stmt (block, 1);
-#endif
+  /* Statements (or statement lists) as processed by the parser.  */
+  tree try_body;
+  tree finally_body;
 
-  blk_nesting_count--;
-  return block;
-}
+  /* Some file position locations.  */
+  location_t try_locus;
+  location_t end_try_locus;
+  location_t end_catch_locus;
+  location_t finally_locus;
+  location_t end_finally_locus;
+
+  /* A STATEMENT_LIST of CATCH_EXPRs, appropriate for sticking into op1
+     of a TRY_CATCH_EXPR.  Even when doing Darwin setjmp.  */
+  tree catch_list;
+
+  /* The CATCH_EXPR of an open @catch clause.  */
+  tree current_catch;
+
+  /* The VAR_DECL holding the Darwin equivalent of EXC_PTR_EXPR.  */
+  tree caught_decl;
+  tree stack_decl;
+  tree rethrow_decl;
+};
+
+static struct objc_try_context *cur_try_context;
+
+/* This hook, called via lang_eh_runtime_type, generates a runtime object
+   that represents TYPE.  For Objective-C, this is just the class name.  */
+/* ??? Isn't there a class object or some such?  Is it easy to get?  */
 
 static tree
-objc_declare_variable (enum rid scspec, tree name, tree type, tree init)
+objc_eh_runtime_type (tree type)
 {
-  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;
+  return add_objc_string (OBJC_TYPE_NAME (TREE_TYPE (type)), class_names);
 }
 
-tree
-objc_build_throw_stmt (tree throw_expr)
+/* Initialize exception handling.  */
+
+static void
+objc_init_exceptions (void)
 {
-  tree func_params;
+  static bool done = false;
+  if (done)
+    return;
+  done = true;
 
+  /* Why?  */
   if (!flag_objc_exceptions)
-    fatal_error ("Use `-fobjc-exceptions' to enable Objective-C exception syntax");
+    warning ("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)
+  if (!flag_objc_sjlj_exceptions)
     {
-      error ("`@throw;' (rethrow) used outside of a `@catch' block");
-      return error_mark_node;
+      c_eh_initialized_p = true;
+      eh_personality_libfunc
+       = init_one_libfunc (USING_SJLJ_EXCEPTIONS
+                           ? "__gnu_objc_personality_sj0"
+                           : "__gnu_objc_personality_v0");
+      using_eh_for_cleanups ();
+      lang_eh_runtime_type = objc_eh_runtime_type;
     }
-
-  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)
+/* Build an EXC_PTR_EXPR, or the moral equivalent.  In the case of Darwin,
+   we'll arrange for it to be initialized (and associated with a binding)
+   later.  */
+
+static tree
+objc_build_exc_ptr (void)
 {
-  struct val_stack *new_elem = xmalloc (sizeof (struct val_stack));
-  new_elem->val = val;
-  new_elem->next = *nc;
-  *nc = new_elem;
+  if (flag_objc_sjlj_exceptions)
+    {
+      tree var = cur_try_context->caught_decl;
+      if (!var)
+       {
+         var = objc_create_temporary_var (id_type);
+         cur_try_context->caught_decl = var;
+       }
+      return var;
+    }
+  else
+    return build (EXC_PTR_EXPR, id_type);
 }
 
-static void
-val_stack_pop (struct val_stack **nc)
+/* Build "objc_exception_try_exit(&_stack)".  */
+
+static tree
+next_sjlj_build_try_exit (void)
 {
-  struct val_stack *old_elem = *nc;
-  *nc = old_elem->next;
-  free (old_elem);
+  tree t;
+  t = build_fold_addr_expr (cur_try_context->stack_decl);
+  t = tree_cons (NULL, t, NULL);
+  t = build_function_call (objc_exception_try_exit_decl, t);
+  return t;
 }
 
-static void
-objc_build_try_enter_fragment (void)
+/* Build
+       objc_exception_try_enter (&_stack);
+       if (_setjmp(&_stack.buf))
+         ;
+       else
+         ;
+   Return the COND_EXPR.  Note that the THEN and ELSE fields are left
+   empty, ready for the caller to fill them in.  */
+
+static tree
+next_sjlj_build_enter_and_setjmp (void)
 {
-  /* objc_exception_try_enter(&_stackExceptionData);
-     if (!_setjmp(&_stackExceptionData.buf)) {  */
+  tree t, enter, sj, cond;
 
-  tree func_params, cond;
+  t = build_fold_addr_expr (cur_try_context->stack_decl);
+  t = tree_cons (NULL, t, NULL);
+  enter = build_function_call (objc_exception_try_enter_decl, t);
 
-  func_params
-    = tree_cons (NULL_TREE,
-                build_unary_op (ADDR_EXPR,
-                                TREE_VALUE (objc_stack_exception_data),
-                                0),
-                NULL_TREE);
+  t = build_component_ref (cur_try_context->stack_decl,
+                          get_identifier ("buf"));
+  t = build_fold_addr_expr (t);
+  t = convert (ptr_type_node, t);
+  t = tree_cons (NULL, t, NULL);
+  sj = build_function_call (objc_setjmp_decl, t);
 
-  assemble_external (objc_exception_try_enter_decl);
-  c_expand_expr_stmt (build_function_call
-                     (objc_exception_try_enter_decl, func_params));
+  cond = build (COMPOUND_EXPR, TREE_TYPE (sj), enter, sj);
+  cond = lang_hooks.truthvalue_conversion (cond);
 
-#ifdef OBJCPLUS
-  /* Um, C and C++ have very different statement construction functions.
-     Partly because different scoping rules are in effect, but partly 
-     because of how their parsers are constructed.  I highly recommend
-     simply constructing the statements by hand here.  You don't need
-     any of the ancilliary tracking necessary for user parsing bits anyway.  */
-#error
-#endif
-
-  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_finish_if_cond (cond, 0, 0);
-  objc_enter_block ();
+  return build (COND_EXPR, void_type_node, cond, NULL, NULL);
 }
 
+/* Build
+       DECL = objc_exception_extract(&_stack);
+*/
+   
 static tree
-objc_build_extract_expr (void)
+next_sjlj_build_exc_extract (tree decl)
 {
-  /*   ... = objc_exception_extract(&_stackExceptionData);  */
+  tree t;
 
-  tree func_params
-    = tree_cons (NULL_TREE,
-                build_unary_op (ADDR_EXPR,
-                                TREE_VALUE (objc_stack_exception_data), 0),
-                NULL_TREE);
+  t = build_fold_addr_expr (cur_try_context->stack_decl);
+  t = tree_cons (NULL, t, NULL);
+  t = build_function_call (objc_exception_extract_decl, t);
+  t = convert (TREE_TYPE (decl), t);
+  t = build (MODIFY_EXPR, void_type_node, decl, t);
 
-  assemble_external (objc_exception_extract_decl);
-  return build_function_call (objc_exception_extract_decl, func_params);
+  return t;
 }
 
-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));
-}
+/* Build
+       if (objc_exception_match(obj_get_class(TYPE), _caught)
+         BODY
+       else if (...)
+         ...
+       else
+         {
+           _rethrow = _caught;
+           objc_exception_try_exit(&_stack);
+         }
+   from the sequence of CATCH_EXPRs in the current try context.  */
 
-static void
-objc_build_extract_fragment (void)
+static tree
+next_sjlj_build_catch_list (void)
 {
-  /* } else {
-      _rethrowException = objc_exception_extract(&_stackExceptionData);
-     }  */
+  tree_stmt_iterator i = tsi_start (cur_try_context->catch_list);
+  tree catch_seq, t;
+  tree *last = &catch_seq;
+  bool saw_id = false;
 
-  c_finish_then (objc_exit_block ());
-
-  c_begin_else (0);
-  objc_enter_block ();
-  c_expand_expr_stmt (build_modify_expr
-                     (TREE_VALUE (objc_rethrow_exception),
-                      NOP_EXPR,
-                      objc_build_extract_expr ()));
-  c_finish_else (objc_exit_block ());
-  c_finish_if_stmt (1);
-  if_nesting_count--;
-}
+  for (; !tsi_end_p (i); tsi_next (&i))
+    {
+      tree stmt = tsi_stmt (i);
+      tree type = CATCH_TYPES (stmt);
+      tree body = CATCH_BODY (stmt);
 
-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)) {  */
+      if (type == NULL)
+       {
+         *last = body;
+         saw_id = true;
+         break;
+       }
+      else
+       {
+         tree args, cond;
 
-  tree try_catch_block;
+         if (type == error_mark_node)
+           cond = error_mark_node;
+         else
+           {
+             args = tree_cons (NULL, cur_try_context->caught_decl, NULL);
+             t = get_class_reference (OBJC_TYPE_NAME (TREE_TYPE (type)));
+             args = tree_cons (NULL, t, args);
+             t = build_function_call (objc_exception_match_decl, args);
+             cond = lang_hooks.truthvalue_conversion (t);
+           }
+         t = build (COND_EXPR, void_type_node, cond, body, NULL);
+         SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
 
-  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;
-}
+         *last = t;
+         last = &COND_EXPR_ELSE (t);
+       }
+    }
 
-void
-objc_build_try_epilogue (int also_catch_prologue)
-{
-  if (also_catch_prologue)
+  if (!saw_id)
     {
-      /* } else {
-          register id _caughtException = objc_exception_extract( &_stackExceptionData);
-          objc_exception_try_enter(&_stackExceptionData);
-          if(!_setjmp(&_stackExceptionData.buf)) {
-            if (0) {  */
+      t = build (MODIFY_EXPR, void_type_node, cur_try_context->rethrow_decl,
+                cur_try_context->caught_decl);
+      annotate_with_locus (t, cur_try_context->end_catch_locus);
+      append_to_statement_list (t, last);
 
-      c_finish_then (objc_exit_block ());
-               
-      c_begin_else (0);
-      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);
-      c_begin_if_stmt ();
-      if_nesting_count++;
-      c_finish_if_cond (boolean_false_node, 0, 0);
-      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);
+      t = next_sjlj_build_try_exit ();
+      annotate_with_locus (t, cur_try_context->end_catch_locus);
+      append_to_statement_list (t, last);
     }
-  else
-    {  /* !also_catch_prologue */
 
-      /* } else {
-          _rethrowException = objc_exception_extract( &_stackExceptionData);
-        }
-       }  */
-      objc_build_extract_fragment ();
-      objc_exit_block ();
-    }
+  return catch_seq;
 }
 
-void
-objc_build_catch_stmt (tree catch_expr)
-{
-  /* } else if (objc_exception_match(objc_get_class("SomeClass"), _caughtException)) {
-       register SomeClass *e = _caughtException;  */
-
-  tree cond, func_params, prev_catch, var_name, var_type;
-  int catch_id;
+/* Build a complete @try-@catch-@finally block for legacy Darwin setjmp
+   exception handling.  We aim to build:
 
-#ifndef OBJCPLUS
-  /* Yet another C/C++ impedance mismatch.  */
-  catch_expr = TREE_PURPOSE (catch_expr);
-#endif
+       {
+         struct _objc_exception_data _stack;
+         id volatile _rethrow = 0;
+         try
+           {
+             objc_exception_try_enter (&_stack);
+             if (_setjmp(&_stack.buf))
+               {
+                 id _caught = objc_exception_extract(&_stack);
+                 objc_exception_try_enter (&_stack);
+                 if (_setjmp(&_stack.buf))
+                   _rethrow = objc_exception_extract(&_stack);
+                 else
+                   CATCH-LIST
+               }
+             else
+               TRY-BLOCK
+           }
+         finally
+           {
+             if (!_rethrow)
+               objc_exception_try_exit(&_stack);
+             FINALLY-BLOCK
+             if (_rethrow)
+               objc_exception_throw(_rethrow);
+           }
+       }
 
-  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 CATCH-LIST is empty, we can omit all of the block containing
+   "_caught" except for the setting of _rethrow.  Note the use of
+   a real TRY_FINALLY_EXPR here, which is not involved in EH per-se,
+   but handles goto and other exits from the block.  */
 
-  if (!flag_objc_exceptions)
-    fatal_error ("Use `-fobjc-exceptions' to enable Objective-C exception syntax");
+static tree
+next_sjlj_build_try_catch_finally (void)
+{
+  tree rethrow_decl, stack_decl, t;
+  tree catch_seq, try_fin, bind;
 
-  if (!(catch_id || TYPED_OBJECT (var_type)))
-    fatal_error ("`@catch' parameter is not a known Objective-C class type");
+  /* Create the declarations involved.  */
+  t = xref_tag (RECORD_TYPE, get_identifier (UTAG_EXCDATA));
+  stack_decl = objc_create_temporary_var (t);
+  cur_try_context->stack_decl = stack_decl;
 
-  /* 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))));
-    }
+  rethrow_decl = objc_create_temporary_var (id_type);
+  cur_try_context->rethrow_decl = rethrow_decl;
+  TREE_THIS_VOLATILE (rethrow_decl) = 1;
+  TREE_CHAIN (rethrow_decl) = stack_decl;
 
-  objc_catch_type = tree_cons (NULL_TREE, var_type, objc_catch_type);
+  /* Build the outermost varible binding level.  */
+  bind = build (BIND_EXPR, void_type_node, rethrow_decl, NULL, NULL);
+  annotate_with_locus (bind, cur_try_context->try_locus);
+  TREE_SIDE_EFFECTS (bind) = 1;
 
-  c_finish_then (objc_exit_block ());
+  /* Initialize rethrow_decl.  */
+  t = build (MODIFY_EXPR, void_type_node, rethrow_decl,
+            convert (id_type, null_pointer_node));
+  annotate_with_locus (t, cur_try_context->try_locus);
+  append_to_statement_list (t, &BIND_EXPR_BODY (bind));
 
-  c_begin_else (0);
-  catch_count_stack->val++;
-  c_begin_if_stmt ();
-  if_nesting_count++;
+  /* Build the outermost TRY_FINALLY_EXPR.  */
+  try_fin = build (TRY_FINALLY_EXPR, void_type_node, NULL, NULL);
+  annotate_with_locus (try_fin, cur_try_context->try_locus);
+  TREE_SIDE_EFFECTS (try_fin) = 1;
+  append_to_statement_list (try_fin, &BIND_EXPR_BODY (bind));
 
-  if (catch_id)
-    cond = integer_one_node;
-  else
+  /* Create the complete catch sequence.  */
+  if (cur_try_context->catch_list)
     {
-      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);
-    }
+      tree caught_decl = objc_build_exc_ptr ();
+      catch_seq = build_stmt (BIND_EXPR, caught_decl, NULL, NULL);
 
-  c_finish_if_cond (cond, 0, 0);
-  objc_enter_block ();
-  objc_declare_variable (RID_REGISTER, var_name,
-                        build_pointer_type (var_type),
-                        TREE_VALUE (objc_caught_exception));
-}
+      t = next_sjlj_build_exc_extract (caught_decl);
+      append_to_statement_list (t, &BIND_EXPR_BODY (catch_seq));
 
-void
-objc_build_catch_epilogue (void)
-{
-  /*     } else {
-           _rethrowException = _caughtException;
-           objc_exception_try_exit(&_stackExceptionData);
-         }
-       } else {
-         _rethrowException = objc_exception_extract(&_stackExceptionData);
-       }
-     }
-   } // end TRY-CATCH scope
-  */
+      t = next_sjlj_build_enter_and_setjmp ();
+      COND_EXPR_THEN (t) = next_sjlj_build_exc_extract (rethrow_decl);
+      COND_EXPR_ELSE (t) = next_sjlj_build_catch_list ();
+      append_to_statement_list (t, &BIND_EXPR_BODY (catch_seq));
+    }
+  else
+    catch_seq = next_sjlj_build_exc_extract (rethrow_decl);
+  annotate_with_locus (catch_seq, cur_try_context->end_try_locus);
 
-  c_finish_then (objc_exit_block ());
+  /* Build the main register-and-try if statement.  */
+  t = next_sjlj_build_enter_and_setjmp ();
+  annotate_with_locus (t, cur_try_context->try_locus);
+  COND_EXPR_THEN (t) = catch_seq;
+  COND_EXPR_ELSE (t) = cur_try_context->try_body;
+  TREE_OPERAND (try_fin, 0) = t;
 
-  c_begin_else (0);
-  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--)
-    {
-      /* FIXME.  Need to have the block of each else that was opened.  */
-      c_finish_else ((abort (), NULL)); /* close off all the nested ifs ! */
-      c_finish_if_stmt (1);
-      if_nesting_count--;
-    }
-  val_stack_pop (&catch_count_stack);
-  objc_caught_exception = TREE_CHAIN (objc_caught_exception);
+  /* Build the complete FINALLY statement list.  */
+  t = next_sjlj_build_try_exit ();
+  t = build_stmt (COND_EXPR,
+                 lang_hooks.truthvalue_conversion (rethrow_decl),
+                 NULL, t);
+  annotate_with_locus (t, cur_try_context->finally_locus);
+  append_to_statement_list (t, &TREE_OPERAND (try_fin, 1));
 
-  objc_build_extract_fragment ();
+  append_to_statement_list (cur_try_context->finally_body,
+                           &TREE_OPERAND (try_fin, 1));
 
-  c_finish_else (objc_exit_block ());
-  c_finish_if_stmt (1);
-  if_nesting_count--;
-  objc_exit_block ();
+  t = tree_cons (NULL, rethrow_decl, NULL);
+  t = build_function_call (objc_exception_throw_decl, t);
+  t = build_stmt (COND_EXPR,
+                 lang_hooks.truthvalue_conversion (rethrow_decl),
+                 t, NULL);
+  annotate_with_locus (t, cur_try_context->end_finally_locus);
+  append_to_statement_list (t, &TREE_OPERAND (try_fin, 1));
 
-  /* Return 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);
+  return bind;
 }
 
-tree
-objc_build_finally_prologue (void)
+/* Called just after parsing the @try and its associated BODY.  We now
+   must prepare for the tricky bits -- handling the catches and finally.  */
+
+void
+objc_begin_try_stmt (location_t try_locus, tree body)
 {
-  /* { // begin FINALLY scope
-       if (!_rethrowException) {
-         objc_exception_try_exit(&_stackExceptionData);
-       }  */
+  struct objc_try_context *c = xcalloc (1, sizeof (*c));
+  c->outer = cur_try_context;
+  c->try_body = body;
+  c->try_locus = try_locus;
+  c->end_try_locus = input_location;
+  cur_try_context = c;
 
-  tree blk = objc_enter_block ();
+  objc_init_exceptions ();
+}
+
+/* Called just after parsing "@catch (parm)".  Open a binding level, 
+   enter PARM into the binding level, and initialize it.  Leave the
+   binding level open while the body of the compound statement is parsed.  */
+   
+void
+objc_begin_catch_clause (tree parm)
+{
+  tree compound, decl, type, t;
 
-  c_begin_if_stmt ();
-  if_nesting_count++;
+  /* Begin a new scope that the entire catch clause will live in.  */
+  compound = c_begin_compound_stmt (1);
 
-  c_finish_if_cond (build_unary_op (TRUTH_NOT_EXPR,
-                                   TREE_VALUE (objc_rethrow_exception), 0),
-                   0, 0);
-  objc_enter_block ();
-  objc_build_try_exit_fragment ();
-  c_finish_then (objc_exit_block ());
-  c_finish_if_stmt (1);
-  if_nesting_count--;
+  /* Turn the raw declarator/declspecs into a decl in the current scope.  */
+  decl = define_decl (TREE_VALUE (TREE_PURPOSE (parm)),
+                     TREE_PURPOSE (TREE_PURPOSE (parm)));
 
-  return blk;
-}
+  /* Since a decl is required here by syntax, don't warn if its unused.  */
+  /* ??? As opposed to __attribute__((unused))?  Anyway, this appears to
+     be what the previous objc implementation did.  */
+  TREE_USED (decl) = 1;
 
-tree
-objc_build_finally_epilogue (void)
-{
-  /*    if (_rethrowException) {
-         objc_exception_throw(_rethrowException);
+  /* Verify that the type of the catch is valid.  It must be a pointer
+     to an Objective-C class, or "id" (which is catch-all).  */
+  type = TREE_TYPE (decl);
+  if (POINTER_TYPE_P (type) && objc_is_object_id (TREE_TYPE (type)))
+    type = NULL;
+  else if (!POINTER_TYPE_P (type) || !TYPED_OBJECT (TREE_TYPE (type)))
+    {
+      error ("@catch parameter is not a known Objective-C class type");
+      type = error_mark_node;
+    }
+  else if (cur_try_context->catch_list)
+    {
+      /* Examine previous @catch clauses and see if we've already
+        caught the type in question.  */
+      tree_stmt_iterator i = tsi_start (cur_try_context->catch_list);
+      for (; !tsi_end_p (i); tsi_next (&i))
+       {
+         tree stmt = tsi_stmt (i);
+         t = CATCH_TYPES (stmt);
+         if (t == error_mark_node)
+           continue;
+         if (!t || objc_comptypes (TREE_TYPE (t), TREE_TYPE (type), 0) == 1)
+           {
+             warning ("exception of type %<%T%> will be caught",
+                      TREE_TYPE (type));
+             warning ("%H   by earlier handler for %<%T%>",
+                      EXPR_LOCUS (stmt), TREE_TYPE (t ? t : id_type));
+             break;
+           }
        }
-      } // end FINALLY scope
-    } */
+    }
 
-  c_begin_if_stmt ();
-  if_nesting_count++;
+  /* Record the data for the catch in the try context so that we can
+     finalize it later.  */
+  t = build_stmt (CATCH_EXPR, type, compound);
+  cur_try_context->current_catch = t;
 
-  c_finish_if_cond (TREE_VALUE (objc_rethrow_exception), 0, 0);
-  objc_enter_block ();
-  objc_build_throw_stmt (TREE_VALUE (objc_rethrow_exception));
-  c_finish_then (objc_exit_block ());
-  c_finish_if_stmt (1);
-  if_nesting_count--;
+  /* Initialize the decl from the EXC_PTR_EXPR we get from the runtime.  */
+  t = objc_build_exc_ptr ();
+  t = convert (TREE_TYPE (decl), t);
+  t = build (MODIFY_EXPR, void_type_node, decl, t);
+  add_stmt (t);
+}
 
-  objc_exit_block ();
-  objc_rethrow_exception = TREE_CHAIN (objc_rethrow_exception);
-  objc_stack_exception_data = TREE_CHAIN (objc_stack_exception_data);
+/* Called just after parsing the closing brace of a @catch clause.  Close
+   the open binding level, and record a CATCH_EXPR for it.  */
 
-  val_stack_pop (&exc_binding_stack);
-  return objc_exit_block ();
+void
+objc_finish_catch_clause (void)
+{
+  tree c = cur_try_context->current_catch;
+  cur_try_context->current_catch = NULL;
+  cur_try_context->end_catch_locus = input_location;
+
+  CATCH_BODY (c) = c_end_compound_stmt (CATCH_BODY (c), 1);
+  append_to_statement_list (c, &cur_try_context->catch_list);
 }
 
-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'.  */
-  /* ??? This is all crock.  What the hell is this trying to do?  */
-  tree outer_blk = objc_build_finally_epilogue ();
-  tree prec_stmt = TREE_CHAIN (TREE_CHAIN (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;
+/* Called after parsing a @finally clause and its associated BODY.
+   Record the body for later placement.  */
 
-  if (!flag_objc_exceptions)
-    fatal_error ("Use `-fobjc-exceptions' to enable Objective-C exception syntax");
+void
+objc_build_finally_clause (location_t finally_locus, tree body)
+{
+  cur_try_context->finally_body = body;
+  cur_try_context->finally_locus = finally_locus;
+  cur_try_context->end_finally_locus = input_location;
+}
+
+/* Called to finalize a @try construct.  */
 
-  /* It is an error to have a @try block without a @catch and/or @finally
-     (even though sensible code can be generated nonetheless).  */
+void
+objc_finish_try_stmt (void)
+{
+  struct objc_try_context *c = cur_try_context;
+  tree stmt;
 
-  if (!has_catch && !has_finally)
+  if (c->catch_list == NULL && c->finally_body == NULL)
     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 */
+  /* If we're doing Darwin setjmp exceptions, build the big nasty.  */
+  if (flag_objc_sjlj_exceptions)
+    {
+      if (!cur_try_context->finally_body)
+       {
+         cur_try_context->finally_locus = input_location;
+         cur_try_context->end_finally_locus = input_location;
+       }
+      stmt = next_sjlj_build_try_catch_finally ();
+    }
+  else
+    {
+      /* Otherwise, nest the CATCH inside a FINALLY.  */
+      stmt = c->try_body;
+      if (c->catch_list)
+       {
+          stmt = build_stmt (TRY_CATCH_EXPR, stmt, c->catch_list);
+         annotate_with_locus (stmt, cur_try_context->try_locus);
+       }
+      if (c->finally_body)
+       {
+         stmt = build_stmt (TRY_FINALLY_EXPR, stmt, c->finally_body);
+         annotate_with_locus (stmt, cur_try_context->try_locus);
+       }
+    }
+  add_stmt (stmt);
+
+  cur_try_context = c->outer;
+  free (c);
 }
 
 void
-objc_build_synchronized_prologue (tree sync_expr)
+objc_build_throw_stmt (tree throw_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);
+  if (throw_expr == NULL)
+    {
+      /* If we're not inside a @catch block, there is no "current
+        exception" to be rethrown.  */
+      if (cur_try_context == NULL
+          || cur_try_context->current_catch == NULL)
+       {
+         error ("%<@throw%> (rethrow) used outside of a @catch block");
+         return;
+       }
+
+      /* Otherwise the object is still sitting in the EXC_PTR_EXPR
+        value that we get from the runtime.  */
+      throw_expr = objc_build_exc_ptr ();
+    }
 
-  assemble_external (objc_sync_enter_decl);
-  c_expand_expr_stmt (build_function_call
-                     (objc_sync_enter_decl, func_params));
+  /* A throw is just a call to the runtime throw function with the
+     object as a parameter.  */
+  func_params = tree_cons (NULL, throw_expr, NULL);
+  add_stmt (build_function_call (objc_exception_throw_decl, func_params));
+
+  objc_init_exceptions ();
 }
 
-tree
-objc_build_synchronized_epilogue (void)
+void
+objc_build_synchronized (location_t start_locus, tree mutex, tree body)
 {
-  /* }
-       @finally {
-         objc_sync_exit( _eval_once );
-       }
-     }  */
+  tree args, call;
 
-  tree func_params;
+  /* First lock the mutex.  */
+  mutex = save_expr (mutex);
+  args = tree_cons (NULL, mutex, NULL);
+  call = build_function_call (objc_sync_enter_decl, args);
+  annotate_with_locus (call, start_locus);
+  add_stmt (call);
 
-  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);
+  /* Build the mutex unlock.  */
+  args = tree_cons (NULL, mutex, NULL);
+  call = build_function_call (objc_sync_exit_decl, args);
+  annotate_with_locus (call, input_location);
 
-  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 ();
+  /* Put the that and the body in a TRY_FINALLY.  */
+  objc_begin_try_stmt (start_locus, body);
+  objc_build_finally_clause (input_location, call);
+  objc_finish_try_stmt ();
 }
 
+\f
 /* Predefine the following data type:
 
    struct _objc_exception_data
@@ -3259,7 +3249,7 @@ objc_build_synchronized_epilogue (void)
 #endif
 
 static void
-build_objc_exception_stuff (void)
+build_next_objc_exception_stuff (void)
 {
   tree field_decl, field_decl_chain, index, temp_type;
 
@@ -3270,6 +3260,7 @@ build_objc_exception_stuff (void)
 
   write_symbols = NO_DEBUG;
   debug_hooks = &do_nothing_debug_hooks;
+
   objc_exception_data_template
     = start_struct (RECORD_TYPE, get_identifier (UTAG_EXCDATA));
 
@@ -3317,20 +3308,7 @@ build_objc_exception_stuff (void)
     = 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,
-                                             void_list_node));
-  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,
@@ -3343,6 +3321,32 @@ build_objc_exception_stuff (void)
   debug_hooks = save_hooks;
 }
 
+static void
+build_objc_exception_stuff (void)
+{
+  tree noreturn_list, nothrow_list, temp_type;
+
+  noreturn_list = tree_cons (get_identifier ("noreturn"), NULL, NULL);
+  nothrow_list = tree_cons (get_identifier ("nothrow"), NULL, NULL);
+
+  /* void objc_exception_throw(id) __attribute__((noreturn)); */
+  /* void objc_sync_enter(id); */
+  /* void objc_sync_exit(id); */
+  temp_type = build_function_type (void_type_node,
+                                  tree_cons (NULL_TREE, id_type,
+                                             void_list_node));
+  objc_exception_throw_decl
+    = builtin_function (TAG_EXCEPTIONTHROW, temp_type, 0, NOT_BUILT_IN, NULL,
+                       noreturn_list);
+  objc_sync_enter_decl
+    = builtin_function (TAG_SYNCENTER, temp_type, 0, NOT_BUILT_IN,
+                       NULL, nothrow_list);
+  objc_sync_exit_decl
+    = builtin_function (TAG_SYNCEXIT, temp_type, 0, NOT_BUILT_IN,
+                       NULL, nothrow_list);
+}
+
+
 /* struct <classname> {
      struct objc_class *isa;
      ...
index 5738bc9aedebee1712c8284aa548b8f5fb072dbd..8794aa432524e9fe471d28a2830e368f5e6fff43 100644 (file)
@@ -39,16 +39,13 @@ void finish_method_def (void);
 tree start_protocol (enum tree_code, tree, tree);
 void finish_protocol (tree);
 
-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);
+void objc_build_throw_stmt (tree);
+void objc_begin_try_stmt (location_t, tree);
+void objc_begin_catch_clause (tree);
+void objc_finish_catch_clause (void);
+void objc_build_finally_clause (location_t, tree);
+void objc_finish_try_stmt (void);
+void objc_build_synchronized (location_t, tree, tree);
 
 tree is_ivar (tree, tree);
 int is_private (tree);
@@ -282,7 +279,6 @@ enum objc_tree_index
     OCTI_LOCAL_EXCEPTION_DECL,
     OCTI_RETHROW_EXCEPTION_DECL,
     OCTI_EVAL_ONCE_DECL,
-    OCTI_EXCEPTION_BLK_STACK,
     OCTI_CATCH_TYPE,
 
     OCTI_MAX
@@ -402,8 +398,6 @@ extern GTY(()) tree objc_global_trees[OCTI_MAX];
 #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]
index 9411b50a1963d3d84460bc8d29498ba06f31406a..c2bbd33d1520d152ea394c9a303d9f82a80bce1b 100644 (file)
@@ -1,3 +1,12 @@
+2004-06-17  Richard Henderson  <rth@redhat.com>
+
+       * objc.dg/sync-1.m: New.
+       * objc.dg/try-catch-1.m: Don't force next runtime.
+       * objc.dg/try-catch-3.m, objc.dg/try-catch-4.m: Likewise.
+       * objc.dg/try-catch-2.m: Likewise.  Enable everywhere.  Remove
+       shadowed catch clause.
+       * objc.dg/try-catch-5.m: New.
+
 2004-06-17  Zack Weinberg  <zack@codesourcery.com>
 
        Bug 14610
diff --git a/gcc/testsuite/objc.dg/sync-1.m b/gcc/testsuite/objc.dg/sync-1.m
new file mode 100644 (file)
index 0000000..d7035c7
--- /dev/null
@@ -0,0 +1,12 @@
+/* Make sure that @synchronized parses.  */
+/* { dg-options "-fnext-runtime -fobjc-exceptions" } */
+/* { dg-do compile } */
+
+#include <objc/Object.h>
+
+void foo(id sem)
+{
+  @synchronized (sem) { 
+    return;
+  }
+}
index 4ba86207bd9b550167edcd0fcf668e70e964e2c0..c47e41c96015617970c8fad03ecb8ab8bf3c8f11 100644 (file)
@@ -1,8 +1,6 @@
-/* Test if the compiler accepts @throw / @try..@catch..@finally 
-   syntax.  This will only be usable on MacOS X 10.3 and later,
-   but may be compiled on all targets.  */
+/* Test if the compiler accepts @throw / @try..@catch..@finally syntax.  */
 /* Developed by Ziemowit Laski <zlaski@apple.com>.  */
-/* { dg-options "-fnext-runtime -fobjc-exceptions" } */
+/* { dg-options "-fobjc-exceptions" } */
 /* { dg-do compile } */
 
 #include <objc/Object.h>
index 6adefafae15b6db2733e286f34c0a2923edf9c85..b2550da11480f00d57964af89382f58d73822ac5 100644 (file)
@@ -2,11 +2,9 @@
    all uncaught exceptions.  */
 /* Developed by Ziemowit Laski <zlaski@apple.com>.  */
 
-/* { dg-options "-fobjc-exceptions -lobjc" } */
-/* { dg-do run { target *-*-darwin* } } */
+/* { dg-options "-fobjc-exceptions" } */
+/* { dg-do run } */
 
-#include <objc/objc.h>
-#include <objc/objc-runtime.h>
 #include <objc/Object.h>
 #include <stdio.h>
 
@@ -72,10 +70,6 @@ void test (Object* sendPort)
                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) {
index b79b494d18228738e6b6ee4fa891ff30331ab372..af2829e2c2facea36a4f9482f2d7406c8b1c2bb3 100644 (file)
@@ -3,7 +3,7 @@
 /* Author: Ziemowit Laski <zlaski@apple.com> */
 
 /* { dg-do compile } */
-/* { dg-options "-fnext-runtime -fobjc-exceptions" } */
+/* { dg-options "-fobjc-exceptions" } */
 
 #include <objc/Object.h>
 
index b9c28daeb18d89a5f28b108a87d1b342c1b67ae1..dedcc4ec4f7d0690a0a9edfb7f7b38fd121a18c5 100644 (file)
@@ -3,7 +3,7 @@
 /* Author: Ziemowit Laski <zlaski@apple.com> */
 
 /* { dg-do compile } */
-/* { dg-options "-Wall -fnext-runtime -fobjc-exceptions" } */
+/* { dg-options "-Wall -fobjc-exceptions" } */
 
 @interface Exception
 @end
diff --git a/gcc/testsuite/objc.dg/try-catch-5.m b/gcc/testsuite/objc.dg/try-catch-5.m
new file mode 100644 (file)
index 0000000..f833bc2
--- /dev/null
@@ -0,0 +1,27 @@
+/* Check that the compiler does correctly complain about
+   exceptions being caught by previous @catch blocks.  */
+/* Force the use of NeXT runtime to see that we don't ICE after
+   generating the warning message.  */
+
+/* { dg-do compile } */
+/* { dg-options "-Wall -fnext-runtime -fobjc-exceptions" } */
+
+@interface Exception
+@end
+
+@interface FooException : Exception
+@end
+
+extern void foo();
+
+void test()
+{
+    @try {
+        foo();
+    }
+    @catch (Exception* e) {    /* { dg-warning "earlier handler" } */
+    }
+    @catch (FooException* fe) {        /* { dg-warning "will be caught" } */
+    }
+}
+