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>
* c-typeck.c (tagged_types_tu_compatible_p <case UNION_TYPE>):
......
......@@ -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. */
......
......@@ -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. */
......
......@@ -71,11 +71,14 @@ enum decl_context
/* 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"
......
......@@ -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)
......
......@@ -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
%{
......@@ -1515,7 +1514,7 @@ designator:
;
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
;
......
......@@ -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);
......
......@@ -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\"
......
......@@ -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 ();
......
......@@ -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;
}
/* 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 ();
}
/* 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;
...
......
......@@ -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]
......
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
......
/* 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
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>
......
......@@ -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) {
......
......@@ -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>
......
......@@ -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
......
/* 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