Commit 093c7153 by Richard Henderson Committed by Richard Henderson

c-common.c (flag_objc_sjlj_exceptions): New.

	* 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
parent a776161b
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> 2004-06-17 Andrew Pinski <apinski@apple.com>
* c-typeck.c (tagged_types_tu_compatible_p <case UNION_TYPE>): * c-typeck.c (tagged_types_tu_compatible_p <case UNION_TYPE>):
......
...@@ -361,6 +361,9 @@ int flag_nil_receivers = 1; ...@@ -361,6 +361,9 @@ int flag_nil_receivers = 1;
@try, etc.) in source code. */ @try, etc.) in source code. */
int flag_objc_exceptions = 0; 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 /* Nonzero means that code generation will be altered to support
"zero-link" execution. This currently affects ObjC only, but may "zero-link" execution. This currently affects ObjC only, but may
affect other languages in the future. */ affect other languages in the future. */
......
...@@ -321,6 +321,9 @@ extern int flag_nil_receivers; ...@@ -321,6 +321,9 @@ extern int flag_nil_receivers;
@try, etc.) in source code. */ @try, etc.) in source code. */
extern int flag_objc_exceptions; 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 /* Nonzero means that code generation will be altered to support
"zero-link" execution. This currently affects ObjC only, but may "zero-link" execution. This currently affects ObjC only, but may
affect other languages in the future. */ affect other languages in the future. */
......
...@@ -71,11 +71,14 @@ enum decl_context ...@@ -71,11 +71,14 @@ enum decl_context
/* Nonzero if we have seen an invalid cross reference /* Nonzero if we have seen an invalid cross reference
to a struct, union, or enum, but not yet printed the message. */ to a struct, union, or enum, but not yet printed the message. */
tree pending_invalid_xref; tree pending_invalid_xref;
/* File and line to appear in the eventual error message. */ /* File and line to appear in the eventual error message. */
location_t pending_invalid_xref_location; 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 /* 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' constant value. Note that will do not have to save this or `enum_overflow'
around nested function definition since such a definition could only around nested function definition since such a definition could only
...@@ -2982,8 +2985,6 @@ finish_decl (tree decl, tree init, tree asmspec_tree) ...@@ -2982,8 +2985,6 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
tree attr = lookup_attribute ("cleanup", DECL_ATTRIBUTES (decl)); tree attr = lookup_attribute ("cleanup", DECL_ATTRIBUTES (decl));
if (attr) if (attr)
{ {
static bool eh_initialized_p;
tree cleanup_id = TREE_VALUE (TREE_VALUE (attr)); tree cleanup_id = TREE_VALUE (TREE_VALUE (attr));
tree cleanup_decl = lookup_name (cleanup_id); tree cleanup_decl = lookup_name (cleanup_id);
tree cleanup; tree cleanup;
...@@ -2998,9 +2999,9 @@ finish_decl (tree decl, tree init, tree asmspec_tree) ...@@ -2998,9 +2999,9 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
TREE_USED (cleanup_decl) = 1; TREE_USED (cleanup_decl) = 1;
/* Initialize EH, if we've been told to do so. */ /* 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 eh_personality_libfunc
= init_one_libfunc (USING_SJLJ_EXCEPTIONS = init_one_libfunc (USING_SJLJ_EXCEPTIONS
? "__gcc_personality_sj0" ? "__gcc_personality_sj0"
......
...@@ -863,6 +863,10 @@ c_common_handle_option (size_t scode, const char *arg, int value) ...@@ -863,6 +863,10 @@ c_common_handle_option (size_t scode, const char *arg, int value)
flag_objc_exceptions = value; flag_objc_exceptions = value;
break; break;
case OPT_fobjc_sjlj_exceptions:
flag_objc_sjlj_exceptions = value;
break;
case OPT_foperator_names: case OPT_foperator_names:
cpp_opts->operator_names = value; cpp_opts->operator_names = value;
break; break;
...@@ -1109,6 +1113,12 @@ c_common_post_options (const char **pfilename) ...@@ -1109,6 +1113,12 @@ c_common_post_options (const char **pfilename)
flag_inline_functions = 0; 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 /* -Wextra implies -Wsign-compare, but not if explicitly
overridden. */ overridden. */
if (warn_sign_compare == -1) if (warn_sign_compare == -1)
......
...@@ -251,7 +251,6 @@ do { \ ...@@ -251,7 +251,6 @@ do { \
%type <ttype> CLASSNAME OBJECTNAME OBJC_STRING %type <ttype> CLASSNAME OBJECTNAME OBJC_STRING
%type <ttype> superclass %type <ttype> superclass
%type <itype> objc_try_catch_stmt objc_finally_block
@@end_ifobjc @@end_ifobjc
%{ %{
...@@ -1515,7 +1514,7 @@ designator: ...@@ -1515,7 +1514,7 @@ designator:
; ;
nested_function: nested_function:
declarator declarator
{ if (pedantic) { if (pedantic)
pedwarn ("ISO C forbids nested functions"); pedwarn ("ISO C forbids nested functions");
...@@ -1527,25 +1526,25 @@ nested_function: ...@@ -1527,25 +1526,25 @@ nested_function:
YYERROR1; YYERROR1;
} }
} }
old_style_parm_decls save_location old_style_parm_decls save_location
{ tree decl = current_function_decl; { tree decl = current_function_decl;
DECL_SOURCE_LOCATION (decl) = $4; DECL_SOURCE_LOCATION (decl) = $4;
store_parm_decls (); } store_parm_decls (); }
/* This used to use compstmt_or_error. /* This used to use compstmt_or_error. That caused a bug with
That caused a bug with input `f(g) int g {}', input `f(g) int g {}', where the use of YYERROR1 above caused
where the use of YYERROR1 above caused an error an error which then was handled by compstmt_or_error. There
which then was handled by compstmt_or_error. followed a repeated execution of that same rule, which called
There followed a repeated execution of that same rule, YYERROR1 again, and so on. */
which called YYERROR1 again, and so on. */ compstmt
compstmt
{ tree decl = current_function_decl; { tree decl = current_function_decl;
add_stmt ($6);
finish_function (); finish_function ();
pop_function_context (); pop_function_context ();
add_decl_stmt (decl); } add_decl_stmt (decl); }
; ;
notype_nested_function: notype_nested_function:
notype_declarator notype_declarator
{ if (pedantic) { if (pedantic)
pedwarn ("ISO C forbids nested functions"); pedwarn ("ISO C forbids nested functions");
...@@ -1557,18 +1556,18 @@ notype_nested_function: ...@@ -1557,18 +1556,18 @@ notype_nested_function:
YYERROR1; YYERROR1;
} }
} }
old_style_parm_decls save_location old_style_parm_decls save_location
{ tree decl = current_function_decl; { tree decl = current_function_decl;
DECL_SOURCE_LOCATION (decl) = $4; DECL_SOURCE_LOCATION (decl) = $4;
store_parm_decls (); } store_parm_decls (); }
/* This used to use compstmt_or_error. /* This used to use compstmt_or_error. That caused a bug with
That caused a bug with input `f(g) int g {}', input `f(g) int g {}', where the use of YYERROR1 above caused
where the use of YYERROR1 above caused an error an error which then was handled by compstmt_or_error. There
which then was handled by compstmt_or_error. followed a repeated execution of that same rule, which called
There followed a repeated execution of that same rule, YYERROR1 again, and so on. */
which called YYERROR1 again, and so on. */ compstmt
compstmt
{ tree decl = current_function_decl; { tree decl = current_function_decl;
add_stmt ($6);
finish_function (); finish_function ();
pop_function_context (); pop_function_context ();
add_decl_stmt (decl); } add_decl_stmt (decl); }
...@@ -2029,7 +2028,7 @@ label_decl: ...@@ -2029,7 +2028,7 @@ label_decl:
It causes syntax errors to ignore to the next openbrace. */ It causes syntax errors to ignore to the next openbrace. */
compstmt_or_error: compstmt_or_error:
compstmt compstmt
{} { add_stmt ($1); }
| error compstmt | error compstmt
; ;
...@@ -2060,8 +2059,7 @@ compstmt_primary_start: ...@@ -2060,8 +2059,7 @@ compstmt_primary_start:
; ;
compstmt: compstmt_start compstmt_nostart compstmt: compstmt_start compstmt_nostart
{ add_stmt (c_end_compound_stmt ($1, true)); { $$ = c_end_compound_stmt ($1, true); }
$$ = NULL_TREE; }
; ;
if_prefix: if_prefix:
...@@ -2226,37 +2224,27 @@ xexpr: ...@@ -2226,37 +2224,27 @@ xexpr:
/* Parse a single real statement, not including any labels. */ /* Parse a single real statement, not including any labels. */
stmt: stmt:
compstmt compstmt
{ stmt_count++; $$ = $1; } { stmt_count++; add_stmt ($1); }
| expr ';' | expr ';'
{ stmt_count++; { stmt_count++; c_expand_expr_stmt ($1); }
$$ = c_expand_expr_stmt ($1); }
| c99_block_start select_or_iter_stmt | c99_block_start select_or_iter_stmt
{ add_stmt (c_end_compound_stmt ($1, flag_isoc99)); { add_stmt (c_end_compound_stmt ($1, flag_isoc99)); }
$$ = NULL_TREE; }
| BREAK ';' | BREAK ';'
{ stmt_count++; { stmt_count++;
if (!(c_in_iteration_stmt || c_in_case_stmt)) if (!(c_in_iteration_stmt || c_in_case_stmt))
{ error ("break statement not within loop or switch");
error ("break statement not within loop or switch");
$$ = NULL_TREE;
}
else else
$$ = add_stmt (build_break_stmt ()); } add_stmt (build_break_stmt ()); }
| CONTINUE ';' | CONTINUE ';'
{ stmt_count++; { stmt_count++;
if (!c_in_iteration_stmt) if (!c_in_iteration_stmt)
{ error ("continue statement not within a loop");
error ("continue statement not within a loop");
$$ = NULL_TREE;
}
else else
$$ = add_stmt (build_continue_stmt ()); } add_stmt (build_continue_stmt ()); }
| RETURN ';' | RETURN ';'
{ stmt_count++; { stmt_count++; c_expand_return (NULL_TREE); }
$$ = c_expand_return (NULL_TREE); }
| RETURN expr ';' | RETURN expr ';'
{ stmt_count++; { stmt_count++; c_expand_return ($2); }
$$ = c_expand_return ($2); }
| asm_stmt | asm_stmt
| GOTO identifier ';' | GOTO identifier ';'
{ tree decl; { tree decl;
...@@ -2265,71 +2253,61 @@ stmt: ...@@ -2265,71 +2253,61 @@ stmt:
if (decl != 0) if (decl != 0)
{ {
TREE_USED (decl) = 1; TREE_USED (decl) = 1;
$$ = add_stmt (build_stmt (GOTO_EXPR, decl)); add_stmt (build_stmt (GOTO_EXPR, decl));
} }
else
$$ = NULL_TREE;
} }
| GOTO '*' expr ';' | GOTO '*' expr ';'
{ if (pedantic) { if (pedantic)
pedwarn ("ISO C forbids `goto *expr;'"); pedwarn ("ISO C forbids `goto *expr;'");
stmt_count++; stmt_count++;
$3 = convert (ptr_type_node, $3); $3 = convert (ptr_type_node, $3);
$$ = add_stmt (build_stmt (GOTO_EXPR, $3)); } add_stmt (build_stmt (GOTO_EXPR, $3)); }
| ';' | ';'
{ $$ = NULL_TREE; } { }
@@ifobjc @@ifobjc
| AT_THROW expr ';' | AT_THROW expr ';'
{ stmt_count++; { stmt_count++; objc_build_throw_stmt ($2); }
$$ = objc_build_throw_stmt ($2);
}
| AT_THROW ';' | AT_THROW ';'
{ stmt_count++; { stmt_count++; objc_build_throw_stmt (NULL_TREE); }
$$ = objc_build_throw_stmt (NULL_TREE);
}
| objc_try_catch_stmt | objc_try_catch_stmt
{ objc_build_finally_prologue (); } { }
objc_finally_block | AT_SYNCHRONIZED '(' expr ')' save_location compstmt
{ $$ = objc_build_try_catch_finally_stmt ($1, $3); } { stmt_count++; objc_build_synchronized ($5, $3, $6); }
| AT_SYNCHRONIZED '(' expr ')'
{ objc_build_synchronized_prologue ($3); }
compstmt
{ $$ = objc_build_synchronized_epilogue (); }
; ;
objc_try_catch_stmt: objc_catch_prefix:
objc_try_stmt AT_CATCH '(' parm ')'
{ objc_build_try_epilogue (1); } { objc_begin_catch_clause ($3); }
objc_catch_list
{ objc_build_catch_epilogue (); $$ = 1; }
| objc_try_stmt
{ objc_build_try_epilogue (0); $$ = 0; }
; ;
objc_catch_clause:
objc_catch_prefix '{' compstmt_nostart
{ objc_finish_catch_clause (); }
| objc_catch_prefix '{' error '}'
{ objc_finish_catch_clause (); }
;
objc_try_stmt: objc_opt_catch_list:
AT_TRY /* empty */
{ objc_build_try_prologue (); } | objc_opt_catch_list objc_catch_clause
compstmt
; ;
objc_catch_list: objc_try_catch_clause:
objc_catch_list objc_catch_block AT_TRY save_location compstmt
| objc_catch_block { stmt_count++; objc_begin_try_stmt ($2, $3); }
objc_opt_catch_list
; ;
objc_catch_block: objc_finally_clause:
AT_CATCH '(' parm ')' AT_FINALLY save_location compstmt
{ objc_build_catch_stmt ($3); } { objc_build_finally_clause ($2, $3); }
compstmt
{ stmt_count++; }
; ;
objc_finally_block: objc_try_catch_stmt:
AT_FINALLY compstmt objc_try_catch_clause
{ $$ = 1; } { objc_finish_try_stmt (); }
| /* NULL */ | objc_try_catch_clause objc_finally_clause
{ $$ = 0; } { objc_finish_try_stmt (); }
@@end_ifobjc @@end_ifobjc
; ;
......
...@@ -298,6 +298,9 @@ extern int system_header_p; ...@@ -298,6 +298,9 @@ extern int system_header_p;
extern bool c_override_global_bindings_to_false; 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 */ /* In c-decl.c */
extern void c_finish_incomplete_decl (tree); extern void c_finish_incomplete_decl (tree);
extern void *get_current_scope (void); extern void *get_current_scope (void);
......
...@@ -584,6 +584,10 @@ fobjc-exceptions ...@@ -584,6 +584,10 @@ fobjc-exceptions
ObjC ObjC++ ObjC ObjC++
Enable Objective-C exception and synchronization syntax Enable Objective-C exception and synchronization syntax
fobjc-sjlj-exceptions
ObjC ObjC++
Enable Objective-C setjmp exception handling runtime
foperator-names foperator-names
C++ ObjC++ C++ ObjC++
Recognize C++ kewords like \"compl\" and \"xor\" Recognize C++ kewords like \"compl\" and \"xor\"
......
...@@ -4085,9 +4085,12 @@ output_function_exception_table (void) ...@@ -4085,9 +4085,12 @@ output_function_exception_table (void)
if (TREE_CODE (type) == ADDR_EXPR) if (TREE_CODE (type) == ADDR_EXPR)
{ {
type = TREE_OPERAND (type, 0); type = TREE_OPERAND (type, 0);
node = cgraph_varpool_node (type); if (TREE_CODE (type) == VAR_DECL)
if (node) {
cgraph_varpool_mark_needed_node (node); node = cgraph_varpool_node (type);
if (node)
cgraph_varpool_mark_needed_node (node);
}
} }
else if (TREE_CODE (type) != INTEGER_CST) else if (TREE_CODE (type) != INTEGER_CST)
abort (); abort ();
......
...@@ -63,6 +63,8 @@ Boston, MA 02111-1307, USA. */ ...@@ -63,6 +63,8 @@ Boston, MA 02111-1307, USA. */
#include "target.h" #include "target.h"
#include "diagnostic.h" #include "diagnostic.h"
#include "cgraph.h" #include "cgraph.h"
#include "tree-iterator.h"
#include "libfuncs.h"
/* This is the default way of generating a method name. */ /* This is the default way of generating a method name. */
/* I am not sure it is really correct. /* I am not sure it is really correct.
...@@ -134,13 +136,7 @@ static void build_selector_translation_table (void); ...@@ -134,13 +136,7 @@ static void build_selector_translation_table (void);
static tree objc_add_static_instance (tree, tree); static tree objc_add_static_instance (tree, tree);
static void build_objc_exception_stuff (void); static void build_objc_exception_stuff (void);
static tree objc_declare_variable (enum rid, tree, tree, tree); static void build_next_objc_exception_stuff (void);
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_ivar_template (void);
static tree build_method_template (void); static tree build_method_template (void);
...@@ -365,23 +361,6 @@ static const char *default_constant_string_class_name; ...@@ -365,23 +361,6 @@ static const char *default_constant_string_class_name;
#define TAG_RETURN_STRUCT "objc_return_struct" #define TAG_RETURN_STRUCT "objc_return_struct"
#define UTAG_EXCDATA "_objc_exception_data" #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. */ /* The OCTI_... enumeration itself is in objc/objc-act.h. */
tree objc_global_trees[OCTI_MAX]; tree objc_global_trees[OCTI_MAX];
...@@ -626,6 +605,20 @@ lookup_protocol_in_reflist (tree rproto_list, tree lproto) ...@@ -626,6 +605,20 @@ lookup_protocol_in_reflist (tree rproto_list, tree lproto)
return 0; 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 /* Return 1 if LHS and RHS are compatible types for assignment or
various other operations. Return 0 if they are incompatible, and various other operations. Return 0 if they are incompatible, and
return -1 if we choose to not decide (because the types are really 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) ...@@ -777,12 +770,12 @@ objc_comptypes (tree lhs, tree rhs, int reflexive)
return 1; return 1;
} }
/* <Protocol> = id */ /* <Protocol> = id */
else if (OBJC_TYPE_NAME (TREE_TYPE (rhs)) == objc_object_id) else if (objc_is_object_id (TREE_TYPE (rhs)))
{ {
return 1; return 1;
} }
/* <Protocol> = Class */ /* <Protocol> = Class */
else if (OBJC_TYPE_NAME (TREE_TYPE (rhs)) == objc_class_id) else if (objc_is_class_id (TREE_TYPE (rhs)))
{ {
return 0; return 0;
} }
...@@ -854,12 +847,12 @@ objc_comptypes (tree lhs, tree rhs, int reflexive) ...@@ -854,12 +847,12 @@ objc_comptypes (tree lhs, tree rhs, int reflexive)
return 0; return 0;
} }
/* id = <Protocol> */ /* id = <Protocol> */
else if (OBJC_TYPE_NAME (TREE_TYPE (lhs)) == objc_object_id) else if (objc_is_object_id (TREE_TYPE (lhs)))
{ {
return 1; return 1;
} }
/* Class = <Protocol> */ /* Class = <Protocol> */
else if (OBJC_TYPE_NAME (TREE_TYPE (lhs)) == objc_class_id) else if (objc_is_class_id (TREE_TYPE (lhs)))
{ {
return 0; return 0;
} }
...@@ -892,16 +885,14 @@ objc_comptypes (tree lhs, tree rhs, int reflexive) ...@@ -892,16 +885,14 @@ objc_comptypes (tree lhs, tree rhs, int reflexive)
'Object *o = [[Object alloc] init]; falls 'Object *o = [[Object alloc] init]; falls
in the case <class> * = `id'. in the case <class> * = `id'.
*/ */
if ((OBJC_TYPE_NAME (lhs) == objc_object_id && TYPED_OBJECT (rhs)) if ((objc_is_object_id (lhs) && TYPED_OBJECT (rhs))
|| (OBJC_TYPE_NAME (rhs) == objc_object_id && TYPED_OBJECT (lhs))) || (objc_is_object_id (rhs) && TYPED_OBJECT (lhs)))
return 1; return 1;
/* `id' = `Class', `Class' = `id' */ /* `id' = `Class', `Class' = `id' */
else if ((OBJC_TYPE_NAME (lhs) == objc_object_id else if ((objc_is_object_id (lhs) && objc_is_class_id (rhs))
&& OBJC_TYPE_NAME (rhs) == objc_class_id) || (objc_is_class_id (lhs) && objc_is_object_id (rhs)))
|| (OBJC_TYPE_NAME (lhs) == objc_class_id
&& OBJC_TYPE_NAME (rhs) == objc_object_id))
return 1; return 1;
/* `Class' != `<class> *' && `<class> *' != `Class'! */ /* `Class' != `<class> *' && `<class> *' != `Class'! */
...@@ -1273,8 +1264,9 @@ synth_module_prologue (void) ...@@ -1273,8 +1264,9 @@ synth_module_prologue (void)
= 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 (); build_super_template ();
build_objc_exception_stuff ();
if (flag_next_runtime) if (flag_next_runtime)
build_objc_exception_stuff (); build_next_objc_exception_stuff ();
/* static SEL _OBJC_SELECTOR_TABLE[]; */ /* static SEL _OBJC_SELECTOR_TABLE[]; */
...@@ -2682,563 +2674,561 @@ get_class_ivars (tree interface, int raw) ...@@ -2682,563 +2674,561 @@ get_class_ivars (tree interface, int raw)
} }
static tree static tree
objc_enter_block (void) objc_create_temporary_var (tree type)
{ {
tree block; tree decl;
#ifdef OBJCPLUS decl = build_decl (VAR_DECL, NULL_TREE, type);
block = begin_compound_stmt (0); TREE_USED (decl) = 1;
#else DECL_ARTIFICIAL (decl) = 1;
block = c_begin_compound_stmt (1); DECL_IGNORED_P (decl) = 1;
#endif DECL_CONTEXT (decl) = current_function_decl;
objc_exception_block_stack = tree_cons (NULL_TREE, block,
objc_exception_block_stack);
blk_nesting_count++; return decl;
return block;
} }
/* 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 /* Stack of open try blocks. */
objc_exit_block (void)
struct objc_try_context
{ {
tree block = TREE_VALUE (objc_exception_block_stack); struct objc_try_context *outer;
objc_exception_block_stack = TREE_CHAIN (objc_exception_block_stack);
objc_clear_super_receiver (); /* Statements (or statement lists) as processed by the parser. */
#ifdef OBJCPLUS tree try_body;
finish_compound_stmt (block); tree finally_body;
#else
block = c_end_compound_stmt (block, 1);
#endif
blk_nesting_count--; /* Some file position locations. */
return block; 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 static tree
objc_declare_variable (enum rid scspec, tree name, tree type, tree init) objc_eh_runtime_type (tree type)
{ {
tree decl; return add_objc_string (OBJC_TYPE_NAME (TREE_TYPE (type)), class_names);
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 /* Initialize exception handling. */
objc_build_throw_stmt (tree throw_expr)
static void
objc_init_exceptions (void)
{ {
tree func_params; static bool done = false;
if (done)
return;
done = true;
/* Why? */
if (!flag_objc_exceptions) 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) if (!flag_objc_sjlj_exceptions)
throw_expr = TREE_VALUE (objc_caught_exception);
if (!throw_expr)
{ {
error ("`@throw;' (rethrow) used outside of a `@catch' block"); c_eh_initialized_p = true;
return error_mark_node; 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 /* Build an EXC_PTR_EXPR, or the moral equivalent. In the case of Darwin,
val_stack_push (struct val_stack **nc, long val) 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)); if (flag_objc_sjlj_exceptions)
new_elem->val = val; {
new_elem->next = *nc; tree var = cur_try_context->caught_decl;
*nc = new_elem; 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 /* Build "objc_exception_try_exit(&_stack)". */
val_stack_pop (struct val_stack **nc)
static tree
next_sjlj_build_try_exit (void)
{ {
struct val_stack *old_elem = *nc; tree t;
*nc = old_elem->next; t = build_fold_addr_expr (cur_try_context->stack_decl);
free (old_elem); t = tree_cons (NULL, t, NULL);
t = build_function_call (objc_exception_try_exit_decl, t);
return t;
} }
static void /* Build
objc_build_try_enter_fragment (void) 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); tree t, enter, sj, cond;
if (!_setjmp(&_stackExceptionData.buf)) { */
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 t = build_component_ref (cur_try_context->stack_decl,
= tree_cons (NULL_TREE, get_identifier ("buf"));
build_unary_op (ADDR_EXPR, t = build_fold_addr_expr (t);
TREE_VALUE (objc_stack_exception_data), t = convert (ptr_type_node, t);
0), t = tree_cons (NULL, t, NULL);
NULL_TREE); sj = build_function_call (objc_setjmp_decl, t);
assemble_external (objc_exception_try_enter_decl); cond = build (COMPOUND_EXPR, TREE_TYPE (sj), enter, sj);
c_expand_expr_stmt (build_function_call cond = lang_hooks.truthvalue_conversion (cond);
(objc_exception_try_enter_decl, func_params));
#ifdef OBJCPLUS return build (COND_EXPR, void_type_node, cond, NULL, NULL);
/* 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 ();
} }
/* Build
DECL = objc_exception_extract(&_stack);
*/
static tree static tree
objc_build_extract_expr (void) next_sjlj_build_exc_extract (tree decl)
{ {
/* ... = objc_exception_extract(&_stackExceptionData); */ tree t;
tree func_params t = build_fold_addr_expr (cur_try_context->stack_decl);
= tree_cons (NULL_TREE, t = tree_cons (NULL, t, NULL);
build_unary_op (ADDR_EXPR, t = build_function_call (objc_exception_extract_decl, t);
TREE_VALUE (objc_stack_exception_data), 0), t = convert (TREE_TYPE (decl), t);
NULL_TREE); t = build (MODIFY_EXPR, void_type_node, decl, t);
assemble_external (objc_exception_extract_decl); return t;
return build_function_call (objc_exception_extract_decl, func_params);
} }
static void /* Build
objc_build_try_exit_fragment (void) if (objc_exception_match(obj_get_class(TYPE), _caught)
{ BODY
/* objc_exception_try_exit(&_stackExceptionData); */ else if (...)
...
tree func_params else
= tree_cons (NULL_TREE, {
build_unary_op (ADDR_EXPR, _rethrow = _caught;
TREE_VALUE (objc_stack_exception_data), 0), objc_exception_try_exit(&_stack);
NULL_TREE); }
from the sequence of CATCH_EXPRs in the current try context. */
assemble_external (objc_exception_try_exit_decl);
c_expand_expr_stmt (build_function_call (objc_exception_try_exit_decl,
func_params));
}
static void static tree
objc_build_extract_fragment (void) next_sjlj_build_catch_list (void)
{ {
/* } else { tree_stmt_iterator i = tsi_start (cur_try_context->catch_list);
_rethrowException = objc_exception_extract(&_stackExceptionData); tree catch_seq, t;
} */ tree *last = &catch_seq;
bool saw_id = false;
c_finish_then (objc_exit_block ()); for (; !tsi_end_p (i); tsi_next (&i))
{
c_begin_else (0); tree stmt = tsi_stmt (i);
objc_enter_block (); tree type = CATCH_TYPES (stmt);
c_expand_expr_stmt (build_modify_expr tree body = CATCH_BODY (stmt);
(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--;
}
tree if (type == NULL)
objc_build_try_prologue (void) {
{ *last = body;
/* { // new scope saw_id = true;
struct _objc_exception_data _stackExceptionData; break;
volatile id _rethrowException = nil; }
{ // begin TRY-CATCH scope else
objc_exception_try_enter(&_stackExceptionData); {
if (!_setjmp(&_stackExceptionData.buf)) { */ 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) *last = t;
fatal_error ("Use `-fobjc-exceptions' to enable Objective-C exception syntax"); last = &COND_EXPR_ELSE (t);
}
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 if (!saw_id)
objc_build_try_epilogue (int also_catch_prologue)
{
if (also_catch_prologue)
{ {
/* } else { t = build (MODIFY_EXPR, void_type_node, cur_try_context->rethrow_decl,
register id _caughtException = objc_exception_extract( &_stackExceptionData); cur_try_context->caught_decl);
objc_exception_try_enter(&_stackExceptionData); annotate_with_locus (t, cur_try_context->end_catch_locus);
if(!_setjmp(&_stackExceptionData.buf)) { append_to_statement_list (t, last);
if (0) { */
c_finish_then (objc_exit_block ()); t = next_sjlj_build_try_exit ();
annotate_with_locus (t, cur_try_context->end_catch_locus);
c_begin_else (0); append_to_statement_list (t, last);
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);
} }
else
{ /* !also_catch_prologue */
/* } else { return catch_seq;
_rethrowException = objc_exception_extract( &_stackExceptionData);
}
} */
objc_build_extract_fragment ();
objc_exit_block ();
}
} }
void /* Build a complete @try-@catch-@finally block for legacy Darwin setjmp
objc_build_catch_stmt (tree catch_expr) exception handling. We aim to build:
{
/* } 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;
#ifndef OBJCPLUS {
/* Yet another C/C++ impedance mismatch. */ struct _objc_exception_data _stack;
catch_expr = TREE_PURPOSE (catch_expr); id volatile _rethrow = 0;
#endif 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); If CATCH-LIST is empty, we can omit all of the block containing
var_type = TREE_VALUE (TREE_PURPOSE (catch_expr)); "_caught" except for the setting of _rethrow. Note the use of
if (TREE_CODE (var_name) == INDIRECT_REF) a real TRY_FINALLY_EXPR here, which is not involved in EH per-se,
var_name = TREE_OPERAND (var_name, 0); but handles goto and other exits from the block. */
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) static tree
fatal_error ("Use `-fobjc-exceptions' to enable Objective-C exception syntax"); 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))) /* Create the declarations involved. */
fatal_error ("`@catch' parameter is not a known Objective-C class type"); 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 rethrow_decl = objc_create_temporary_var (id_type);
superclasses of the 'var_type' class. */ cur_try_context->rethrow_decl = rethrow_decl;
for (prev_catch = objc_catch_type; TREE_VALUE (prev_catch); TREE_THIS_VOLATILE (rethrow_decl) = 1;
prev_catch = TREE_CHAIN (prev_catch)) TREE_CHAIN (rethrow_decl) = stack_decl;
{
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); /* 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); /* Build the outermost TRY_FINALLY_EXPR. */
catch_count_stack->val++; try_fin = build (TRY_FINALLY_EXPR, void_type_node, NULL, NULL);
c_begin_if_stmt (); annotate_with_locus (try_fin, cur_try_context->try_locus);
if_nesting_count++; TREE_SIDE_EFFECTS (try_fin) = 1;
append_to_statement_list (try_fin, &BIND_EXPR_BODY (bind));
if (catch_id) /* Create the complete catch sequence. */
cond = integer_one_node; if (cur_try_context->catch_list)
else
{ {
cond = get_class_reference (OBJC_TYPE_NAME (var_type)); tree caught_decl = objc_build_exc_ptr ();
catch_seq = build_stmt (BIND_EXPR, caught_decl, NULL, NULL);
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_finish_if_cond (cond, 0, 0); t = next_sjlj_build_exc_extract (caught_decl);
objc_enter_block (); append_to_statement_list (t, &BIND_EXPR_BODY (catch_seq));
objc_declare_variable (RID_REGISTER, var_name,
build_pointer_type (var_type),
TREE_VALUE (objc_caught_exception));
}
void t = next_sjlj_build_enter_and_setjmp ();
objc_build_catch_epilogue (void) COND_EXPR_THEN (t) = next_sjlj_build_exc_extract (rethrow_decl);
{ COND_EXPR_ELSE (t) = next_sjlj_build_catch_list ();
/* } else { append_to_statement_list (t, &BIND_EXPR_BODY (catch_seq));
_rethrowException = _caughtException; }
objc_exception_try_exit(&_stackExceptionData); else
} catch_seq = next_sjlj_build_exc_extract (rethrow_decl);
} else { annotate_with_locus (catch_seq, cur_try_context->end_try_locus);
_rethrowException = objc_exception_extract(&_stackExceptionData);
}
}
} // end TRY-CATCH scope
*/
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); /* Build the complete FINALLY statement list. */
objc_enter_block (); t = next_sjlj_build_try_exit ();
c_expand_expr_stmt t = build_stmt (COND_EXPR,
(build_modify_expr lang_hooks.truthvalue_conversion (rethrow_decl),
(TREE_VALUE (objc_rethrow_exception), NULL, t);
NOP_EXPR, annotate_with_locus (t, cur_try_context->finally_locus);
TREE_VALUE (objc_caught_exception))); append_to_statement_list (t, &TREE_OPERAND (try_fin, 1));
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);
objc_build_extract_fragment (); append_to_statement_list (cur_try_context->finally_body,
&TREE_OPERAND (try_fin, 1));
c_finish_else (objc_exit_block ()); t = tree_cons (NULL, rethrow_decl, NULL);
c_finish_if_stmt (1); t = build_function_call (objc_exception_throw_decl, t);
if_nesting_count--; t = build_stmt (COND_EXPR,
objc_exit_block (); 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). */ return bind;
while (TREE_VALUE (objc_catch_type))
objc_catch_type = TREE_CHAIN (objc_catch_type);
objc_catch_type = TREE_PURPOSE (objc_catch_type);
} }
tree /* Called just after parsing the @try and its associated BODY. We now
objc_build_finally_prologue (void) 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 struct objc_try_context *c = xcalloc (1, sizeof (*c));
if (!_rethrowException) { c->outer = cur_try_context;
objc_exception_try_exit(&_stackExceptionData); 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 (); /* Begin a new scope that the entire catch clause will live in. */
if_nesting_count++; compound = c_begin_compound_stmt (1);
c_finish_if_cond (build_unary_op (TRUTH_NOT_EXPR, /* Turn the raw declarator/declspecs into a decl in the current scope. */
TREE_VALUE (objc_rethrow_exception), 0), decl = define_decl (TREE_VALUE (TREE_PURPOSE (parm)),
0, 0); TREE_PURPOSE (TREE_PURPOSE (parm)));
objc_enter_block ();
objc_build_try_exit_fragment ();
c_finish_then (objc_exit_block ());
c_finish_if_stmt (1);
if_nesting_count--;
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 /* Verify that the type of the catch is valid. It must be a pointer
objc_build_finally_epilogue (void) to an Objective-C class, or "id" (which is catch-all). */
{ type = TREE_TYPE (decl);
/* if (_rethrowException) { if (POINTER_TYPE_P (type) && objc_is_object_id (TREE_TYPE (type)))
objc_exception_throw(_rethrowException); 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 (); /* Record the data for the catch in the try context so that we can
if_nesting_count++; 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); /* Initialize the decl from the EXC_PTR_EXPR we get from the runtime. */
objc_enter_block (); t = objc_build_exc_ptr ();
objc_build_throw_stmt (TREE_VALUE (objc_rethrow_exception)); t = convert (TREE_TYPE (decl), t);
c_finish_then (objc_exit_block ()); t = build (MODIFY_EXPR, void_type_node, decl, t);
c_finish_if_stmt (1); add_stmt (t);
if_nesting_count--; }
objc_exit_block (); /* Called just after parsing the closing brace of a @catch clause. Close
objc_rethrow_exception = TREE_CHAIN (objc_rethrow_exception); the open binding level, and record a CATCH_EXPR for it. */
objc_stack_exception_data = TREE_CHAIN (objc_stack_exception_data);
val_stack_pop (&exc_binding_stack); void
return objc_exit_block (); 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 /* Called after parsing a @finally clause and its associated BODY.
objc_build_try_catch_finally_stmt (int has_catch, int has_finally) Record the body for later placement. */
{
/* 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;
if (!flag_objc_exceptions) void
fatal_error ("Use `-fobjc-exceptions' to enable Objective-C exception syntax"); 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 void
(even though sensible code can be generated nonetheless). */ 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'"); error ("`@try' without `@catch' or `@finally'");
/* We shall now do something truly disgusting. We shall remove the /* If we're doing Darwin setjmp exceptions, build the big nasty. */
'try_catch_blk' and 'finally_blk' from the 'outer_blk' statement if (flag_objc_sjlj_exceptions)
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 if (!cur_try_context->finally_body)
construct the 'outer_blk' lazily. */ {
cur_try_context->finally_locus = input_location;
TREE_CHAIN (try_catch_blk) = TREE_CHAIN (finally_blk) = NULL_TREE; cur_try_context->end_finally_locus = input_location;
try_catch_expr = build1 (STMT_EXPR, void_type_node, try_catch_blk); }
TREE_SIDE_EFFECTS (try_catch_expr) = 1; stmt = next_sjlj_build_try_catch_finally ();
finally_expr = build1 (STMT_EXPR, void_type_node, finally_blk); }
TREE_SIDE_EFFECTS (finally_expr) = 1; else
try_finally_expr = build (TRY_FINALLY_EXPR, void_type_node, try_catch_expr, {
finally_expr); /* Otherwise, nest the CATCH inside a FINALLY. */
TREE_SIDE_EFFECTS (try_finally_expr) = 1; stmt = c->try_body;
try_finally_stmt = build_stmt (EXPR_STMT, try_finally_expr); if (c->catch_list)
TREE_CHAIN (prec_stmt) = try_finally_stmt; {
TREE_CHAIN (try_finally_stmt) = succ_stmt; stmt = build_stmt (TRY_CATCH_EXPR, stmt, c->catch_list);
annotate_with_locus (stmt, cur_try_context->try_locus);
return outer_blk; /* the whole enchilada */ }
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 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; tree func_params;
if (!flag_objc_exceptions) if (throw_expr == NULL)
fatal_error ("Use `-fobjc-exceptions' to enable Objective-C exception syntax"); {
/* If we're not inside a @catch block, there is no "current
objc_enter_block (); exception" to be rethrown. */
objc_eval_once if (cur_try_context == NULL
= tree_cons (NULL_TREE, || cur_try_context->current_catch == NULL)
objc_declare_variable (RID_AUTO, {
get_identifier (UTAG_EVALONCE_VAR), error ("%<@throw%> (rethrow) used outside of a @catch block");
id_type, return;
sync_expr), }
objc_eval_once);
objc_build_try_prologue (); /* Otherwise the object is still sitting in the EXC_PTR_EXPR
objc_enter_block (); value that we get from the runtime. */
func_params = tree_cons (NULL_TREE, throw_expr = objc_build_exc_ptr ();
TREE_VALUE (objc_eval_once), }
NULL_TREE);
assemble_external (objc_sync_enter_decl); /* A throw is just a call to the runtime throw function with the
c_expand_expr_stmt (build_function_call object as a parameter. */
(objc_sync_enter_decl, func_params)); func_params = tree_cons (NULL, throw_expr, NULL);
add_stmt (build_function_call (objc_exception_throw_decl, func_params));
objc_init_exceptions ();
} }
tree void
objc_build_synchronized_epilogue (void) objc_build_synchronized (location_t start_locus, tree mutex, tree body)
{ {
/* } tree args, call;
@finally {
objc_sync_exit( _eval_once );
}
} */
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 (); /* Build the mutex unlock. */
objc_build_try_epilogue (0); args = tree_cons (NULL, mutex, NULL);
objc_build_finally_prologue (); call = build_function_call (objc_sync_exit_decl, args);
func_params = tree_cons (NULL_TREE, TREE_VALUE (objc_eval_once), annotate_with_locus (call, input_location);
NULL_TREE);
assemble_external (objc_sync_exit_decl); /* Put the that and the body in a TRY_FINALLY. */
c_expand_expr_stmt (build_function_call (objc_sync_exit_decl, objc_begin_try_stmt (start_locus, body);
func_params)); objc_build_finally_clause (input_location, call);
objc_build_try_catch_finally_stmt (0, 1); objc_finish_try_stmt ();
return objc_exit_block ();
} }
/* Predefine the following data type: /* Predefine the following data type:
struct _objc_exception_data struct _objc_exception_data
...@@ -3259,7 +3249,7 @@ objc_build_synchronized_epilogue (void) ...@@ -3259,7 +3249,7 @@ objc_build_synchronized_epilogue (void)
#endif #endif
static void static void
build_objc_exception_stuff (void) build_next_objc_exception_stuff (void)
{ {
tree field_decl, field_decl_chain, index, temp_type; tree field_decl, field_decl_chain, index, temp_type;
...@@ -3270,6 +3260,7 @@ build_objc_exception_stuff (void) ...@@ -3270,6 +3260,7 @@ build_objc_exception_stuff (void)
write_symbols = NO_DEBUG; write_symbols = NO_DEBUG;
debug_hooks = &do_nothing_debug_hooks; debug_hooks = &do_nothing_debug_hooks;
objc_exception_data_template objc_exception_data_template
= start_struct (RECORD_TYPE, get_identifier (UTAG_EXCDATA)); = start_struct (RECORD_TYPE, get_identifier (UTAG_EXCDATA));
...@@ -3317,20 +3308,7 @@ build_objc_exception_stuff (void) ...@@ -3317,20 +3308,7 @@ build_objc_exception_stuff (void)
= builtin_function (TAG_EXCEPTIONTRYENTER, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); = builtin_function (TAG_EXCEPTIONTRYENTER, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE);
objc_exception_try_exit_decl objc_exception_try_exit_decl
= builtin_function (TAG_EXCEPTIONTRYEXIT, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); = 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); */ /* int objc_exception_match(id, id); */
temp_type = build_function_type (integer_type_node, temp_type = build_function_type (integer_type_node,
tree_cons (NULL_TREE, id_type, tree_cons (NULL_TREE, id_type,
...@@ -3343,6 +3321,32 @@ build_objc_exception_stuff (void) ...@@ -3343,6 +3321,32 @@ build_objc_exception_stuff (void)
debug_hooks = save_hooks; 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 <classname> {
struct objc_class *isa; struct objc_class *isa;
... ...
......
...@@ -39,16 +39,13 @@ void finish_method_def (void); ...@@ -39,16 +39,13 @@ void finish_method_def (void);
tree start_protocol (enum tree_code, tree, tree); tree start_protocol (enum tree_code, tree, tree);
void finish_protocol (tree); void finish_protocol (tree);
tree objc_build_throw_stmt (tree); void objc_build_throw_stmt (tree);
tree objc_build_try_catch_finally_stmt (int, int); void objc_begin_try_stmt (location_t, tree);
void objc_build_synchronized_prologue (tree); void objc_begin_catch_clause (tree);
tree objc_build_synchronized_epilogue (void); void objc_finish_catch_clause (void);
tree objc_build_try_prologue (void); void objc_build_finally_clause (location_t, tree);
void objc_build_try_epilogue (int); void objc_finish_try_stmt (void);
void objc_build_catch_stmt (tree); void objc_build_synchronized (location_t, tree, tree);
void objc_build_catch_epilogue (void);
tree objc_build_finally_prologue (void);
tree objc_build_finally_epilogue (void);
tree is_ivar (tree, tree); tree is_ivar (tree, tree);
int is_private (tree); int is_private (tree);
...@@ -282,7 +279,6 @@ enum objc_tree_index ...@@ -282,7 +279,6 @@ enum objc_tree_index
OCTI_LOCAL_EXCEPTION_DECL, OCTI_LOCAL_EXCEPTION_DECL,
OCTI_RETHROW_EXCEPTION_DECL, OCTI_RETHROW_EXCEPTION_DECL,
OCTI_EVAL_ONCE_DECL, OCTI_EVAL_ONCE_DECL,
OCTI_EXCEPTION_BLK_STACK,
OCTI_CATCH_TYPE, OCTI_CATCH_TYPE,
OCTI_MAX OCTI_MAX
...@@ -402,8 +398,6 @@ extern GTY(()) tree objc_global_trees[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_caught_exception objc_global_trees[OCTI_LOCAL_EXCEPTION_DECL]
#define objc_rethrow_exception objc_global_trees[OCTI_RETHROW_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_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_catch_type objc_global_trees[OCTI_CATCH_TYPE]
#define objc_method_template objc_global_trees[OCTI_METH_TEMPL] #define objc_method_template objc_global_trees[OCTI_METH_TEMPL]
......
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> 2004-06-17 Zack Weinberg <zack@codesourcery.com>
Bug 14610 Bug 14610
......
/* 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;
}
}
/* Test if the compiler accepts @throw / @try..@catch..@finally /* Test if the compiler accepts @throw / @try..@catch..@finally syntax. */
syntax. This will only be usable on MacOS X 10.3 and later,
but may be compiled on all targets. */
/* Developed by Ziemowit Laski <zlaski@apple.com>. */ /* Developed by Ziemowit Laski <zlaski@apple.com>. */
/* { dg-options "-fnext-runtime -fobjc-exceptions" } */ /* { dg-options "-fobjc-exceptions" } */
/* { dg-do compile } */ /* { dg-do compile } */
#include <objc/Object.h> #include <objc/Object.h>
......
...@@ -2,11 +2,9 @@ ...@@ -2,11 +2,9 @@
all uncaught exceptions. */ all uncaught exceptions. */
/* Developed by Ziemowit Laski <zlaski@apple.com>. */ /* Developed by Ziemowit Laski <zlaski@apple.com>. */
/* { dg-options "-fobjc-exceptions -lobjc" } */ /* { dg-options "-fobjc-exceptions" } */
/* { dg-do run { target *-*-darwin* } } */ /* { dg-do run } */
#include <objc/objc.h>
#include <objc/objc-runtime.h>
#include <objc/Object.h> #include <objc/Object.h>
#include <stdio.h> #include <stdio.h>
...@@ -72,10 +70,6 @@ void test (Object* sendPort) ...@@ -72,10 +70,6 @@ void test (Object* sendPort)
CHECK_IF(!sendPort); CHECK_IF(!sendPort);
CHECK_IF(!cleanupPorts); 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) { int main (void) {
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
/* Author: Ziemowit Laski <zlaski@apple.com> */ /* Author: Ziemowit Laski <zlaski@apple.com> */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-fnext-runtime -fobjc-exceptions" } */ /* { dg-options "-fobjc-exceptions" } */
#include <objc/Object.h> #include <objc/Object.h>
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
/* Author: Ziemowit Laski <zlaski@apple.com> */ /* Author: Ziemowit Laski <zlaski@apple.com> */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-Wall -fnext-runtime -fobjc-exceptions" } */ /* { dg-options "-Wall -fobjc-exceptions" } */
@interface Exception @interface Exception
@end @end
......
/* 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" } */
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment