summaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2002-02-06 05:05:49 +0000
committerobrien <obrien@FreeBSD.org>2002-02-06 05:05:49 +0000
commit6e12cd4bd27aa0e4792692204ecf892dff5d1c8c (patch)
tree62647f89ca45269935dcbc3fcbd810f0276f2679 /contrib
parent1b2d18310566cfa42f3acd476706af1981a6686d (diff)
downloadFreeBSD-src-6e12cd4bd27aa0e4792692204ecf892dff5d1c8c.zip
FreeBSD-src-6e12cd4bd27aa0e4792692204ecf892dff5d1c8c.tar.gz
Use the stock GCC 3.1-snap version of this.
Diffstat (limited to 'contrib')
-rw-r--r--contrib/gcc/cp/except.c1566
1 files changed, 649 insertions, 917 deletions
diff --git a/contrib/gcc/cp/except.c b/contrib/gcc/cp/except.c
index f2896c7..e320dea 100644
--- a/contrib/gcc/cp/except.c
+++ b/contrib/gcc/cp/except.c
@@ -1,5 +1,6 @@
/* Handle exceptional things in C++.
- Copyright (C) 1989, 92-97, 1998, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001 Free Software Foundation, Inc.
Contributed by Michael Tiemann <tiemann@cygnus.com>
Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
initial re-implementation courtesy Tad Hunt.
@@ -28,382 +29,83 @@ Boston, MA 02111-1307, USA. */
#include "system.h"
#include "tree.h"
#include "rtl.h"
+#include "expr.h"
+#include "libfuncs.h"
#include "cp-tree.h"
#include "flags.h"
#include "obstack.h"
-#include "expr.h"
#include "output.h"
#include "except.h"
-#include "function.h"
-#include "defaults.h"
#include "toplev.h"
-#include "eh-common.h"
-
-rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
-
-/* Holds the fndecl for __builtin_return_address. */
-tree builtin_return_address_fndecl;
-
-/* A couple of backend routines from m88k.c */
-
-static void push_eh_cleanup PROTO((void));
-static tree build_eh_type_type PROTO((tree));
-static tree build_eh_type PROTO((tree));
-static void expand_end_eh_spec PROTO((tree));
-static tree call_eh_info PROTO((void));
-static void push_eh_info PROTO((void));
-static tree get_eh_info PROTO((void));
-static tree get_eh_value PROTO((void));
-#if 0
-static tree get_eh_type PROTO((void));
-static tree get_eh_caught PROTO((void));
-static tree get_eh_handlers PROTO((void));
-#endif
-static tree do_pop_exception PROTO((void));
-static void process_start_catch_block PROTO((tree, tree));
-static tree build_eh_type_type_ref PROTO((tree));
-static tree build_terminate_handler PROTO((void));
-static tree alloc_eh_object PROTO((tree));
-
-#if 0
-/* This is the startup, and finish stuff per exception table. */
-
-/* XXX - Tad: exception handling section */
-#ifndef EXCEPT_SECTION_ASM_OP
-#define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
-#endif
-
-#ifdef EXCEPT_SECTION_ASM_OP
-
- /* on machines which support it, the exception table lives in another section,
- but it needs a label so we can reference it... This sets up that
- label! */
-asm (EXCEPT_SECTION_ASM_OP);
-exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
-asm (TEXT_SECTION_ASM_OP);
-
-#endif /* EXCEPT_SECTION_ASM_OP */
-
-#ifdef EXCEPT_SECTION_ASM_OP
-
- /* we need to know where the end of the exception table is... so this
- is how we do it! */
-asm (EXCEPT_SECTION_ASM_OP);
-exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
-asm (TEXT_SECTION_ASM_OP);
-
-#endif /* EXCEPT_SECTION_ASM_OP */
-
-#endif
+static void push_eh_cleanup PARAMS ((tree));
+static tree prepare_eh_type PARAMS ((tree));
+static tree build_eh_type_type PARAMS ((tree));
+static tree do_begin_catch PARAMS ((void));
+static int dtor_nothrow 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 initialize_handler_parm PARAMS ((tree, tree));
+static tree do_allocate_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 tree cp_protect_cleanup_actions PARAMS ((void));
#include "decl.h"
-#include "insn-flags.h"
#include "obstack.h"
-/* ======================================================================
- 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.
-
- ===================================================================== */
-
-/* local globals for function calls
- ====================================================================== */
-
-/* Used to cache "terminate" and "__throw_type_match*". */
-static tree Terminate, CatchMatch;
-
-/* Used to cache __find_first_exception_table_match for throw. */
-static tree FirstExceptionMatch;
-
-/* Used to cache a call to __unwind_function. */
-static tree Unwind;
-
-/* ====================================================================== */
-
-
-/* ========================================================================= */
-
-
-
-/* local globals - these local globals are for storing data necessary for
- generating the exception table and code in the correct order.
-
- ========================================================================= */
-
-extern rtx catch_clauses;
-extern tree const_ptr_type_node;
-
-/* ========================================================================= */
-
-/* sets up all the global eh stuff that needs to be initialized at the
- start of compilation.
-
- This includes:
- - Setting up all the function call trees. */
+/* 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);
-
- if (flag_honor_std)
- push_namespace (get_identifier ("std"));
- Terminate = auto_function (get_identifier ("terminate"),
- vtype, NOT_BUILT_IN);
- TREE_THIS_VOLATILE (Terminate) = 1;
- if (flag_honor_std)
- pop_namespace ();
-
- push_lang_context (lang_name_c);
-
- set_exception_lang_code (EH_LANG_C_plus_plus);
- set_exception_version_code (1);
-
- CatchMatch
- = builtin_function (flag_rtti
- ? "__throw_type_match_rtti"
- : "__throw_type_match",
- build_function_type (ptr_type_node,
- tree_cons (NULL_TREE, const_ptr_type_node,
- tree_cons (NULL_TREE, const_ptr_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- void_list_node)))),
- NOT_BUILT_IN, NULL_PTR);
- FirstExceptionMatch
- = builtin_function ("__find_first_exception_table_match",
- build_function_type (ptr_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- void_list_node)),
- NOT_BUILT_IN, NULL_PTR);
- Unwind
- = builtin_function ("__unwind_function",
- build_function_type (void_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- void_list_node)),
- NOT_BUILT_IN, NULL_PTR);
-
- pop_lang_context ();
-
- /* 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 t1, t, fields[7];
-
- /* Declare cp_eh_info * __start_cp_handler (void),
- as defined in exception.cc. */
- push_obstacks_nochange ();
- end_temporary_allocation ();
-
- /* struct cp_eh_info. This must match exception.cc. Note that this
- type is not pushed anywhere. */
- t1= make_lang_type (RECORD_TYPE);
- fields[0] = build_lang_field_decl (FIELD_DECL,
- get_identifier ("handler_label"), ptr_type_node);
- fields[1] = build_lang_field_decl (FIELD_DECL,
- get_identifier ("dynamic_handler_chain"), ptr_type_node);
- fields[2] = build_lang_field_decl (FIELD_DECL,
- get_identifier ("info"), ptr_type_node);
- fields[3] = build_lang_field_decl (FIELD_DECL,
- get_identifier ("table_index"), 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 (t1, "eh_context", fields, 3, ptr_type_node);
- t1 = build_pointer_type (t1);
-
- t1= make_lang_type (RECORD_TYPE);
- fields[0] = build_lang_field_decl (FIELD_DECL,
- get_identifier ("match_function"), ptr_type_node);
- fields[1] = build_lang_field_decl (FIELD_DECL,
- get_identifier ("language"), short_integer_type_node);
- fields[2] = build_lang_field_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 (t1, "__eh_info", fields, 2, ptr_type_node);
- t = make_lang_type (RECORD_TYPE);
- fields[0] = build_lang_field_decl (FIELD_DECL,
- get_identifier ("eh_info"), t1);
- fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"),
- ptr_type_node);
- fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
- ptr_type_node);
- fields[3] = build_lang_field_decl
- (FIELD_DECL, get_identifier ("cleanup"),
- build_pointer_type (build_function_type
- (ptr_type_node, tree_cons
- (NULL_TREE, ptr_type_node, void_list_node))));
- fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"),
- boolean_type_node);
- fields[5] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"),
- build_pointer_type (t));
- fields[6] = build_lang_field_decl
- (FIELD_DECL, get_identifier ("handlers"), long_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 (t, "cp_eh_info", fields, 6, ptr_type_node);
- t = build_pointer_type (t);
-
- /* And now the function. */
- fn = build_lang_decl (FUNCTION_DECL, fn,
- build_function_type (t, void_list_node));
- DECL_EXTERNAL (fn) = 1;
- TREE_PUBLIC (fn) = 1;
- DECL_ARTIFICIAL (fn) = 1;
- pushdecl_top_level (fn);
- make_function_rtl (fn);
- pop_obstacks ();
- }
- mark_used (fn);
- 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, 0);
+ tree tmp;
+
+ /* void std::terminate (); */
+ push_namespace (std_identifier);
+ 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;
+ pop_namespace ();
+
+ /* 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);
+
+ eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
+ ? "__gxx_personality_sj0"
+ : "__gxx_personality_v0");
+
+ lang_eh_runtime_type = build_eh_type_type;
+ lang_protect_cleanup_actions = &cp_protect_cleanup_actions;
}
-/* Returns a reference to the cp_eh_info node for the current exception. */
+/* Returns an expression to be executed if an unhandled exception is
+ propagated out of a cleanup region. */
static tree
-get_eh_info ()
+cp_protect_cleanup_actions ()
{
- /* 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);
-}
+ /* [except.terminate]
-/* Returns a reference to the current exception object. */
+ When the destruction of an object during stack unwinding exits
+ using an exception ... void terminate(); is called. */
+ return build_call (terminate_node, NULL_TREE);
+}
static tree
-get_eh_value ()
-{
- return build_component_ref (get_eh_info (), get_identifier ("value"),
- NULL_TREE, 0);
-}
-
-/* Returns a reference to the current exception type. */
-
-#if 0
-static tree
-get_eh_type ()
-{
- return build_component_ref (get_eh_info (), get_identifier ("type"),
- NULL_TREE, 0);
-}
-
-/* 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;
{
- const char *typestring;
- tree exp;
-
+ if (type == NULL_TREE)
+ return type;
if (type == error_mark_node)
return error_mark_node;
@@ -414,295 +116,338 @@ build_eh_type_type (type)
/* Peel off cv qualifiers. */
type = TYPE_MAIN_VARIANT (type);
- if (flag_rtti)
- return build1 (ADDR_EXPR, ptr_type_node, get_typeid_1 (type));
-
- typestring = build_overload_name (type, 1, 1);
- exp = combine_strings (build_string (strlen (typestring)+1, typestring));
- return build1 (ADDR_EXPR, ptr_type_node, exp);
+ return type;
}
-/* Build the address of a runtime type for use in the runtime matching
- field of the new exception model */
+/* Build the address of a typeinfo decl for use in the runtime
+ matching field of the exception model. */
static tree
-build_eh_type_type_ref (type)
+build_eh_type_type (type)
tree type;
{
- const char *typestring;
tree exp;
- if (type == error_mark_node)
- return error_mark_node;
+ 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);
- push_obstacks_nochange ();
- end_temporary_allocation ();
+ mark_used (exp);
+ exp = build1 (ADDR_EXPR, ptr_type_node, exp);
- if (flag_rtti)
- {
- exp = get_tinfo_fn (type);
- TREE_USED (exp) = 1;
- mark_inline_for_output (exp);
- exp = build1 (ADDR_EXPR, ptr_type_node, exp);
- }
- else
- {
- typestring = build_overload_name (type, 1, 1);
- exp = combine_strings (build_string (strlen (typestring)+1, typestring));
- exp = build1 (ADDR_EXPR, ptr_type_node, exp);
- }
- pop_obstacks ();
- return (exp);
+ return exp;
}
+tree
+build_exc_ptr ()
+{
+ return build (EXC_PTR_EXPR, ptr_type_node);
+}
-/* Build a type value for use at runtime for a exp that is thrown or
- matched against by the exception handling system. */
+/* Build up a call to __cxa_begin_catch, to tell the runtime that the
+ exception has been handled. */
static tree
-build_eh_type (exp)
- tree exp;
+do_begin_catch ()
{
- if (flag_rtti)
+ tree fn;
+
+ fn = get_identifier ("__cxa_begin_catch");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
{
- exp = build_typeid (exp);
- return build1 (ADDR_EXPR, ptr_type_node, exp);
+ /* 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));
}
- return build_eh_type_type (TREE_TYPE (exp));
+
+ return build_function_call (fn, tree_cons (NULL_TREE, build_exc_ptr (),
+ NULL_TREE));
}
-/* This routine is called to mark all the symbols representing runtime
- type functions in the exception table as haveing been referenced.
- This will make sure code is emitted for them. Called from finish_file. */
-void
-mark_all_runtime_matches ()
+/* Returns nonzero if cleaning up an exception of type TYPE (which can be
+ NULL_TREE for a ... handler) will not throw an exception. */
+
+static int
+dtor_nothrow (type)
+ tree type;
{
- 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++)
- {
- 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;
- }
- }
-
- free (ptr);
+ tree fn;
+
+ if (type == NULL_TREE)
+ return 0;
+
+ if (! TYPE_HAS_DESTRUCTOR (type))
+ return 1;
+
+ fn = lookup_member (type, dtor_identifier, 0, 0);
+ fn = TREE_VALUE (fn);
+ return TREE_NOTHROW (fn);
}
-/* Build up a call to __cp_pop_exception, to destroy the exception object
- for the current catch block. HANDLER is either true or false, telling
- the library whether or not it is being called from an exception handler;
- if it is, it avoids destroying the object on rethrow. */
+/* 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 ()
+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. */
- push_obstacks_nochange ();
- end_temporary_allocation ();
- fn = build_lang_decl
- (FUNCTION_DECL, fn,
- build_function_type (void_type_node, tree_cons
- (NULL_TREE, ptr_type_node, void_list_node)));
- DECL_EXTERNAL (fn) = 1;
- TREE_PUBLIC (fn) = 1;
- DECL_ARTIFICIAL (fn) = 1;
- pushdecl_top_level (fn);
- make_function_rtl (fn);
- pop_obstacks ();
+ /* 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;
}
- mark_used (fn);
- /* 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, expr_tree_cons
- (NULL_TREE, cleanup, NULL_TREE));
+ cleanup = build_function_call (fn, NULL_TREE);
+ TREE_NOTHROW (cleanup) = dtor_nothrow (type);
+
return cleanup;
}
/* This routine creates the cleanup for the current exception. */
static void
-push_eh_cleanup ()
+push_eh_cleanup (type)
+ tree type;
{
- int yes;
-
- yes = suspend_momentary ();
- /* All cleanups must last longer than normal. */
- expand_decl_cleanup (NULL_TREE, do_pop_exception ());
- resume_momentary (yes);
+ finish_decl_cleanup (NULL_TREE, do_end_catch (type));
}
-/* Build up a call to terminate on the function obstack, for use as an
- exception handler. */
+/* Return nonzero value if DECL is a Java type suitable for catch or
+ throw. */
-static tree
-build_terminate_handler ()
+static bool
+decl_is_java_type (decl, err)
+ tree decl;
+ int err;
{
- int yes = suspend_momentary ();
- tree term = build_function_call (Terminate, NULL_TREE);
- resume_momentary (yes);
- return term;
-}
+ bool r = (TREE_CODE (decl) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
+ && TYPE_FOR_JAVA (TREE_TYPE (decl)));
+
+ if (err)
+ {
+ if (TREE_CODE (decl) == REFERENCE_TYPE
+ && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
+ && TYPE_FOR_JAVA (TREE_TYPE (decl)))
+ {
+ /* Can't throw a reference. */
+ error ("type `%T' is disallowed in Java `throw' or `catch'",
+ decl);
+ }
+
+ if (r)
+ {
+ tree jthrow_node
+ = IDENTIFIER_GLOBAL_VALUE (get_identifier ("jthrowable"));
+
+ if (jthrow_node == NULL_TREE)
+ fatal_error
+ ("call to Java `catch' or `throw' with `jthrowable' undefined");
-/* Call this to start a catch block. Typename is the typename, and identifier
- is the variable to place the object in or NULL if the variable doesn't
- matter. If typename is NULL, that means its a "catch (...)" or catch
- everything. In that case we don't need to do any type checking.
- (ie: it ends up as the "else" clause rather than an "else if" clause) */
+ jthrow_node = TREE_TYPE (TREE_TYPE (jthrow_node));
+ if (! DERIVED_FROM_P (jthrow_node, TREE_TYPE (decl)))
+ {
+ /* Thrown object must be a Throwable. */
+ error ("type `%T' is not derived from `java::lang::Throwable'",
+ TREE_TYPE (decl));
+ }
+ }
+ }
+
+ return r;
+}
+
+/* Select the personality routine to be used for exception handling,
+ or issue an error if we need two different ones in the same
+ translation unit.
+ ??? At present eh_personality_libfunc is set to
+ __gxx_personality_(sj|v)0 in init_exception_processing - should it
+ be done here instead? */
void
-expand_start_catch_block (declspecs, declarator)
- tree declspecs, declarator;
+choose_personality_routine (lang)
+ enum languages lang;
{
- tree decl;
-
- if (processing_template_decl)
+ static enum {
+ chose_none,
+ chose_cpp,
+ chose_java,
+ gave_error
+ } state;
+
+ switch (state)
{
- if (declspecs)
- {
- decl = grokdeclarator (declarator, declspecs, CATCHPARM,
- 1, NULL_TREE);
- pushdecl (decl);
- decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
- copy_to_permanent (declspecs),
- NULL_TREE);
- add_tree (decl);
- }
+ case gave_error:
return;
+
+ case chose_cpp:
+ if (lang != lang_cplusplus)
+ goto give_error;
+ return;
+
+ case chose_java:
+ if (lang != lang_java)
+ goto give_error;
+ return;
+
+ case chose_none:
+ ; /* proceed to language selection */
}
- if (! doing_eh (1))
- return;
+ switch (lang)
+ {
+ case lang_cplusplus:
+ state = chose_cpp;
+ break;
+
+ case lang_java:
+ state = chose_java;
+ eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
+ ? "__gcj_personality_sj0"
+ : "__gcj_personality_v0");
+ break;
+
+ default:
+ abort ();
+ }
+ return;
- process_start_catch_block (declspecs, declarator);
+ give_error:
+ error ("mixing C++ and Java catches in a single translation unit");
+ state = gave_error;
}
-
-/* This function performs the expand_start_catch_block functionality for
- exceptions implemented in the new style. __throw determines whether
- a handler needs to be called or not, so the handler itself has to do
- nothing additional. */
+/* Initialize the catch parameter DECL. */
static void
-process_start_catch_block (declspecs, declarator)
- tree declspecs, declarator;
+initialize_handler_parm (decl, exp)
+ tree decl;
+ tree exp;
{
- tree decl = NULL_TREE;
tree init;
+ tree init_type;
- /* Create a binding level for the eh_info and the exception object
- cleanup. */
- pushlevel (0);
- expand_start_bindings (0);
+ /* 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. Pointers are returned
+ adjusted by value from __cxa_begin_catch. Others are returned by
+ reference. */
+ init_type = TREE_TYPE (decl);
+ if (! TYPE_PTR_P (init_type)
+ && TREE_CODE (init_type) != REFERENCE_TYPE)
+ init_type = build_reference_type (init_type);
- if (declspecs)
- {
- decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
-
- if (decl == NULL_TREE)
- error ("invalid catch parameter");
- }
+ choose_personality_routine (decl_is_java_type (init_type, 0)
+ ? lang_java : lang_cplusplus);
- if (decl)
- start_catch_handler (build_eh_type_type_ref (TREE_TYPE (decl)));
- else
- start_catch_handler (CATCH_ALL_TYPE);
+ /* Since pointers are passed by value, initialize a reference to
+ pointer catch parm with the address of the temporary. */
+ if (TREE_CODE (init_type) == REFERENCE_TYPE
+ && TYPE_PTR_P (TREE_TYPE (init_type)))
+ exp = build_unary_op (ADDR_EXPR, exp, 1);
- emit_line_note (input_filename, lineno);
+ exp = ocp_convert (init_type, exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
- push_eh_info ();
+ init = convert_from_reference (exp);
- if (decl)
+ /* If the constructor for the catch parm exits via an exception, we
+ must call terminate. See eh23.C. */
+ if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
{
- tree exp;
- tree init_type;
+ /* Generate the copy constructor call directly so we can wrap it.
+ See also expand_default_init. */
+ init = ocp_convert (TREE_TYPE (decl), init,
+ CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
+ init = build1 (MUST_NOT_THROW_EXPR, TREE_TYPE (init), init);
+ }
- /* Make sure we mark the catch param as used, otherwise we'll get
- a warning about an unused ((anonymous)). */
- TREE_USED (decl) = 1;
+ /* Let `cp_finish_decl' know that this initializer is ok. */
+ DECL_INITIAL (decl) = error_mark_node;
+ decl = pushdecl (decl);
- /* Figure out the type that the initializer is. */
- init_type = TREE_TYPE (decl);
- if (TREE_CODE (init_type) != REFERENCE_TYPE
- && TREE_CODE (init_type) != POINTER_TYPE)
- init_type = build_reference_type (init_type);
+ start_decl_1 (decl);
+ cp_finish_decl (decl, init, NULL_TREE,
+ LOOKUP_ONLYCONVERTING|DIRECT_BIND);
+}
- exp = get_eh_value ();
+/* Call this to start a catch block. DECL is the catch parameter. */
- /* Since pointers are passed by value, initialize a reference to
- pointer catch parm with the address of the value slot. */
- if (TREE_CODE (init_type) == REFERENCE_TYPE
- && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
- exp = build_unary_op (ADDR_EXPR, exp, 1);
+tree
+expand_start_catch_block (decl)
+ tree decl;
+{
+ tree exp = NULL_TREE;
+ tree type;
+ bool is_java;
- exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
+ if (! doing_eh (1))
+ return NULL_TREE;
- push_eh_cleanup ();
+ /* Make sure this declaration is reasonable. */
+ if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE))
+ decl = NULL_TREE;
- /* Create a binding level for the parm. */
- pushlevel (0);
- expand_start_bindings (0);
+ if (decl)
+ type = prepare_eh_type (TREE_TYPE (decl));
+ else
+ type = NULL_TREE;
- init = convert_from_reference (exp);
+ is_java = false;
+ if (decl)
+ {
+ tree init;
- /* If the constructor for the catch parm exits via an exception, we
- must call terminate. See eh23.C. */
- if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
+ if (decl_is_java_type (type, 1))
{
- /* Generate the copy constructor call directly so we can wrap it.
- 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 ());
+ /* 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);
+ is_java = true;
}
-
- /* Let `cp_finish_decl' know that this initializer is ok. */
- DECL_INITIAL (decl) = init;
- decl = pushdecl (decl);
-
- start_decl_1 (decl);
- cp_finish_decl (decl, init, NULL_TREE, 0,
- LOOKUP_ONLYCONVERTING|DIRECT_BIND);
+ else
+ {
+ /* 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
- {
- push_eh_cleanup ();
+ finish_expr_stmt (do_begin_catch ());
- /* Create a binding level for the parm. */
- pushlevel (0);
- expand_start_bindings (0);
+ /* C++ requires that we call __cxa_end_catch at the end of
+ processing the exception. */
+ if (! is_java)
+ push_eh_cleanup (type);
- /* Fall into the catch all section. */
- }
+ if (decl)
+ initialize_handler_parm (decl, exp);
- emit_line_note (input_filename, lineno);
+ return type;
}
@@ -716,448 +461,435 @@ expand_end_catch_block ()
if (! doing_eh (1))
return;
- /* Cleanup the EH parameter. */
- expand_end_bindings (getdecls (), kept_level_p (), 0);
- poplevel (kept_level_p (), 1, 0);
-
- /* Cleanup the EH object. */
- expand_end_bindings (getdecls (), kept_level_p (), 0);
- poplevel (kept_level_p (), 1, 0);
-
- /* 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 ();
+ /* The exception being handled is rethrown if control reaches the end of
+ a handler of the function-try-block of a constructor or destructor. */
+ if (in_function_try_handler
+ && (DECL_CONSTRUCTOR_P (current_function_decl)
+ || DECL_DESTRUCTOR_P (current_function_decl)))
+ finish_expr_stmt (build_throw (NULL_TREE));
}
-/* 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. */
-
-void
-expand_start_eh_spec ()
+tree
+begin_eh_spec_block ()
{
- expand_start_try_stmts ();
+ tree r = build_stmt (EH_SPEC_BLOCK, NULL_TREE, NULL_TREE);
+ add_stmt (r);
+ return r;
}
-static void
-expand_end_eh_spec (raises)
- tree raises;
+void
+finish_eh_spec_block (raw_raises, eh_spec_block)
+ tree raw_raises;
+ tree eh_spec_block;
{
- tree tmp, fn, decl, types = NULL_TREE;
- int count = 0;
+ tree raises;
- expand_start_all_catch ();
- expand_start_catch_block (NULL_TREE, NULL_TREE);
+ RECHAIN_STMTS (eh_spec_block, EH_SPEC_STMTS (eh_spec_block));
- /* Build up an array of type_infos. */
- for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
- {
- types = expr_tree_cons
- (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
- ++count;
- }
+ /* 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);
- types = build_nt (CONSTRUCTOR, NULL_TREE, types);
- TREE_HAS_CONSTRUCTOR (types) = 1;
+ EH_SPEC_RAISES (eh_spec_block) = raises;
+}
- /* 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;
- cp_finish_decl (decl, types, NULL_TREE, 0, 0);
+/* Return a pointer to a buffer for an exception object of type TYPE. */
- decl = decay_conversion (decl);
+static tree
+do_allocate_exception (type)
+ tree type;
+{
+ tree fn;
- fn = get_identifier ("__check_eh_spec");
+ fn = get_identifier ("__cxa_allocate_exception");
if (IDENTIFIER_GLOBAL_VALUE (fn))
fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
- push_obstacks_nochange ();
- end_temporary_allocation ();
-
- 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 = build_lang_decl (FUNCTION_DECL, fn, tmp);
- DECL_EXTERNAL (fn) = 1;
- TREE_PUBLIC (fn) = 1;
- DECL_ARTIFICIAL (fn) = 1;
- TREE_THIS_VOLATILE (fn) = 1;
- pushdecl_top_level (fn);
- make_function_rtl (fn);
- pop_obstacks ();
- }
-
- mark_used (fn);
- tmp = expr_tree_cons (NULL_TREE, build_int_2 (count, 0), expr_tree_cons
- (NULL_TREE, decl, NULL_TREE));
- tmp = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), tmp);
- expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
-
- expand_end_catch_block ();
- expand_end_all_catch ();
-}
-
-/* This is called to expand all the toplevel exception handling
- finalization for a function. It should only be called once per
- function. */
-
-void
-expand_exception_blocks ()
-{
- do_pending_stack_adjust ();
- push_to_sequence (catch_clauses);
- expand_leftover_cleanups ();
- do_pending_stack_adjust ();
- catch_clauses = get_insns ();
- end_sequence ();
-
- /* Do this after we expand leftover cleanups, so that the
- expand_eh_region_end that expand_end_eh_spec does will match the
- right expand_eh_region_start, and make sure it comes out before
- the terminate protected region. */
- if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
- {
- expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
- do_pending_stack_adjust ();
- push_to_sequence (catch_clauses);
- expand_leftover_cleanups ();
- do_pending_stack_adjust ();
- catch_clauses = get_insns ();
- end_sequence ();
- }
-
- if (catch_clauses)
- {
- 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 (exceptions_via_longjmp == 0)
- expand_eh_region_start ();
-
- emit_insns (catch_clauses);
- catch_clauses = NULL_RTX;
-
- if (exceptions_via_longjmp == 0)
- expand_eh_region_end (build_terminate_handler ());
-
- expand_leftover_cleanups ();
-
- 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));
}
-tree
-start_anon_func ()
-{
- static int counter = 0;
- int old_interface_unknown = interface_unknown;
- char name[32];
- tree params;
- tree t;
-
- push_cp_function_context (NULL_TREE);
- push_to_top_level ();
-
- /* No need to mangle this. */
- push_lang_context (lang_name_c);
-
- interface_unknown = 1;
-
- params = void_list_node;
- /* tcf stands for throw clean function. */
- sprintf (name, "__tcf_%d", counter++);
- t = make_call_declarator (get_identifier (name), params, NULL_TREE,
- NULL_TREE);
- start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
- void_list_node),
- t, NULL_TREE, 0);
- store_parm_decls ();
- pushlevel (0);
- clear_last_expr ();
- push_momentary ();
- expand_start_bindings (0);
- emit_line_note (input_filename, lineno);
-
- interface_unknown = old_interface_unknown;
-
- pop_lang_context ();
-
- return current_function_decl;
-}
-
-void
-end_anon_func ()
-{
- expand_end_bindings (getdecls (), 1, 0);
- poplevel (1, 0, 0);
- pop_momentary ();
-
- finish_function (lineno, 0, 0);
-
- pop_from_top_level ();
- pop_cp_function_context (NULL_TREE);
-}
-
-/* Return a pointer to a buffer for an exception object of type TYPE. */
+#if 0
+/* Call __cxa_free_exception from a cleanup. This is never invoked
+ directly. */
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;
- push_obstacks_nochange ();
- end_temporary_allocation ();
- tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
- fn = build_lang_decl (FUNCTION_DECL, fn,
- build_function_type (ptr_type_node, tmp));
- DECL_EXTERNAL (fn) = 1;
- TREE_PUBLIC (fn) = 1;
- DECL_ARTIFICIAL (fn) = 1;
- pushdecl_top_level (fn);
- make_function_rtl (fn);
- pop_obstacks ();
+ /* Declare void __cxa_free_exception (void *). */
+ fn = push_void_library_fn (fn, tree_cons (NULL_TREE, ptr_type_node,
+ void_list_node));
}
- mark_used (fn);
- exp = build_function_call (fn, expr_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));
}
+#endif
-/* 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. */
-void
-expand_throw (exp)
+tree
+build_throw (exp)
tree exp;
{
tree fn;
- static tree cleanup_type;
- if (! doing_eh (1))
- return;
+ if (exp == error_mark_node)
+ return exp;
+
+ if (processing_template_decl)
+ return build_min (THROW_EXPR, void_type_node, exp);
- if (exp)
+ if (exp == null_node)
+ warning ("throwing NULL, which has integral, not pointer type");
+
+ if (exp != NULL_TREE)
{
- tree throw_type;
- tree cleanup = NULL_TREE, e;
+ if (!is_admissible_throw_operand (exp))
+ return error_mark_node;
+ }
- /* throw expression */
- /* First, decay it. */
- exp = decay_conversion (exp);
+ if (! doing_eh (1))
+ return error_mark_node;
- /* cleanup_type is void (*)(void *, int),
- the internal type of a destructor. */
- if (cleanup_type == NULL_TREE)
+ if (exp && decl_is_java_type (TREE_TYPE (exp), 1))
+ {
+ tree fn = get_identifier ("_Jv_Throw");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
{
- push_obstacks_nochange ();
- end_temporary_allocation ();
- cleanup_type = build_pointer_type
- (build_function_type
- (void_type_node, tree_cons
- (NULL_TREE, ptr_type_node, tree_cons
- (NULL_TREE, integer_type_node, void_list_node))));
- pop_obstacks ();
+ /* 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);
}
- if (TYPE_PTR_P (TREE_TYPE (exp)))
- throw_type = build_eh_type (exp);
+ exp = build_function_call (fn, tree_cons (NULL_TREE, exp, NULL_TREE));
+ }
+ else if (exp)
+ {
+ tree throw_type;
+ tree cleanup;
+ tree stmt_expr;
+ tree compound_stmt;
+ tree object, ptr;
+ tree tmp;
+
+ fn = get_identifier ("__cxa_throw");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
- tree object, ptr;
-
- /* OK, this is kind of wacky. The WP 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. We also expand the call to __eh_alloc
- first. Since there could be temps in the expression, we need
- to handle that, too. */
-
- expand_start_target_temps ();
-
-#if 0
- /* Unfortunately, this doesn't work. */
- preexpand_calls (exp);
-#else
- /* Store the throw expression into a temp. This can be less
- efficient than storing it into the allocated space directly, but
- oh well. To do this efficiently we would need to insinuate
- ourselves into expand_call. */
- if (TREE_SIDE_EFFECTS (exp))
+ /* The CLEANUP_TYPE is the internal type of a destructor. */
+ if (cleanup_type == NULL_TREE)
{
- tree temp = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp));
- DECL_ARTIFICIAL (temp) = 1;
- DECL_RTL (temp) = assign_temp (TREE_TYPE (exp), 2, 0, 1);
- DECL_INITIAL (temp) = exp;
- cp_finish_decl (temp, exp, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
- exp = temp;
+ 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);
}
-#endif
- /* Allocate the space for the exception. */
- ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
- expand_expr (ptr, const0_rtx, VOIDmode, 0);
+ /* 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);
+ }
- expand_eh_region_start ();
+ begin_init_stmts (&stmt_expr, &compound_stmt);
- object = build_indirect_ref (ptr, NULL_PTR);
- exp = build_modify_expr (object, INIT_EXPR, exp);
+ /* throw expression */
+ /* First, decay it. */
+ exp = decay_conversion (exp);
- if (exp == error_mark_node)
- error (" in thrown expression");
+ /* 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))
+ {
+ tmp = create_temporary_var (TREE_TYPE (exp));
+ DECL_INITIAL (tmp) = exp;
+ cp_finish_decl (tmp, exp, NULL_TREE, LOOKUP_ONLYCONVERTING);
+ exp = tmp;
+ }
- expand_expr (exp, const0_rtx, VOIDmode, 0);
- expand_eh_region_end (build_terminate_handler ());
- expand_end_target_temps ();
+ /* 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);
- throw_type = build_eh_type (object);
+ object = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (exp)), ptr);
+ object = build_indirect_ref (object, NULL);
- if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
- {
- cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
- 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);
- }
+ exp = build_modify_expr (object, INIT_EXPR, exp);
+ if (exp == error_mark_node)
+ error (" in thrown expression");
- exp = ptr;
- }
+ exp = build1 (MUST_NOT_THROW_EXPR, TREE_TYPE (exp), exp);
+ finish_expr_stmt (exp);
- /* Cast EXP to `void *' so that it will match the prototype for
- __cp_push_exception. */
- exp = convert (ptr_type_node, exp);
+ throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object)));
- if (cleanup == NULL_TREE)
+ if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
{
- cleanup = build_int_2 (0, 0);
- TREE_TYPE (cleanup) = cleanup_type;
+ 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);
}
-
- fn = get_identifier ("__cp_push_exception");
- 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;
- push_obstacks_nochange ();
- end_temporary_allocation ();
- 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 = build_lang_decl (FUNCTION_DECL, fn,
- build_function_type (void_type_node, tmp));
- DECL_EXTERNAL (fn) = 1;
- TREE_PUBLIC (fn) = 1;
- DECL_ARTIFICIAL (fn) = 1;
- pushdecl_top_level (fn);
- make_function_rtl (fn);
- pop_obstacks ();
+ cleanup = build_int_2 (0, 0);
+ TREE_TYPE (cleanup) = cleanup_type;
}
- mark_used (fn);
- e = expr_tree_cons (NULL_TREE, exp, expr_tree_cons
- (NULL_TREE, throw_type, expr_tree_cons
- (NULL_TREE, cleanup, NULL_TREE)));
- e = build_function_call (fn, e);
- expand_expr (e, const0_rtx, VOIDmode, 0);
+ 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. */
+
+ 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. */
- push_obstacks_nochange ();
- end_temporary_allocation ();
- fn = build_lang_decl (FUNCTION_DECL, fn,
- build_function_type (void_type_node,
- void_list_node));
- DECL_EXTERNAL (fn) = 1;
- TREE_PUBLIC (fn) = 1;
- DECL_ARTIFICIAL (fn) = 1;
- pushdecl_top_level (fn);
- make_function_rtl (fn);
- pop_obstacks ();
+ /* Declare void __cxa_rethrow (void). */
+ fn = push_throw_library_fn
+ (fn, build_function_type (void_type_node, void_list_node));
}
- mark_used (fn);
exp = build_function_call (fn, NULL_TREE);
- expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
}
- expand_internal_throw ();
+ exp = build1 (THROW_EXPR, void_type_node, exp);
+
+ return exp;
}
-/* Build a throw expression. */
+/* Make sure TYPE is complete, pointer to complete, reference to
+ complete, or pointer to cv void. Issue diagnostic on failure.
+ Return the zero on failure and non-zero on success. FROM can be
+ the expr or decl from whence TYPE came, if available. */
-tree
-build_throw (e)
- tree e;
+static int
+complete_ptr_ref_or_void_ptr_p (type, from)
+ tree type;
+ tree from;
{
- if (e == error_mark_node)
- return e;
+ int is_ptr;
+
+ /* Check complete. */
+ type = complete_type_or_else (type, from);
+ if (!type)
+ return 0;
+
+ /* Or a pointer or ref to one, or cv void *. */
+ is_ptr = TREE_CODE (type) == POINTER_TYPE;
+ if (is_ptr || TREE_CODE (type) == REFERENCE_TYPE)
+ {
+ tree core = TREE_TYPE (type);
+
+ if (is_ptr && VOID_TYPE_P (core))
+ /* OK */;
+ else if (!complete_type_or_else (core, from))
+ return 0;
+ }
+ return 1;
+}
- if (processing_template_decl)
- return build_min (THROW_EXPR, void_type_node, e);
+/* Return truth-value if EXPRESSION is admissible in throw-expression,
+ i.e. if it is not of incomplete type or a pointer/reference to such
+ a type or of an abstract class type. */
+
+static bool
+is_admissible_throw_operand (expr)
+ tree expr;
+{
+ tree type = TREE_TYPE (expr);
+
+ /* 15.1/4 [...] The type of the throw-expression shall not be an
+ incomplete type, or a pointer or a reference to an incomplete
+ type, other than void*, const void*, volatile void*, or
+ const volatile void*. Except for these restriction and the
+ restrictions on type matching mentioned in 15.3, the operand
+ of throw is treated exactly as a function argument in a call
+ (5.2.2) or the operand of a return statement. */
+ if (!complete_ptr_ref_or_void_ptr_p (type, expr))
+ return false;
+
+ /* 10.4/3 An abstract class shall not be used as a parameter type,
+ as a function return type or as type of an explicit
+ conversion. */
+ else if (CLASS_TYPE_P (type) && CLASSTYPE_PURE_VIRTUALS (type))
+ {
+ error ("expression '%E' of abstract class type '%T' cannot be used in throw-expression", expr, type);
+ return false;
+ }
+
+ return true;
+}
+
+/* Returns nonzero if FN is a declaration of a standard C library
+ function which is known not to throw.
+
+ [lib.res.on.exception.handling]: None of the functions from the
+ Standard C library shall report an error by throwing an
+ exception, unless it calls a program-supplied function that
+ throws an exception. */
+
+#include "cfns.h"
+
+int
+nothrow_libfn_p (fn)
+ tree fn;
+{
+ tree id;
+
+ if (TREE_PUBLIC (fn)
+ && DECL_EXTERNAL (fn)
+ && DECL_NAMESPACE_SCOPE_P (fn)
+ && DECL_EXTERN_C_P (fn))
+ /* OK */;
+ else
+ /* Can't be a C library function. */
+ return 0;
+
+ id = DECL_ASSEMBLER_NAME (fn);
+ return !!libc_name_p (IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
+}
+
+/* Returns nonzero if an exception of type FROM will be caught by a
+ handler for type TO, as per [except.handle]. */
+
+static int
+can_convert_eh (to, from)
+ tree to, from;
+{
+ if (TREE_CODE (to) == REFERENCE_TYPE)
+ to = TREE_TYPE (to);
+ if (TREE_CODE (from) == REFERENCE_TYPE)
+ from = TREE_TYPE (from);
+
+ if (TREE_CODE (to) == POINTER_TYPE && TREE_CODE (from) == POINTER_TYPE)
+ {
+ to = TREE_TYPE (to);
+ from = TREE_TYPE (from);
- if (e == null_node)
- cp_warning ("throwing NULL, which has integral, not pointer type");
+ if (! at_least_as_qualified_p (to, from))
+ return 0;
+
+ if (TREE_CODE (to) == VOID_TYPE)
+ return 1;
+
+ /* else fall through */
+ }
- e = build1 (THROW_EXPR, void_type_node, e);
- TREE_SIDE_EFFECTS (e) = 1;
- TREE_USED (e) = 1;
+ if (CLASS_TYPE_P (to) && CLASS_TYPE_P (from)
+ && PUBLICLY_UNIQUELY_DERIVED_P (to, from))
+ return 1;
- return e;
+ return 0;
+}
+
+/* Check whether any of HANDLERS are shadowed by another handler accepting
+ TYPE. Note that the shadowing may not be complete; even if an exception
+ of type B would be caught by a handler for A, there could be a derived
+ class C for which A is an ambiguous base but B is not, so the handler
+ for B would catch an exception of type C. */
+
+static void
+check_handlers_1 (master, handlers)
+ tree master;
+ tree handlers;
+{
+ tree type = TREE_TYPE (master);
+ tree handler;
+
+ for (handler = handlers; handler; handler = TREE_CHAIN (handler))
+ if (TREE_TYPE (handler)
+ && can_convert_eh (type, TREE_TYPE (handler)))
+ {
+ lineno = STMT_LINENO (handler);
+ warning ("exception of type `%T' will be caught",
+ TREE_TYPE (handler));
+ lineno = STMT_LINENO (master);
+ warning (" by earlier handler for `%T'", type);
+ break;
+ }
+}
+
+/* Given a chain of HANDLERs, make sure that they're OK. */
+
+void
+check_handlers (handlers)
+ tree handlers;
+{
+ tree handler;
+ int save_line = lineno;
+ for (handler = handlers; handler; handler = TREE_CHAIN (handler))
+ {
+ if (TREE_CHAIN (handler) == NULL_TREE)
+ /* No more handlers; nothing to shadow. */;
+ else if (TREE_TYPE (handler) == NULL_TREE)
+ {
+ lineno = STMT_LINENO (handler);
+ pedwarn
+ ("`...' handler must be the last handler for its try block");
+ }
+ else
+ check_handlers_1 (handler, TREE_CHAIN (handler));
+ }
+ lineno = save_line;
}
OpenPOWER on IntegriCloud