aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2001-03-28 03:04:51 -0800
committerRichard Henderson <rth@gcc.gnu.org>2001-03-28 03:04:51 -0800
commit52a11cbfcf0cfb32628b6953588b6af4037ac0b6 (patch)
treea923c8785a06871784c5177530130063c4925f5a /gcc/cp
parentce1c98ea459813570b4588427030daa03958fda6 (diff)
downloadgcc-52a11cbfcf0cfb32628b6953588b6af4037ac0b6.zip
gcc-52a11cbfcf0cfb32628b6953588b6af4037ac0b6.tar.gz
gcc-52a11cbfcf0cfb32628b6953588b6af4037ac0b6.tar.bz2
IA-64 ABI Exception Handling.
From-SVN: r40924
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog56
-rw-r--r--gcc/cp/cp-tree.def5
-rw-r--r--gcc/cp/cp-tree.h23
-rw-r--r--gcc/cp/decl.c13
-rw-r--r--gcc/cp/decl2.c4
-rw-r--r--gcc/cp/dump.c13
-rw-r--r--gcc/cp/error.c2
-rw-r--r--gcc/cp/except.c970
-rw-r--r--gcc/cp/expr.c14
-rw-r--r--gcc/cp/semantics.c39
-rw-r--r--gcc/cp/tree.c1
11 files changed, 448 insertions, 692 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 9540023..0db7144 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,61 @@
2001-03-28 Richard Henderson <rth@redhat.com>
+ IA-64 ABI Exception Handling:
+ * cp-tree.def (EH_SPEC_BLOCK): New.
+ (MUST_NOT_THROW_EXPR): New.
+ * cp-tree.h: Update changed function declarations.
+ (CPTI_PUSH_EXCEPTION_IDENTIFIER): Remove.
+ (CPTI_CALL_UNEXPECTED): New.
+ (struct cp_language_function): Rename x_eh_spec_try_block
+ to x_eh_spec_block.
+ (EH_SPEC_STMTS, EH_SPEC_RAISES): New.
+ * decl.c (current_binding_level): If no current function
+ bindings, revert to scope_chain.
+ (initialize_predefined_identifiers): Remove __cp_push_exception.
+ (store_parm_decls): Use begin_eh_spec_block.
+ (finish_function): Use finish_eh_spec_block.
+ (mark_lang_function): Update for name changes.
+ * decl2.c (finish_file): No mark_all_runtime_matches.
+ * dump.c (cp_dump_tree): Handle new tree codes.
+ * error.c (dump_expr) [BIND_EXPR]: Fix typo.
+ * except.c (catch_language_init, catch_language): Remove.
+ (init_exception_processing): Don't set language code.
+ Initialize call_unexpected_node, protect_cleanup_actions,
+ eh_personality_libfunc, lang_eh_runtime_type.
+ (call_eh_info, push_eh_info, get_eh_info, get_eh_value): Remove.
+ (get_eh_type, get_eh_caught, get_eh_handlers): Remove.
+ (prepare_eh_type): Split out type canonicalizations ...
+ (build_eh_type_type): ... from here.
+ (build_eh_type_type_ref): Remove.
+ (mark_all_runtime_matches): Remove.
+ (build_exc_ptr): New.
+ (do_begin_catch, do_end_catch): New.
+ (do_pop_exception): Remove.
+ (build_terminate_handler): Remove.
+ (choose_personality_routine): Split out language choice from ...
+ (initialize_handler_parm): ... here.
+ Use MUST_NOT_THROW_EXPR.
+ (expand_start_catch_block): Use do_begin_catch. Simplify Java
+ exception object handling.
+ (expand_start_eh_spec, expand_end_eh_spec): Remove.
+ (expand_exception_blocks, alloc_eh_object): Remove.
+ (begin_eh_spec_block, finish_eh_spec_block): New.
+ (do_allocate_exception, do_free_exception): New.
+ (expand_throw): Merge into ...
+ (build_throw): ... here. Update for abi.
+ * expr.c (cplus_expand_expr): No expand_internal_throw.
+ Handle MUST_NOT_THROW_EXPR.
+ * pt.c (tsubst_expr): Handle EH_SPEC_BLOCK.
+ * semantics.c (*) Update for except.h name changes.
+ (genrtl_try_block): No protect_with_terminate.
+ (genrtl_eh_spec_block): New.
+ (genrtl_handler): Don't emit the goto here.
+ (cp_expand_stmt): Handle EH_SPEC_BLOCK.
+ (genrtl_finish_function): Don't expand_exception_blocks.
+ * tree.c (cp_statement_code_p): Handle EH_SPEC_BLOCK.
+
+2001-03-28 Richard Henderson <rth@redhat.com>
+
* decl.c (struct named_label_list): Rename eh_region to
in_try_scope, add in_catch_scope.
(struct binding_level): Rename eh_region to is_try_scope,
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 3d514b5..5e89189 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -236,8 +236,13 @@ DEFTREECODE (START_CATCH_STMT, "start_catch_stmt", 'e', 0)
DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 2)
DEFTREECODE (RETURN_INIT, "return_init", 'e', 2)
DEFTREECODE (TRY_BLOCK, "try_block", 'e', 2)
+DEFTREECODE (EH_SPEC_BLOCK, "eh_spec_block", 'e', 2)
DEFTREECODE (HANDLER, "handler", 'e', 2)
+/* A MUST_NOT_THROW_EXPR wraps an expression that may not
+ throw, and must call terminate if it does. */
+DEFTREECODE (MUST_NOT_THROW_EXPR, "must_not_throw_expr", 'e', 1)
+
DEFTREECODE (TAG_DEFN, "tag_defn", 'e', 0)
/* And some codes for expressing conversions for overload resolution. */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 91c280c..449a3bd 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -616,7 +616,6 @@ enum cp_tree_index
CPTI_PFN_IDENTIFIER,
CPTI_PFN_OR_DELTA2_IDENTIFIER,
CPTI_VPTR_IDENTIFIER,
- CPTI_PUSH_EXCEPTION_IDENTIFIER,
CPTI_STD_IDENTIFIER,
CPTI_LANG_NAME_C,
@@ -627,6 +626,7 @@ enum cp_tree_index
CPTI_NULL,
CPTI_JCLASS,
CPTI_TERMINATE,
+ CPTI_CALL_UNEXPECTED,
CPTI_ATEXIT,
CPTI_DSO_HANDLE,
CPTI_DCAST,
@@ -740,9 +740,6 @@ extern tree cp_global_trees[CPTI_MAX];
#define pfn_identifier cp_global_trees[CPTI_PFN_IDENTIFIER]
#define pfn_or_delta2_identifier cp_global_trees[CPTI_PFN_OR_DELTA2_IDENTIFIER]
#define vptr_identifier cp_global_trees[CPTI_VPTR_IDENTIFIER]
-/* The name of the function to call to push an exception onto the
- exception stack. */
-#define cp_push_exception_identifier cp_global_trees[CPTI_PUSH_EXCEPTION_IDENTIFIER]
/* The name of the std namespace. */
#define std_identifier cp_global_trees[CPTI_STD_IDENTIFIER]
#define lang_name_c cp_global_trees[CPTI_LANG_NAME_C]
@@ -761,6 +758,9 @@ extern tree cp_global_trees[CPTI_MAX];
/* The declaration for `std::terminate'. */
#define terminate_node cp_global_trees[CPTI_TERMINATE]
+/* The declaration for "__cxa_call_unexpected". */
+#define call_unexpected_node cp_global_trees[CPTI_CALL_UNEXPECTED]
+
/* A pointer to `std::atexit'. */
#define atexit_node cp_global_trees[CPTI_ATEXIT]
@@ -872,7 +872,7 @@ struct cp_language_function
tree x_dtor_label;
tree x_current_class_ptr;
tree x_current_class_ref;
- tree x_eh_spec_try_block;
+ tree x_eh_spec_block;
tree x_in_charge_parm;
tree x_vtt_parm;
@@ -916,10 +916,10 @@ struct cp_language_function
#define current_class_ref \
(cfun ? cp_function_chain->x_current_class_ref : NULL_TREE)
-/* The TRY_BLOCK for the exception-specifiers for the current
+/* The EH_SPEC_BLOCK for the exception-specifiers for the current
function, if any. */
-#define current_eh_spec_try_block cp_function_chain->x_eh_spec_try_block
+#define current_eh_spec_block cp_function_chain->x_eh_spec_block
/* The `__in_chrg' parameter for the current function. Only used for
constructors and destructors. */
@@ -3035,6 +3035,9 @@ extern int flag_new_for_scope;
#define TRY_STMTS(NODE) TREE_OPERAND (TRY_BLOCK_CHECK (NODE), 0)
#define TRY_HANDLERS(NODE) TREE_OPERAND (TRY_BLOCK_CHECK (NODE), 1)
+#define EH_SPEC_STMTS(NODE) TREE_OPERAND (EH_SPEC_BLOCK_CHECK (NODE), 0)
+#define EH_SPEC_RAISES(NODE) TREE_OPERAND (EH_SPEC_BLOCK_CHECK (NODE), 1)
+
/* Nonzero if this try block is a function try block. */
#define FN_TRY_BLOCK_P(NODE) TREE_LANG_FLAG_3 (TRY_BLOCK_CHECK (NODE))
#define HANDLER_PARMS(NODE) TREE_OPERAND (HANDLER_CHECK (NODE), 0)
@@ -4000,9 +4003,9 @@ extern void init_exception_processing PARAMS ((void));
extern tree expand_start_catch_block PARAMS ((tree));
extern void expand_end_catch_block PARAMS ((tree));
extern void expand_builtin_throw PARAMS ((void));
-extern tree expand_start_eh_spec PARAMS ((void));
-extern void expand_end_eh_spec PARAMS ((tree, tree));
+extern void expand_eh_spec_block PARAMS ((tree));
extern void expand_exception_blocks PARAMS ((void));
+extern tree build_exc_ptr PARAMS ((void));
extern tree build_throw PARAMS ((tree));
extern void mark_all_runtime_matches PARAMS ((void));
extern int nothrow_libfn_p PARAMS ((tree));
@@ -4256,6 +4259,8 @@ extern tree finish_case_label PARAMS ((tree, tree));
extern tree finish_goto_stmt PARAMS ((tree));
extern tree begin_try_block PARAMS ((void));
extern void finish_try_block PARAMS ((tree));
+extern tree begin_eh_spec_block PARAMS ((void));
+extern void finish_eh_spec_block PARAMS ((tree, tree));
extern void finish_handler_sequence PARAMS ((tree));
extern tree begin_function_try_block PARAMS ((void));
extern void finish_function_try_block PARAMS ((tree));
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 366d37c..b96545d 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -478,7 +478,7 @@ struct binding_level
/* The binding level currently in effect. */
#define current_binding_level \
- (cfun \
+ (cfun && cp_function_chain->bindings \
? cp_function_chain->bindings \
: scope_chain->bindings)
@@ -6306,7 +6306,6 @@ initialize_predefined_identifiers ()
{ VTABLE_PFN_NAME, &pfn_identifier, 0 },
{ "__pfn_or_delta2", &pfn_or_delta2_identifier, 0 },
{ "_vptr", &vptr_identifier, 0 },
- { "__cp_push_exception", &cp_push_exception_identifier, 0 },
{ "__vtt_parm", &vtt_parm_identifier, 0 },
{ "std", &std_identifier, 0 },
{ NULL, NULL, 0 }
@@ -13721,7 +13720,7 @@ store_parm_decls (current_function_parms)
if (flag_exceptions && !processing_template_decl
&& flag_enforce_eh_specs
&& TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
- current_eh_spec_try_block = expand_start_eh_spec ();
+ current_eh_spec_block = begin_eh_spec_block ();
}
@@ -13966,9 +13965,9 @@ finish_function (flags)
if (flag_exceptions && !processing_template_decl
&& flag_enforce_eh_specs
&& TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
- expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS
- (TREE_TYPE (current_function_decl)),
- current_eh_spec_try_block);
+ finish_eh_spec_block (TYPE_RAISES_EXCEPTIONS
+ (TREE_TYPE (current_function_decl)),
+ current_eh_spec_block);
}
/* If we're saving up tree structure, tie off the function now. */
@@ -14395,7 +14394,7 @@ mark_lang_function (p)
ggc_mark_tree (p->x_dtor_label);
ggc_mark_tree (p->x_current_class_ptr);
ggc_mark_tree (p->x_current_class_ref);
- ggc_mark_tree (p->x_eh_spec_try_block);
+ ggc_mark_tree (p->x_eh_spec_block);
ggc_mark_tree_varray (p->x_local_names);
mark_named_label_lists (&p->x_named_labels, &p->x_named_label_uses);
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index a8300b9..35c8ca7 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -3621,10 +3621,6 @@ finish_file ()
}
}
- /* Mark all functions that might deal with exception-handling as
- referenced. */
- mark_all_runtime_matches ();
-
/* We lie to the back-end, pretending that some functions are
not defined when they really are. This keeps these functions
from being put out unnecessarily. But, we must stop lying
diff --git a/gcc/cp/dump.c b/gcc/cp/dump.c
index a0982a6..a4033c3 100644
--- a/gcc/cp/dump.c
+++ b/gcc/cp/dump.c
@@ -188,6 +188,13 @@ cp_dump_tree (di, t)
dump_next_stmt (di, t);
break;
+ case EH_SPEC_BLOCK:
+ dump_stmt (di, t);
+ dump_child ("body", EH_SPEC_STMTS (t));
+ dump_child ("raises", EH_SPEC_RAISES (t));
+ dump_next_stmt (di, t);
+ break;
+
case PTRMEM_CST:
dump_child ("clas", PTRMEM_CST_CLASS (t));
dump_child ("mbr", PTRMEM_CST_MEMBER (t));
@@ -227,6 +234,12 @@ cp_dump_tree (di, t)
dump_next_stmt (di, t);
break;
+ case MUST_NOT_THROW_EXPR:
+ dump_stmt (di, t);
+ dump_child ("body", TREE_OPERAND (t, 0));
+ dump_next_stmt (di, t);
+ break;
+
case SUBOBJECT:
dump_stmt (di, t);
dump_child ("clnp", TREE_OPERAND (t, 0));
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index feb4736..7d2f1fa 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -2104,7 +2104,7 @@ dump_expr (t, flags)
break;
case BIND_EXPR:
- output_add_character (scratch_buffer, '}');
+ output_add_character (scratch_buffer, '{');
dump_expr (TREE_OPERAND (t, 1), flags & ~TFF_EXPR_IN_PARENS);
output_add_character (scratch_buffer, '}');
break;
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index 4f5bde6..600a21a 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -34,299 +34,67 @@ Boston, MA 02111-1307, USA. */
#include "output.h"
#include "except.h"
#include "toplev.h"
-#include "eh-common.h"
static void push_eh_cleanup PARAMS ((tree));
+static tree prepare_eh_type PARAMS ((tree));
static tree build_eh_type_type PARAMS ((tree));
-static tree call_eh_info PARAMS ((void));
-static void push_eh_info PARAMS ((void));
-static tree get_eh_info PARAMS ((void));
-static tree get_eh_value PARAMS ((void));
-#if 0
-static tree get_eh_type PARAMS ((void));
-static tree get_eh_caught PARAMS ((void));
-static tree get_eh_handlers PARAMS ((void));
-#endif
+static tree do_begin_catch PARAMS ((void));
static int dtor_nothrow PARAMS ((tree));
-static tree do_pop_exception PARAMS ((tree));
-static tree build_eh_type_type_ref PARAMS ((tree));
-static tree build_terminate_handler PARAMS ((void));
-static tree alloc_eh_object PARAMS ((tree));
+static tree do_end_catch PARAMS ((tree));
+static void push_eh_cleanup PARAMS ((tree));
+static bool decl_is_java_type PARAMS ((tree decl, int err));
+static void choose_personality_routine PARAMS ((bool));
+static void initialize_handler_parm PARAMS ((tree, tree));
+static tree do_allocate_exception PARAMS ((tree));
+static tree do_free_exception PARAMS ((tree));
static int complete_ptr_ref_or_void_ptr_p PARAMS ((tree, tree));
static bool is_admissible_throw_operand PARAMS ((tree));
static int can_convert_eh PARAMS ((tree, tree));
static void check_handlers_1 PARAMS ((tree, tree));
-static void initialize_handler_parm PARAMS ((tree));
-static tree expand_throw PARAMS ((tree));
-static int decl_is_java_type PARAMS ((tree decl, int err));
#include "decl.h"
#include "obstack.h"
-/* In a given translation unit we are constrained to catch only C++
- types or only Java types. `catch_language' holds the current type,
- and `catch_language_init' registers whether `catch_language' has
- been set. */
-
-static int catch_language_init = 0;
-static int catch_language;
-
-/* ======================================================================
- Briefly the algorithm works like this:
-
- When a constructor or start of a try block is encountered,
- push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
- new entry in the unwind protection stack and returns a label to
- output to start the protection for that block.
-
- When a destructor or end try block is encountered, pop_eh_entry
- (&eh_stack) is called. Pop_eh_entry () returns the eh_entry it
- created when push_eh_entry () was called. The eh_entry structure
- contains three things at this point. The start protect label,
- the end protect label, and the exception handler label. The end
- protect label should be output before the call to the destructor
- (if any). If it was a destructor, then its parse tree is stored
- in the finalization variable in the eh_entry structure. Otherwise
- the finalization variable is set to NULL to reflect the fact that
- it is the end of a try block. Next, this modified eh_entry node
- is enqueued in the finalizations queue by calling
- enqueue_eh_entry (&queue,entry).
-
- +---------------------------------------------------------------+
- |XXX: Will need modification to deal with partially |
- | constructed arrays of objects |
- | |
- | Basically, this consists of keeping track of how many |
- | of the objects have been constructed already (this |
- | should be in a register though, so that shouldn't be a |
- | problem. |
- +---------------------------------------------------------------+
-
- When a catch block is encountered, there is a lot of work to be
- done.
-
- Since we don't want to generate the catch block inline with the
- regular flow of the function, we need to have some way of doing
- so. Luckily, we can use sequences to defer the catch sections.
- When the start of a catch block is encountered, we start the
- sequence. After the catch block is generated, we end the
- sequence.
-
- Next we must insure that when the catch block is executed, all
- finalizations for the matching try block have been completed. If
- any of those finalizations throw an exception, we must call
- terminate according to the ARM (section r.15.6.1). What this
- means is that we need to dequeue and emit finalizations for each
- entry in the eh_queue until we get to an entry with a NULL
- finalization field. For any of the finalization entries, if it
- is not a call to terminate (), we must protect it by giving it
- another start label, end label, and exception handler label,
- setting its finalization tree to be a call to terminate (), and
- enqueue'ing this new eh_entry to be output at an outer level.
- Finally, after all that is done, we can get around to outputting
- the catch block which basically wraps all the "catch (...) {...}"
- statements in a big if/then/else construct that matches the
- correct block to call.
-
- ===================================================================== */
-
-/* ====================================================================== */
-
-/* sets up all the global eh stuff that needs to be initialized at the
+/* Sets up all the global eh stuff that needs to be initialized at the
start of compilation. */
void
init_exception_processing ()
{
- /* void vtype () */
- tree vtype = build_function_type (void_type_node, void_list_node);
-
+ tree tmp;
+
if (flag_honor_std)
push_namespace (std_identifier);
- terminate_node = build_cp_library_fn_ptr ("terminate", vtype);
+
+ /* void std::terminate (); */
+ tmp = build_function_type (void_type_node, void_list_node);
+ terminate_node = build_cp_library_fn_ptr ("terminate", tmp);
TREE_THIS_VOLATILE (terminate_node) = 1;
TREE_NOTHROW (terminate_node) = 1;
if (flag_honor_std)
pop_namespace ();
- set_exception_lang_code (EH_LANG_C_plus_plus);
- set_exception_version_code (1);
-
- /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
- be protected with __terminate. */
- protect_cleanup_actions_with_terminate = 1;
-}
-
-/* Retrieve a pointer to the cp_eh_info node for the current exception. */
-
-static tree
-call_eh_info ()
-{
- tree fn;
-
- fn = get_identifier ("__start_cp_handler");
- if (IDENTIFIER_GLOBAL_VALUE (fn))
- fn = IDENTIFIER_GLOBAL_VALUE (fn);
- else
- {
- tree eh_info_type;
- tree cleanup_fn_type;
- tree matcher_fn_type;
- tree cp_eh_info_type;
- tree exception_desc_type;
- tree fields[8];
-
- eh_info_type = make_aggr_type (RECORD_TYPE);
- exception_desc_type = make_aggr_type (RECORD_TYPE);
-
- /* void * (*) (__eh_info *, void *, exception_descriptor *); */
- matcher_fn_type = tree_cons
- (NULL_TREE, build_pointer_type (eh_info_type), tree_cons
- (NULL_TREE, ptr_type_node, tree_cons
- (NULL_TREE, build_pointer_type (exception_desc_type),
- void_list_node)));
- matcher_fn_type = build_function_type (ptr_type_node, matcher_fn_type);
- matcher_fn_type = build_pointer_type (matcher_fn_type);
-
- /* void (*) (void *); */
- cleanup_fn_type = tree_cons
- (NULL_TREE, ptr_type_node, void_list_node);
- cleanup_fn_type = build_function_type (void_type_node, cleanup_fn_type);
- cleanup_fn_type = build_pointer_type (cleanup_fn_type);
-
- /* eh-common.h
- struct __eh_info
- {
- __eh_matcher match_function;
- short language;
- short version;
- }; */
- fields[0] = build_decl (FIELD_DECL,
- get_identifier ("match_function"), ptr_type_node);
- fields[1] = build_decl (FIELD_DECL,
- get_identifier ("language"), short_integer_type_node);
- fields[2] = build_decl (FIELD_DECL,
- get_identifier ("version"), short_integer_type_node);
- /* N.B.: The fourth field LEN is expected to be
- the number of fields - 1, not the total number of fields. */
- finish_builtin_type (eh_info_type, "__eh_info", fields, 2, ptr_type_node);
-
- /* exception_support.h
- struct cp_eh_info
- {
- __eh_info eh_info;
- void *value;
- void *type;
- cleanup_fn cleanup;
- bool caught;
- cp_eh_info *next;
- long handlers;
- void *original_value;
- }; */
- cp_eh_info_type = make_aggr_type (RECORD_TYPE);
- fields[0] = build_decl (FIELD_DECL, get_identifier ("eh_info"),
- eh_info_type);
- fields[1] = build_decl (FIELD_DECL, get_identifier ("value"),
- ptr_type_node);
- fields[2] = build_decl (FIELD_DECL, get_identifier ("type"),
- ptr_type_node);
- fields[3] = build_decl (FIELD_DECL, get_identifier ("cleanup"),
- cleanup_fn_type);
- fields[4] = build_decl (FIELD_DECL, get_identifier ("caught"),
- boolean_type_node);
- fields[5] = build_decl (FIELD_DECL, get_identifier ("next"),
- build_pointer_type (cp_eh_info_type));
- fields[6] = build_decl (FIELD_DECL, get_identifier ("handlers"),
- long_integer_type_node);
- fields[7] = build_decl (FIELD_DECL, get_identifier ("original_value"),
- ptr_type_node);
- /* N.B.: The fourth field LEN is expected to be
- the number of fields - 1, not the total number of fields. */
- finish_builtin_type (cp_eh_info_type, "cp_eh_info", fields, 7, ptr_type_node);
-
- /* And now the function. */
- fn = push_library_fn (fn,
- build_function_type (build_pointer_type (cp_eh_info_type),
- void_list_node));
- }
- return build_function_call (fn, NULL_TREE);
-}
-
-/* Retrieve a pointer to the cp_eh_info node for the current exception
- and save it in the current binding level. */
-
-static void
-push_eh_info ()
-{
- tree decl, fn = call_eh_info ();
-
- /* Remember the pointer to the current exception info; it won't change
- during this catch block. */
- decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
- TREE_TYPE (fn));
- DECL_ARTIFICIAL (decl) = 1;
- DECL_INITIAL (decl) = fn;
- decl = pushdecl (decl);
- cp_finish_decl (decl, fn, NULL_TREE, 0);
-}
-
-/* Returns a reference to the cp_eh_info node for the current exception. */
-
-static tree
-get_eh_info ()
-{
- /* Look for the pointer pushed in push_eh_info. */
- tree t = lookup_name (get_identifier ("__exception_info"), 0);
- return build_indirect_ref (t, NULL_PTR);
-}
-
-/* Returns a reference to the current exception object. */
+ protect_cleanup_actions = build_call (terminate_node, NULL_TREE);
-static tree
-get_eh_value ()
-{
- return build_component_ref (get_eh_info (), get_identifier ("value"),
- NULL_TREE, 0);
-}
+ /* void __cxa_call_unexpected(void *); */
+ tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
+ tmp = build_function_type (void_type_node, tmp);
+ call_unexpected_node
+ = push_throw_library_fn (get_identifier ("__cxa_call_unexpected"), tmp);
-/* Returns a reference to the current exception type. */
+ eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
+ ? "__gxx_personality_sj0"
+ : "__gxx_personality_v0");
-#if 0
-static tree
-get_eh_type ()
-{
- return build_component_ref (get_eh_info (), get_identifier ("type"),
- NULL_TREE, 0);
+ lang_eh_runtime_type = build_eh_type_type;
}
-/* Returns a reference to whether or not the current exception
- has been caught. */
-
static tree
-get_eh_caught ()
-{
- return build_component_ref (get_eh_info (), get_identifier ("caught"),
- NULL_TREE, 0);
-}
-
-/* Returns a reference to whether or not the current exception
- has been caught. */
-
-static tree
-get_eh_handlers ()
-{
- return build_component_ref (get_eh_info (), get_identifier ("handlers"),
- NULL_TREE, 0);
-}
-#endif
-
-/* Build a type value for use at runtime for a type that is matched
- against by the exception handling system. */
-
-static tree
-build_eh_type_type (type)
+prepare_eh_type (type)
tree type;
{
+ if (type == NULL_TREE)
+ return type;
if (type == error_mark_node)
return error_mark_node;
@@ -337,14 +105,14 @@ build_eh_type_type (type)
/* Peel off cv qualifiers. */
type = TYPE_MAIN_VARIANT (type);
- return build1 (ADDR_EXPR, ptr_type_node, get_typeid_1 (type));
+ return type;
}
/* Build the address of a typeinfo decl for use in the runtime
- matching field of the new exception model */
+ matching field of the exception model. */
static tree
-build_eh_type_type_ref (type)
+build_eh_type_type (type)
tree type;
{
tree exp;
@@ -352,47 +120,43 @@ build_eh_type_type_ref (type)
if (type == NULL_TREE || type == error_mark_node)
return type;
- /* peel back references, so they match. */
- if (TREE_CODE (type) == REFERENCE_TYPE)
- type = TREE_TYPE (type);
-
- /* Peel off cv qualifiers. */
- type = TYPE_MAIN_VARIANT (type);
+ if (decl_is_java_type (type, 0))
+ exp = build_java_class_ref (TREE_TYPE (type));
+ else
+ exp = get_tinfo_decl (type);
- exp = get_tinfo_decl (type);
mark_used (exp);
exp = build1 (ADDR_EXPR, ptr_type_node, exp);
- return (exp);
+ return exp;
+}
+
+tree
+build_exc_ptr ()
+{
+ return build (EXC_PTR_EXPR, ptr_type_node);
}
-/* This routine is called to mark all the symbols representing runtime
- type functions in the exception table as having been referenced.
- This will make sure code is emitted for them. Called from finish_file. */
+/* Build up a call to __cxa_begin_catch, to tell the runtime that the
+ exception has been handled. */
-void
-mark_all_runtime_matches ()
+static tree
+do_begin_catch ()
{
- int x,num;
- void **ptr;
- tree exp;
-
- num = find_all_handler_type_matches (&ptr);
- if (num == 0 || ptr == NULL)
- return;
-
- for (x=0; x <num; x++)
+ tree fn;
+
+ fn = get_identifier ("__cxa_begin_catch");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
{
- exp = (tree) ptr[x];
- if (TREE_CODE (exp) == ADDR_EXPR)
- {
- exp = TREE_OPERAND (exp, 0);
- if (TREE_CODE (exp) == FUNCTION_DECL)
- TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (exp)) = 1;
- }
+ /* Declare void* __cxa_begin_catch (void *). */
+ tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
+ fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp));
}
-
- free (ptr);
+
+ return build_function_call (fn, tree_cons (NULL_TREE, build_exc_ptr (),
+ NULL_TREE));
}
/* Returns nonzero if cleaning up an exception of type TYPE (which can be
@@ -415,32 +179,29 @@ dtor_nothrow (type)
return TREE_NOTHROW (fn);
}
-/* Build up a call to __cp_pop_exception, to destroy the exception object
+/* Build up a call to __cxa_end_catch, to destroy the exception object
for the current catch block if no others are currently using it. */
static tree
-do_pop_exception (type)
+do_end_catch (type)
tree type;
{
tree fn, cleanup;
- fn = get_identifier ("__cp_pop_exception");
+
+ fn = get_identifier ("__cxa_end_catch");
if (IDENTIFIER_GLOBAL_VALUE (fn))
fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
- /* Declare void __cp_pop_exception (void *),
- as defined in exception.cc. */
- fn = push_void_library_fn
- (fn, tree_cons (NULL_TREE, ptr_type_node, void_list_node));
+ /* Declare void __cxa_end_catch (). */
+ fn = push_void_library_fn (fn, void_list_node);
/* This can throw if the destructor for the exception throws. */
TREE_NOTHROW (fn) = 0;
}
- /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
- cleanup = lookup_name (get_identifier ("__exception_info"), 0);
- cleanup = build_function_call (fn, tree_cons
- (NULL_TREE, cleanup, NULL_TREE));
+ cleanup = build_function_call (fn, NULL_TREE);
TREE_NOTHROW (cleanup) = dtor_nothrow (type);
+
return cleanup;
}
@@ -450,29 +211,20 @@ static void
push_eh_cleanup (type)
tree type;
{
- finish_decl_cleanup (NULL_TREE, do_pop_exception (type));
-}
-
-/* Build up a call to terminate on the function obstack, for use as an
- exception handler. */
-
-static tree
-build_terminate_handler ()
-{
- return build_function_call (terminate_node, NULL_TREE);
+ finish_decl_cleanup (NULL_TREE, do_end_catch (type));
}
/* Return nonzero value if DECL is a Java type suitable for catch or
throw. */
-static int
+static bool
decl_is_java_type (decl, err)
tree decl;
int err;
{
- int r = (TREE_CODE (decl) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
- && TYPE_FOR_JAVA (TREE_TYPE (decl)));
+ bool r = (TREE_CODE (decl) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
+ && TYPE_FOR_JAVA (TREE_TYPE (decl)));
if (err)
{
@@ -508,71 +260,74 @@ decl_is_java_type (decl, err)
return r;
}
+static void
+choose_personality_routine (is_java)
+ bool is_java;
+{
+ static enum {
+ chose_none,
+ chose_cpp,
+ chose_java,
+ gave_error
+ } state;
+
+ switch (state)
+ {
+ case chose_none:
+ /* We defaulted to C++ in init_exception_processing.
+ Reconfigure for Java if we changed our minds. */
+ if (is_java)
+ eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
+ ? "__gcj_personality_sj0"
+ : "__gcj_personality_v0");
+ state = (is_java ? chose_java : chose_cpp);
+ break;
+
+ case chose_cpp:
+ case chose_java:
+ if (state != (is_java ? chose_java : chose_cpp))
+ {
+ error ("mixing C++ and Java catches in a single translation unit");
+ state = gave_error;
+ }
+ break;
+
+ case gave_error:
+ break;
+ }
+}
+
/* Initialize the catch parameter DECL. */
static void
-initialize_handler_parm (decl)
+initialize_handler_parm (decl, exp)
tree decl;
+ tree exp;
{
- tree exp;
tree init;
tree init_type;
- int lang;
/* Make sure we mark the catch param as used, otherwise we'll get a
warning about an unused ((anonymous)). */
TREE_USED (decl) = 1;
- /* Figure out the type that the initializer is. */
+ /* Figure out the type that the initializer is. Pointers are returned
+ adjusted by value from __cxa_begin_catch. Others are returned by
+ reference. */
init_type = TREE_TYPE (decl);
- if (TREE_CODE (init_type) != REFERENCE_TYPE
- && TREE_CODE (init_type) != POINTER_TYPE)
+ if (TREE_CODE (init_type) != POINTER_TYPE
+ && TREE_CODE (init_type) != REFERENCE_TYPE)
init_type = build_reference_type (init_type);
- if (decl_is_java_type (init_type, 0))
- {
- tree fn
- = builtin_function ("_Jv_exception_info",
- build_function_type (ptr_type_node,
- tree_cons (NULL_TREE,
- void_type_node,
- NULL_TREE)),
- 0, NOT_BUILT_IN, NULL_PTR);
-
- exp = build (CALL_EXPR, ptr_type_node,
- build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)),
- fn),
- NULL_TREE, NULL_TREE);
- TREE_SIDE_EFFECTS (exp) = 1;
- lang = EH_LANG_Java;
-
- set_exception_lang_code (EH_LANG_Java);
- set_exception_version_code (1);
- }
- else
- {
- exp = get_eh_value ();
- lang = EH_LANG_C_plus_plus;
- }
-
- if (catch_language_init)
- {
- if (lang != catch_language)
- error ("mixing C++ and Java `catch'es in single translation unit");
- }
- else
- {
- catch_language_init = 1;
- catch_language = lang;
- }
+ choose_personality_routine (decl_is_java_type (init_type, 0));
/* Since pointers are passed by value, initialize a reference to
- pointer catch parm with the address of the value slot. */
+ pointer catch parm with the address of the temporary. */
if (TREE_CODE (init_type) == REFERENCE_TYPE
&& TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
exp = build_unary_op (ADDR_EXPR, exp, 1);
- exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
+ exp = ocp_convert (init_type, exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
init = convert_from_reference (exp);
@@ -584,8 +339,7 @@ initialize_handler_parm (decl)
See also expand_default_init. */
init = ocp_convert (TREE_TYPE (decl), init,
CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
- init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
- build_terminate_handler ());
+ init = build1 (MUST_NOT_THROW_EXPR, TREE_TYPE (init), init);
}
/* Let `cp_finish_decl' know that this initializer is ok. */
@@ -605,6 +359,9 @@ expand_start_catch_block (decl)
{
tree compound_stmt_1;
tree compound_stmt_2;
+ tree exp = NULL_TREE;
+ tree type;
+ bool is_java;
if (! doing_eh (1))
return NULL_TREE;
@@ -618,34 +375,54 @@ expand_start_catch_block (decl)
compound_stmt_1 = begin_compound_stmt (/*has_no_scope=*/0);
note_level_for_catch ();
- if (! decl || ! decl_is_java_type (TREE_TYPE (decl), 1))
+ if (decl)
+ type = prepare_eh_type (TREE_TYPE (decl));
+ else
+ type = NULL_TREE;
+ begin_catch_block (type);
+
+ is_java = false;
+ if (decl)
{
- /* The ordinary C++ case. */
- tree type;
+ tree init;
- if (decl)
- type = TREE_TYPE (decl);
+ if (decl_is_java_type (type, 1))
+ {
+ /* Java only passes object via pointer and doesn't require
+ adjusting. The java object is immediately before the
+ generic exception header. */
+ init = build_exc_ptr ();
+ init = build1 (NOP_EXPR, build_pointer_type (type), init);
+ init = build (MINUS_EXPR, TREE_TYPE (init), init,
+ TYPE_SIZE_UNIT (TREE_TYPE (init)));
+ init = build_indirect_ref (init, NULL_PTR);
+ is_java = true;
+ }
else
- type = NULL_TREE;
- begin_catch_block (build_eh_type_type_ref (type));
-
- push_eh_info ();
- push_eh_cleanup (type);
+ {
+ /* C++ requires that we call __cxa_begin_catch to get the
+ pointer to the actual object. */
+ init = do_begin_catch ();
+ }
+
+ exp = create_temporary_var (ptr_type_node);
+ DECL_REGISTER (exp) = 1;
+ cp_finish_decl (exp, init, NULL_TREE, LOOKUP_ONLYCONVERTING);
+ finish_expr_stmt (build_modify_expr (exp, INIT_EXPR, init));
}
else
- {
- /* The Java case. In this case, the match_info is a pointer to
- the Java class object. We assume that the class is a
- compiled class. */
- tree ref = build_java_class_ref (TREE_TYPE (TREE_TYPE (decl)));
- begin_catch_block (build1 (ADDR_EXPR, jclass_node, ref));
- }
+ finish_expr_stmt (do_begin_catch ());
+
+ /* C++ requires that we call __cxa_end_catch at the end of
+ processing the exception. */
+ if (! is_java)
+ push_eh_cleanup (type);
/* Create a binding level for the parm. */
compound_stmt_2 = begin_compound_stmt (/*has_no_scope=*/0);
if (decl)
- initialize_handler_parm (decl);
+ initialize_handler_parm (decl, exp);
return build_tree_list (compound_stmt_1, compound_stmt_2);
}
@@ -678,204 +455,151 @@ expand_end_catch_block (blocks)
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1);
}
-/* An exception spec is implemented more or less like:
-
- try {
- function body;
- } catch (...) {
- void *p[] = { typeid(raises) };
- __check_eh_spec (p, count);
- }
-
- __check_eh_spec in exception.cc handles all the details. */
-
tree
-expand_start_eh_spec ()
+begin_eh_spec_block ()
{
- return begin_try_block ();
+ tree r = build_stmt (EH_SPEC_BLOCK, NULL_TREE, NULL_TREE);
+ add_stmt (r);
+ return r;
}
void
-expand_end_eh_spec (raises, try_block)
- tree raises;
- tree try_block;
+finish_eh_spec_block (raw_raises, eh_spec_block)
+ tree raw_raises;
+ tree eh_spec_block;
{
- tree tmp, fn, decl, types = NULL_TREE;
- tree blocks;
- tree handler;
- int count = 0;
-
- finish_try_block (try_block);
- handler = begin_handler ();
- blocks = finish_handler_parms (NULL_TREE, handler);
-
- if (TREE_VALUE (raises) == NULL_TREE)
- {
- fn = get_identifier ("__check_null_eh_spec");
- if (IDENTIFIER_GLOBAL_VALUE (fn))
- fn = IDENTIFIER_GLOBAL_VALUE (fn);
- else
- {
- tmp = build_function_type (void_type_node, void_list_node);
- fn = push_throw_library_fn (fn, tmp);
- /* Since the spec doesn't allow any exceptions, this call will
- never throw. We use push_throw_library_fn because we do want
- TREE_THIS_VOLATILE to be set. */
- TREE_NOTHROW (fn) = 1;
- }
- tmp = NULL_TREE;
- }
- else
- {
- /* Build up an array of type_infos. */
- for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
- {
- types = tree_cons
- (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
- ++count;
- }
-
- types = build_nt (CONSTRUCTOR, NULL_TREE, types);
- TREE_HAS_CONSTRUCTOR (types) = 1;
-
- /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */
- tmp = build_cplus_array_type (const_ptr_type_node, NULL_TREE);
- decl = build_decl (VAR_DECL, NULL_TREE, tmp);
- DECL_ARTIFICIAL (decl) = 1;
- DECL_INITIAL (decl) = types;
- DECL_CONTEXT (decl) = current_function_decl;
- cp_finish_decl (decl, types, NULL_TREE, 0);
-
- decl = decay_conversion (decl);
-
- fn = get_identifier ("__check_eh_spec");
- if (IDENTIFIER_GLOBAL_VALUE (fn))
- fn = IDENTIFIER_GLOBAL_VALUE (fn);
- else
- {
- tmp = tree_cons
- (NULL_TREE, integer_type_node, tree_cons
- (NULL_TREE, TREE_TYPE (decl), void_list_node));
- tmp = build_function_type (void_type_node, tmp);
-
- fn = push_throw_library_fn (fn, tmp);
- }
+ tree raises;
- tmp = tree_cons (NULL_TREE, build_int_2 (count, 0),
- tree_cons (NULL_TREE, decl, NULL_TREE));
- }
+ RECHAIN_STMTS (eh_spec_block, EH_SPEC_STMTS (eh_spec_block));
- tmp = build_call (fn, tmp);
- finish_expr_stmt (tmp);
+ /* Strip cv quals, etc, from the specification types. */
+ for (raises = NULL_TREE;
+ raw_raises && TREE_VALUE (raw_raises);
+ raw_raises = TREE_CHAIN (raw_raises))
+ raises = tree_cons (NULL_TREE, prepare_eh_type (TREE_VALUE (raw_raises)),
+ raises);
- finish_handler (blocks, handler);
- finish_handler_sequence (try_block);
+ EH_SPEC_RAISES (eh_spec_block) = raises;
}
-/* This is called to expand all the toplevel exception handling
- finalization for a function. It should only be called once per
- function. */
+/* Return a pointer to a buffer for an exception object of type TYPE. */
-void
-expand_exception_blocks ()
+static tree
+do_allocate_exception (type)
+ tree type;
{
- do_pending_stack_adjust ();
+ tree fn;
- if (catch_clauses)
+ fn = get_identifier ("__cxa_allocate_exception");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
{
- rtx funcend = gen_label_rtx ();
- emit_jump (funcend);
-
- /* We cannot protect n regions this way if we must flow into the
- EH region through the top of the region, as we have to with
- the setjmp/longjmp approach. */
- if (USING_SJLJ_EXCEPTIONS == 0)
- expand_eh_region_start ();
-
- emit_insns (catch_clauses);
- catch_clauses = catch_clauses_last = NULL_RTX;
-
- if (USING_SJLJ_EXCEPTIONS == 0)
- expand_eh_region_end (build_terminate_handler ());
-
- emit_insns (catch_clauses);
- catch_clauses = catch_clauses_last = NULL_RTX;
- emit_label (funcend);
+ /* Declare void *__cxa_allocate_exception(size_t). */
+ tree tmp = tree_cons (NULL_TREE, c_size_type_node, void_list_node);
+ fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp));
}
+
+ return build_function_call (fn, tree_cons (NULL_TREE, size_in_bytes (type),
+ NULL_TREE));
}
-/* Return a pointer to a buffer for an exception object of type TYPE. */
+/* Call __cxa_free_exception from a cleanup. This is invoked when
+ a constructor for a thrown object throws. */
static tree
-alloc_eh_object (type)
- tree type;
+do_free_exception (ptr)
+ tree ptr;
{
- tree fn, exp;
+ tree fn;
- fn = get_identifier ("__eh_alloc");
+ fn = get_identifier ("__cxa_free_exception");
if (IDENTIFIER_GLOBAL_VALUE (fn))
fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
- /* Declare __eh_alloc (size_t), as defined in exception.cc. */
- tree tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
- fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp));
+ /* Declare void __cxa_free_exception (void *). */
+ fn = push_void_library_fn (fn, tree_cons (NULL_TREE, ptr_type_node,
+ void_list_node));
}
- exp = build_function_call (fn, tree_cons
- (NULL_TREE, size_in_bytes (type), NULL_TREE));
- exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
- return exp;
+ return build_function_call (fn, tree_cons (NULL_TREE, ptr, NULL_TREE));
}
-/* Expand a throw statement. This follows the following
- algorithm:
-
- 1. Allocate space to save the current PC onto the stack.
- 2. Generate and emit a label and save its address into the
- newly allocated stack space since we can't save the pc directly.
- 3. If this is the first call to throw in this function:
- generate a label for the throw block
- 4. jump to the throw block label. */
+/* Build a throw expression. */
-static tree
-expand_throw (exp)
+tree
+build_throw (exp)
tree exp;
{
tree fn;
+ if (exp == error_mark_node)
+ return exp;
+
+ if (processing_template_decl)
+ return build_min (THROW_EXPR, void_type_node, exp);
+
+ if (exp == null_node)
+ cp_warning ("throwing NULL, which has integral, not pointer type");
+
+ if (exp != NULL_TREE)
+ {
+ if (!is_admissible_throw_operand (exp))
+ return error_mark_node;
+ }
+
if (! doing_eh (1))
return error_mark_node;
- if (exp
- && decl_is_java_type (TREE_TYPE (exp), 1))
+ if (exp && decl_is_java_type (TREE_TYPE (exp), 1))
{
- /* A Java `throw' statement. */
- tree args = tree_cons (NULL_TREE, exp, NULL);
-
- fn = get_identifier (USING_SJLJ_EXCEPTIONS
- ? "_Jv_Sjlj_Throw"
- : "_Jv_Throw");
+ tree fn = get_identifier ("_Jv_Throw");
if (IDENTIFIER_GLOBAL_VALUE (fn))
fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
- /* Declare _Jv_Throw (void *), as defined in Java's
- exception.cc. */
+ /* Declare void _Jv_Throw (void *). */
tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
tmp = build_function_type (ptr_type_node, tmp);
fn = push_throw_library_fn (fn, tmp);
}
- exp = build_function_call (fn, args);
+ exp = build_function_call (fn, tree_cons (NULL_TREE, exp, NULL_TREE));
}
else if (exp)
{
tree throw_type;
- tree cleanup = NULL_TREE, e;
+ tree cleanup;
tree stmt_expr;
tree compound_stmt;
tree try_block;
+ tree object, ptr;
+ tree tmp;
+
+ fn = get_identifier ("__cxa_throw");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
+ {
+ /* The CLEANUP_TYPE is the internal type of a destructor. */
+ if (cleanup_type == NULL_TREE)
+ {
+ tmp = void_list_node;
+ tmp = tree_cons (NULL_TREE, ptr_type_node, tmp);
+ tmp = build_function_type (void_type_node, tmp);
+ cleanup_type = build_pointer_type (tmp);
+ }
+
+ /* Declare void __cxa_throw (void*, void*, void (*)(void*)). */
+ /* ??? Second argument is supposed to be "std::type_info*". */
+ tmp = void_list_node;
+ tmp = tree_cons (NULL_TREE, cleanup_type, tmp);
+ tmp = tree_cons (NULL_TREE, ptr_type_node, tmp);
+ tmp = tree_cons (NULL_TREE, ptr_type_node, tmp);
+ tmp = build_function_type (void_type_node, tmp);
+ fn = push_throw_library_fn (fn, tmp);
+ }
begin_init_stmts (&stmt_expr, &compound_stmt);
@@ -883,161 +607,103 @@ expand_throw (exp)
/* First, decay it. */
exp = decay_conversion (exp);
- /* The CLEANUP_TYPE is the internal type of a destructor. Under
- the old ABI, destructors are two-argument functions; under
- the new ABI they take only one argument. */
- if (cleanup_type == NULL_TREE)
+ /* OK, this is kind of wacky. The standard says that we call
+ terminate when the exception handling mechanism, after
+ completing evaluation of the expression to be thrown but
+ before the exception is caught (_except.throw_), calls a
+ user function that exits via an uncaught exception.
+
+ So we have to protect the actual initialization of the
+ exception object with terminate(), but evaluate the
+ expression first. Since there could be temps in the
+ expression, we need to handle that, too. We also expand
+ the call to __cxa_allocate_exception first (which doesn't
+ matter, since it can't throw). */
+
+ my_friendly_assert (stmts_are_full_exprs_p () == 1, 19990926);
+
+ /* Store the throw expression into a temp. This can be less
+ efficient than storing it into the allocated space directly, but
+ if we allocated the space first we would have to deal with
+ cleaning it up if evaluating this expression throws. */
+ if (TREE_SIDE_EFFECTS (exp))
{
- tree arg_types;
-
- arg_types = void_list_node;
- arg_types = tree_cons (NULL_TREE, ptr_type_node, arg_types);
- cleanup_type = (build_pointer_type
- (build_function_type (void_type_node, arg_types)));
+ tmp = create_temporary_var (TREE_TYPE (exp));
+ DECL_INITIAL (tmp) = exp;
+ cp_finish_decl (tmp, exp, NULL_TREE, LOOKUP_ONLYCONVERTING);
+ exp = tmp;
}
- if (TYPE_PTR_P (TREE_TYPE (exp)))
- throw_type = build_eh_type_type (TREE_TYPE (exp));
- else
- {
- tree object, ptr;
-
- /* OK, this is kind of wacky. The standard says that we call
- terminate when the exception handling mechanism, after
- completing evaluation of the expression to be thrown but
- before the exception is caught (_except.throw_), calls a
- user function that exits via an uncaught exception.
-
- So we have to protect the actual initialization of the
- exception object with terminate(), but evaluate the
- expression first. Since there could be temps in the
- expression, we need to handle that, too. We also expand
- the call to __eh_alloc first (which doesn't matter, since
- it can't throw). */
-
- my_friendly_assert (stmts_are_full_exprs_p () == 1, 19990926);
-
- /* Store the throw expression into a temp. This can be less
- efficient than storing it into the allocated space directly, but
- if we allocated the space first we would have to deal with
- cleaning it up if evaluating this expression throws. */
- if (TREE_SIDE_EFFECTS (exp))
- {
- tree temp = create_temporary_var (TREE_TYPE (exp));
- DECL_INITIAL (temp) = exp;
- cp_finish_decl (temp, exp, NULL_TREE, LOOKUP_ONLYCONVERTING);
- exp = temp;
- }
+ /* Allocate the space for the exception. */
+ ptr = create_temporary_var (ptr_type_node);
+ DECL_REGISTER (ptr) = 1;
+ cp_finish_decl (ptr, NULL_TREE, NULL_TREE, LOOKUP_ONLYCONVERTING);
+ tmp = do_allocate_exception (TREE_TYPE (exp));
+ tmp = build_modify_expr (ptr, INIT_EXPR, tmp);
+ finish_expr_stmt (tmp);
- /* Allocate the space for the exception. */
- ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
- finish_expr_stmt (ptr);
+ object = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (exp)), ptr);
+ object = build_indirect_ref (object, NULL_PTR);
- try_block = begin_try_block ();
- object = build_indirect_ref (ptr, NULL_PTR);
- exp = build_modify_expr (object, INIT_EXPR, exp);
+ try_block = begin_try_block ();
- if (exp == error_mark_node)
- error (" in thrown expression");
+ exp = build_modify_expr (object, INIT_EXPR, exp);
+ if (exp == error_mark_node)
+ error (" in thrown expression");
- finish_expr_stmt (exp);
- finish_cleanup_try_block (try_block);
- finish_cleanup (build_terminate_handler (), try_block);
+ finish_expr_stmt (exp);
+ finish_cleanup_try_block (try_block);
+ finish_cleanup (do_free_exception (ptr), try_block);
- throw_type = build_eh_type_type (TREE_TYPE (object));
-
- if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
- {
- cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
- complete_dtor_identifier,
- 0);
- cleanup = TREE_VALUE (cleanup);
- mark_used (cleanup);
- mark_addressable (cleanup);
- /* Pretend it's a normal function. */
- cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
- }
+ throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object)));
- exp = ptr;
+ if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
+ {
+ cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
+ complete_dtor_identifier, 0);
+ cleanup = TREE_VALUE (cleanup);
+ mark_used (cleanup);
+ mark_addressable (cleanup);
+ /* Pretend it's a normal function. */
+ cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
}
-
- /* Cast EXP to `void *' so that it will match the prototype for
- __cp_push_exception. */
- exp = convert (ptr_type_node, exp);
-
- if (cleanup == NULL_TREE)
+ else
{
cleanup = build_int_2 (0, 0);
TREE_TYPE (cleanup) = cleanup_type;
}
- fn = cp_push_exception_identifier;
- if (IDENTIFIER_GLOBAL_VALUE (fn))
- fn = IDENTIFIER_GLOBAL_VALUE (fn);
- else
- {
- /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
- as defined in exception.cc. */
- tree tmp;
- tmp = tree_cons
- (NULL_TREE, ptr_type_node, tree_cons
- (NULL_TREE, ptr_type_node, tree_cons
- (NULL_TREE, cleanup_type, void_list_node)));
- fn = push_void_library_fn (fn, tmp);
- }
+ tmp = tree_cons (NULL_TREE, cleanup, NULL_TREE);
+ tmp = tree_cons (NULL_TREE, throw_type, tmp);
+ tmp = tree_cons (NULL_TREE, ptr, tmp);
+ tmp = build_function_call (fn, tmp);
+
+ /* ??? Indicate that this function call throws throw_type. */
- e = tree_cons (NULL_TREE, exp, tree_cons
- (NULL_TREE, throw_type, tree_cons
- (NULL_TREE, cleanup, NULL_TREE)));
- finish_expr_stmt (build_function_call (fn, e));
+ finish_expr_stmt (tmp);
exp = finish_init_stmts (stmt_expr, compound_stmt);
}
else
{
- /* rethrow current exception; note that it's no longer caught. */
+ /* Rethrow current exception. */
- tree fn = get_identifier ("__uncatch_exception");
+ tree fn = get_identifier ("__cxa_rethrow");
if (IDENTIFIER_GLOBAL_VALUE (fn))
fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
- /* Declare void __uncatch_exception (void)
- as defined in exception.cc. */
- fn = push_void_library_fn (fn, void_list_node);
+ {
+ /* Declare void __cxa_rethrow (void). */
+ fn = push_throw_library_fn
+ (fn, build_function_type (void_type_node, void_list_node));
+ }
exp = build_function_call (fn, NULL_TREE);
}
- return exp;
-}
+ exp = build1 (THROW_EXPR, void_type_node, exp);
-/* Build a throw expression. */
-
-tree
-build_throw (e)
- tree e;
-{
- if (e == error_mark_node)
- return e;
-
- if (processing_template_decl)
- return build_min (THROW_EXPR, void_type_node, e);
-
- if (e == null_node)
- cp_warning ("throwing NULL, which has integral, not pointer type");
-
- if (e != NULL_TREE)
- {
- if (!is_admissible_throw_operand (e))
- return error_mark_node;
- }
-
- e = expand_throw (e);
- e = build1 (THROW_EXPR, void_type_node, e);
- TREE_SIDE_EFFECTS (e) = 1;
- TREE_USED (e) = 1;
-
- return e;
+ return exp;
}
/* Make sure TYPE is complete, pointer to complete, reference to
diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c
index fc22460..9a9eb86 100644
--- a/gcc/cp/expr.c
+++ b/gcc/cp/expr.c
@@ -88,6 +88,7 @@ cplus_expand_expr (exp, target, tmode, modifier)
tree type = TREE_TYPE (exp);
register enum machine_mode mode = TYPE_MODE (type);
register enum tree_code code = TREE_CODE (exp);
+ rtx ret;
/* No sense saving up arithmetic to be done
if it's all in the wrong mode to form part of an address.
@@ -103,16 +104,19 @@ cplus_expand_expr (exp, target, tmode, modifier)
target, tmode, modifier);
case OFFSET_REF:
- {
- return expand_expr (default_conversion (resolve_offset_ref (exp)),
- target, tmode, EXPAND_NORMAL);
- }
+ return expand_expr (default_conversion (resolve_offset_ref (exp)),
+ target, tmode, EXPAND_NORMAL);
case THROW_EXPR:
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
- expand_internal_throw ();
return NULL;
+ case MUST_NOT_THROW_EXPR:
+ expand_eh_region_start ();
+ ret = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
+ expand_eh_region_end_must_not_throw (build_call (terminate_node, 0));
+ return ret;
+
case EMPTY_CLASS_EXPR:
/* We don't need to generate any code for an empty class. */
return const0_rtx;
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index a070002..6990e2c 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -51,6 +51,7 @@ static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *));
static void deferred_type_access_control PARAMS ((void));
static void emit_associated_thunks PARAMS ((tree));
static void genrtl_try_block PARAMS ((tree));
+static void genrtl_eh_spec_block PARAMS ((tree));
static void genrtl_handler PARAMS ((tree));
static void genrtl_catch_block PARAMS ((tree));
static void genrtl_ctor_stmt PARAMS ((tree));
@@ -575,14 +576,14 @@ genrtl_try_block (t)
{
expand_eh_region_start ();
expand_stmt (TRY_STMTS (t));
- expand_eh_region_end (protect_with_terminate (TRY_HANDLERS (t)));
+ expand_eh_region_end_cleanup (TRY_HANDLERS (t));
}
else
{
if (!FN_TRY_BLOCK_P (t))
emit_line_note (input_filename, lineno);
- expand_start_try_stmts ();
+ expand_eh_region_start ();
expand_stmt (TRY_STMTS (t));
if (FN_TRY_BLOCK_P (t))
@@ -603,6 +604,21 @@ genrtl_try_block (t)
}
}
+/* Generate the RTL for T, which is an EH_SPEC_BLOCK. */
+
+static void
+genrtl_eh_spec_block (t)
+ tree t;
+{
+ expand_eh_region_start ();
+ expand_stmt (EH_SPEC_STMTS (t));
+ expand_eh_region_end_allowed (EH_SPEC_RAISES (t),
+ build_call (call_unexpected_node,
+ tree_cons (NULL_TREE,
+ build_exc_ptr (),
+ NULL_TREE)));
+}
+
/* Begin a try-block. Returns a newly-created TRY_BLOCK if
appropriate. */
@@ -706,13 +722,7 @@ genrtl_handler (t)
genrtl_do_pushlevel ();
expand_stmt (HANDLER_BODY (t));
if (!processing_template_decl)
- {
- /* Fall to outside the try statement when done executing
- handler and we fall off end of handler. This is jump
- Lresume in the documentation. */
- expand_goto (top_label_entry (&caught_return_label_stack));
- end_catch_handler ();
- }
+ expand_end_catch ();
}
/* Begin a handler. Returns a HANDLER if appropriate. */
@@ -757,13 +767,13 @@ finish_handler_parms (decl, handler)
return blocks;
}
-/* Generate the RTL for a CATCH_BLOCK. */
+/* Generate the RTL for a START_CATCH_STMT. */
static void
genrtl_catch_block (type)
tree type;
{
- start_catch_handler (type);
+ expand_start_catch (type);
}
/* Note the beginning of a handler for TYPE. This function is called
@@ -2209,6 +2219,10 @@ cp_expand_stmt (t)
genrtl_try_block (t);
break;
+ case EH_SPEC_BLOCK:
+ genrtl_eh_spec_block (t);
+ break;
+
case HANDLER:
genrtl_handler (t);
break;
@@ -2615,9 +2629,6 @@ genrtl_finish_function (fn)
&& ! DECL_NAME (DECL_RESULT (current_function_decl)))
no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
- if (flag_exceptions)
- expand_exception_blocks ();
-
/* If this function is supposed to return a value, ensure that
we do not fall into the cleanups by mistake. The end of our
function will look like this:
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 3023e8f..5f67840 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1037,6 +1037,7 @@ cp_statement_code_p (code)
case RETURN_INIT:
case TRY_BLOCK:
case HANDLER:
+ case EH_SPEC_BLOCK:
return 1;
default: