/* Handle exceptional things in C++.
- Copyright (C) 1989, 1992, 1993 Free Software Foundation, Inc.
- Contributed by Michael Tiemann (tiemann@cygnus.com)
+ Copyright (C) 1989, 92-95, 1996 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.
This file is part of GNU CC.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
-/* High-level class interface. */
-
#include "config.h"
#include "tree.h"
#include "rtl.h"
#include "cp-tree.h"
#include "flags.h"
-/* On Suns this can get you to the right definition if you
- set the right value for TARGET. */
-#include <setjmp.h>
-#ifdef sequent
-/* Can you believe they forgot this? */
-#define _JBLEN 11
-#endif
+#include "obstack.h"
+#include "expr.h"
+#include "output.h"
+#include "except.h"
+#include "function.h"
-#ifndef _JBLEN
-#define _JBLEN (sizeof(jmp_buf)/sizeof(int))
-#endif
+rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
-#undef NULL
-#define NULL (char *)0
+/* holds the fndecl for __builtin_return_address () */
+tree builtin_return_address_fndecl;
-/* This should be part of `ansi_opname', or at least be defined by the std. */
-#define EXCEPTION_NAME_PREFIX "__ex"
-#define EXCEPTION_NAME_LENGTH 4
+/* A couple of backend routines from m88k.c */
-void init_exception_processing ();
-void init_exception_processing_1 ();
+/* used to cache a call to __builtin_return_address () */
+static tree BuiltinReturnAddress;
+
-/* If non-zero, a VAR_DECL whose cleanup will cause a throw to the
- next exception handler. Its value says whether to throw or not.
- In the case of functions which do not issue a RAISE, it should be
- possible to optimize away this VAR_DECL (and overhead associated
- with it). */
-tree exception_throw_decl;
-/* Use this to know that we did not set `exception_throw_decl',
- until GCC optimizer is smart enough to figure it out for itself. */
-int sets_exception_throw_decl;
+#include <stdio.h>
-/* The exception `type' currently in scope, or NULL_TREE if none. */
-tree current_exception_type;
+static void
+easy_expand_asm (str)
+ char *str;
+{
+ expand_asm (build_string (strlen (str)+1, str));
+}
-/* The exception handler object for the given scope. */
-tree current_exception_decl;
-rtx current_exception_name_as_rtx;
-rtx current_exception_parms_as_rtx;
-/* The ``object'' view of the current exception parameters.
- We cast up from the `parms' field to `current_exception_type'. */
-tree current_exception_object;
+#if 0
+/* This is the startup, and finish stuff per exception table. */
-/* Cache `setjmp', `longjmp', `raise_exception', and `unhandled_exception'
- after default conversion. Maybe later they will get built-in. */
-static tree BISJ, BILJ, BIR, BIUE;
+/* XXX - Tad: exception handling section */
+#ifndef EXCEPT_SECTION_ASM_OP
+#define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
+#endif
-/* Local variables which give the appearance that exception
- handling is part of the language and the execution model. */
+#ifdef EXCEPT_SECTION_ASM_OP
+typedef struct {
+ void *start_region;
+ void *end_region;
+ void *exception_handler;
+ } exception_table;
+#endif /* EXCEPT_SECTION_ASM_OP */
-/* The type of the exception handler stack. */
-tree EHS_type;
+#ifdef EXCEPT_SECTION_ASM_OP
-/* The global handler stack. */
-tree EHS_decl;
+ /* 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);
-/* Cached component refs to fields of `EHS_decl'. */
-static tree EHS_prev, EHS_handler, EHS_parms, EHS_name;
-static rtx EHS_parms_as_rtx, EHS_name_as_rtx;
+#endif /* EXCEPT_SECTION_ASM_OP */
-/* The parameter names of this exception type. */
+#ifdef EXCEPT_SECTION_ASM_OP
-static tree last_exception_fields;
-static tree last_exception_field_types;
+ /* we need to know where the end of the exception table is... so this
+ is how we do it! */
-/* When ID is VOID_TYPE_NODE, it means ``raise all''.
- Cannot be inline, since it uses `alloca', and that
- breaks code which pushes the result of this function
- on the stack. */
-static tree
-exception_object_name (prefix, id)
- tree prefix;
- tree id;
-{
- /* First, cons up the `name' of this exception. */
- char *name;
- int length = (id == void_type_node ? 3 : IDENTIFIER_LENGTH (id)) + EXCEPTION_NAME_LENGTH;
+asm (EXCEPT_SECTION_ASM_OP);
+exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
+asm (TEXT_SECTION_ASM_OP);
- if (prefix)
- length += IDENTIFIER_LENGTH (prefix) + 2;
+#endif /* EXCEPT_SECTION_ASM_OP */
- name = (char *)alloca (length);
- strcpy (name, EXCEPTION_NAME_PREFIX);
- length = EXCEPTION_NAME_LENGTH;
- if (prefix)
- {
- strcpy (name + length, IDENTIFIER_POINTER (prefix));
-#ifdef JOINER
- name[length + IDENTIFIER_LENGTH (prefix)] = JOINER;
-#else
- name[length + IDENTIFIER_LENGTH (prefix)] = '_';
#endif
- length += IDENTIFIER_LENGTH (prefix) + 1;
- }
- if (id == void_type_node)
- strcpy (name + length, "all");
- else
- strcpy (name + length, IDENTIFIER_POINTER (id));
- return get_identifier (name);
-}
-tree
-lookup_exception_cname (ctype, cname, raise_id)
- tree ctype, cname;
- tree raise_id;
+#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
+ is the 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.
+
+ ===================================================================== */
+
+extern rtx emit_insn PROTO((rtx));
+extern rtx gen_nop PROTO(());
+
+/* local globals for function calls
+ ====================================================================== */
+
+/* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
+ "set_unexpected ()" after default_conversion. (lib-except.c) */
+static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch;
+
+/* used to cache __find_first_exception_table_match ()
+ for throw (lib-except.c) */
+static tree FirstExceptionMatch;
+
+/* used to cache a call to __unwind_function () (lib-except.c) */
+static tree Unwind;
+
+/* holds a ready to emit call to "terminate ()". */
+static tree TerminateFunctionCall;
+
+static tree empty_fndecl;
+
+/* ====================================================================== */
+
+
+/* ========================================================================= */
+
+
+
+/* local globals - these local globals are for storing data necessary for
+ generating the exception table and code in the correct order.
+
+ ========================================================================= */
+
+/* Holds the pc for doing "throw" */
+static tree saved_pc;
+/* Holds the type of the thing being thrown. */
+static tree saved_throw_type;
+/* Holds the value being thrown. */
+static tree saved_throw_value;
+/* Holds the cleanup for the value being thrown. */
+static tree saved_cleanup;
+/* Indicates if we are in a catch clause. */
+static tree saved_in_catch;
+
+extern int throw_used;
+extern rtx catch_clauses;
+
+/* ========================================================================= */
+
+/* Cheesyness to save some typing. Returns the return value rtx. */
+
+static rtx
+do_function_call (func, params, return_type)
+ tree func, params, return_type;
{
- tree this_cname = TREE_PURPOSE (raise_id);
- if (this_cname == NULL_TREE)
- {
- if (cname)
- {
- tree name = TREE_VALUE (raise_id);
- if (purpose_member (name, CLASSTYPE_TAGS (ctype)))
- this_cname = cname;
- }
- }
- else if (this_cname == void_type_node)
- this_cname = NULL_TREE;
- else if (TREE_CODE (this_cname) != IDENTIFIER_NODE)
- {
- sorry ("multiple scope refs in `cplus_expand_raise_stmt'");
- this_cname = error_mark_node;
- }
- return this_cname;
+ tree func_call;
+ func_call = build_function_call (func, params);
+ expand_call (func_call, NULL_RTX, 0);
+ if (return_type != NULL_TREE)
+ return hard_function_value (return_type, func_call);
+ return NULL_RTX;
}
-tree
-lookup_exception_tname (oname)
- tree oname;
-{
- return get_identifier (IDENTIFIER_POINTER (oname) + EXCEPTION_NAME_LENGTH);
-}
+/* ========================================================================= */
-tree
-lookup_exception_object (cname, name, complain)
- tree cname, name;
- int complain;
-{
- tree oname;
- tree decl;
+extern tree auto_function PROTO((tree, tree, enum built_in_function));
- if (cname == void_type_node)
- cname = NULL_TREE;
- else if (cname && TREE_CODE (cname) != IDENTIFIER_NODE)
- {
- sorry ("multiple scope refs in `lookup_exception_object'");
- cname = NULL_TREE;
- }
- oname = exception_object_name (cname, name);
- decl = IDENTIFIER_GLOBAL_VALUE (oname);
- if (decl == NULL_TREE || TREE_CODE (decl) != VAR_DECL)
- {
- if (complain)
- {
- push_obstacks_nochange ();
+/* sets up all the global eh stuff that needs to be initialized at the
+ start of compilation.
- if (cname)
- error ("no exception name object for name `%s::%s'",
- IDENTIFIER_POINTER (cname),
- IDENTIFIER_POINTER (name));
- else
- error ("no exception name object for name `%s'",
- IDENTIFIER_POINTER (name));
- end_temporary_allocation ();
- /* Avoid further error messages. */
- pushdecl_top_level (build_lang_field_decl (VAR_DECL,
- exception_object_name (cname, name),
- error_mark_node));
- pop_obstacks ();
- }
- return NULL_TREE;
- }
- return decl;
-}
+ This includes:
+ - Setting up all the function call trees. */
-tree
-lookup_exception_type (ctype, cname, raise_id)
- tree ctype, cname;
- tree raise_id;
+void
+init_exception_processing ()
{
- tree name = TREE_VALUE (raise_id);
- tree purpose = TREE_PURPOSE (raise_id);
+ extern tree define_function ();
+ tree unexpected_fndecl, terminate_fndecl;
+ tree set_unexpected_fndecl, set_terminate_fndecl;
+ tree catch_match_fndecl;
+ tree find_first_exception_match_fndecl;
+ tree unwind_fndecl;
+ tree declspecs;
+ tree d;
+
+ /* void (*)() */
+ tree PFV = build_pointer_type (build_function_type
+ (void_type_node, void_list_node));
+
+ /* arg list for the build_function_type call for set_terminate () and
+ set_unexpected () */
+ tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
+
+ /* void (*pfvtype (void (*) ()))() */
+ tree pfvtype = build_function_type (PFV, pfvlist);
+
+ /* void vtype () */
+ tree vtype = build_function_type (void_type_node, void_list_node);
+
+ set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
+ pfvtype, NOT_BUILT_IN);
+ set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
+ pfvtype, NOT_BUILT_IN);
+ unexpected_fndecl = auto_function (get_identifier ("unexpected"),
+ vtype, NOT_BUILT_IN);
+ terminate_fndecl = auto_function (get_identifier ("terminate"),
+ vtype, NOT_BUILT_IN);
- if (cname && purpose == NULL_TREE)
- purpose = cname;
+ push_lang_context (lang_name_c);
- if (purpose && purpose != void_type_node)
- {
- tree link = NULL_TREE;
+ catch_match_fndecl =
+ builtin_function (flag_rtti
+ ? "__throw_type_match_rtti"
+ : "__throw_type_match",
+ build_function_type (ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ void_list_node)))),
+ NOT_BUILT_IN, NULL_PTR);
+ find_first_exception_match_fndecl =
+ 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_fndecl =
+ 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);
+ empty_fndecl =
+ builtin_function ("__empty",
+ build_function_type (void_type_node, void_list_node),
+ NOT_BUILT_IN, NULL_PTR);
+ DECL_EXTERNAL (empty_fndecl) = 1;
+ TREE_PUBLIC (empty_fndecl) = 1;
+
+ Unexpected = default_conversion (unexpected_fndecl);
+ Terminate = default_conversion (terminate_fndecl);
+ SetTerminate = default_conversion (set_terminate_fndecl);
+ SetUnexpected = default_conversion (set_unexpected_fndecl);
+ CatchMatch = default_conversion (catch_match_fndecl);
+ FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
+ Unwind = default_conversion (unwind_fndecl);
+ BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
+
+ TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
- if (TREE_CODE (purpose) != IDENTIFIER_NODE)
- {
- sorry ("multiple scope refs in `lookup_exception_type'");
- TREE_PURPOSE (raise_id) = NULL_TREE;
- return NULL_TREE;
- }
- if (! is_aggr_typedef (purpose, 1))
- return NULL_TREE;
- ctype = IDENTIFIER_TYPE_VALUE (purpose);
- link = purpose_member (name, CLASSTYPE_TAGS (ctype));
- if (link)
- return TREE_VALUE (link);
- }
+ pop_lang_context ();
- ctype = lookup_name (name, 1);
- if (ctype && TREE_CODE (ctype) == TYPE_DECL)
- ctype = TREE_TYPE (ctype);
- if (ctype && TREE_CODE (ctype) == RECORD_TYPE
- && CLASSTYPE_DECLARED_EXCEPTION (ctype))
- return ctype;
- return NULL_TREE;
+ declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
+ d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc"));
+ d = start_decl (d, declspecs, 0);
+ DECL_COMMON (d) = 1;
+ cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
+ saved_pc = lookup_name (get_identifier ("__eh_pc"), 0);
+
+ declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
+ d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type"));
+ d = start_decl (d, declspecs, 0);
+ DECL_COMMON (d) = 1;
+ cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
+ saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0);
+
+ declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
+ d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value"));
+ d = start_decl (d, declspecs, 0);
+ DECL_COMMON (d) = 1;
+ cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
+ saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0);
+
+ declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
+ d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_cleanup"));
+ d = make_call_declarator (d, void_list_node, NULL_TREE, NULL_TREE);
+ d = start_decl (d, declspecs, 0);
+ DECL_COMMON (d) = 1;
+ cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
+ saved_cleanup = lookup_name (get_identifier ("__eh_cleanup"), 0);
+
+ declspecs = tree_cons (NULL_TREE, get_identifier ("bool"), NULL_TREE);
+ d = get_identifier ("__eh_in_catch");
+ d = start_decl (d, declspecs, 0);
+ DECL_COMMON (d) = 1;
+ cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
+ saved_in_catch = lookup_name (get_identifier ("__eh_in_catch"), 0);
}
-tree
-finish_exception (e, list_of_fieldlists)
- tree e;
- tree list_of_fieldlists;
-{
- tree parmtypes = NULL_TREE, name_field;
- tree cname = TYPE_NAME (e);
-
- if (TREE_CODE (cname) == TYPE_DECL)
- cname = DECL_NAME (cname);
+/* Build a type value for use at runtime for a type that is matched
+ against by the exception handling system. */
- if (last_exception_fields)
- error ("cannot declare exceptions within exceptions");
- if (list_of_fieldlists && ! ANON_AGGRNAME_P (cname))
- cp_error ("exception name `%T' must follow body declaration", e);
- if (list_of_fieldlists)
- {
- tree prev, field;
-
- /* Note: no public, private, or protected allowed. */
- if (TREE_CHAIN (list_of_fieldlists))
- error ("access declarations invalid in exception declaration");
- else if (TREE_PURPOSE (list_of_fieldlists) != (tree)access_default)
- error ("access declarations invalid in exception declaration");
- TREE_PURPOSE (list_of_fieldlists) = (tree)access_default;
-
- /* Note also: no member function declarations allowed. */
- for (prev = 0, field = TREE_VALUE (list_of_fieldlists);
- field; prev = field, field = TREE_CHAIN (field))
- {
- switch (TREE_CODE (field))
- {
- case FIELD_DECL:
- /* ok. */
- parmtypes = tree_cons (NULL_TREE, TREE_TYPE (field), parmtypes);
- continue;
- case FUNCTION_DECL:
- cp_error ("declaration of function `%D' in exception invalid",
- field);
- break;
- case VAR_DECL:
- if (TREE_STATIC (field))
- cp_error ("declaration of static variable `%D' in exception invalid", field);
- else
- cp_error ("declaration of constant field `%D' in exception invalid", field);
- break;
- case CONST_DECL:
- cp_error ("declaration of enum value `%D' in exception invalid", field);
- break;
- case SCOPE_REF:
- error ("use of `::' in exception context invalid");
- break;
- }
- if (prev)
- TREE_CHAIN (prev) = TREE_CHAIN (field);
- else
- TREE_VALUE (list_of_fieldlists) = TREE_CHAIN (field);
- }
- }
+static tree
+build_eh_type_type (type)
+ tree type;
+{
+ char *typestring;
+ tree exp;
- /* Now that we've cleaned up the fields, add a name identifier at front. */
- name_field = build_lang_field_decl (FIELD_DECL, get_identifier ("__name"),
- ptr_type_node);
- if (list_of_fieldlists)
- {
- TREE_CHAIN (name_field) = TREE_VALUE (list_of_fieldlists);
- TREE_VALUE (list_of_fieldlists) = name_field;
- }
- else
- list_of_fieldlists = build_tree_list (NULL_TREE, name_field);
+ if (type == error_mark_node)
+ return error_mark_node;
- last_exception_fields = TREE_VALUE (list_of_fieldlists);
- if (parmtypes)
- {
- last_exception_field_types = nreverse (parmtypes);
- /* Set the TREE_CHAIN of what is now at the end of the
- list to `void_list_node'. */
- TREE_CHAIN (parmtypes) = void_list_node;
- }
- else
- last_exception_field_types = void_list_node;
+ /* peel back references, so they match. */
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
- popclass (0);
+ /* Peel off cv qualifiers. */
+ type = TYPE_MAIN_VARIANT (type);
-#if 0
- /* Remove aggregate types from the list of tags,
- since these appear at global scope. */
- while (x && IS_AGGR_TYPE (TREE_VALUE (x)))
- x = TREE_CHAIN (x);
- CLASSTYPE_TAGS (t) = x;
- y = x;
- while (x)
+ if (flag_rtti)
{
- if (IS_AGGR_TYPE (TREE_VALUE (x)))
- TREE_CHAIN (y) = TREE_CHAIN (x);
- x = TREE_CHAIN (x);
+ return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
}
-#endif
-
- if (flag_cadillac)
- cadillac_finish_exception (e);
- return e;
+ typestring = build_overload_name (type, 1, 1);
+ exp = combine_strings (build_string (strlen (typestring)+1, typestring));
+ return build1 (ADDR_EXPR, ptr_type_node, exp);
}
-void
-finish_exception_decl (cname, decl)
- tree cname, decl;
+/* Build a type value for use at runtime for a exp that is thrown or
+ matched against by the exception handling system. */
+
+static tree
+build_eh_type (exp)
+ tree exp;
{
- /* In decl.h. */
- extern tree last_function_parms;
-
- /* An exception declaration. */
- tree t, ctor;
- tree parmdecls = NULL_TREE, fields;
- tree list_of_fieldlists = temp_tree_cons (NULL_TREE,
- copy_list (last_exception_fields),
- NULL_TREE);
- tree edecl = build_lang_field_decl (VAR_DECL,
- exception_object_name (cname, DECL_NAME (decl)),
- ptr_type_node);
-
- DECL_LANGUAGE (edecl) = lang_c;
- TREE_STATIC (edecl) = 1;
- TREE_PUBLIC (edecl) = 1;
- finish_decl (pushdecl (edecl), NULL_TREE, NULL_TREE, 0);
-
- /* Now instantiate the exception decl. */
- t = xref_tag (exception_type_node, DECL_NAME (decl), NULL_TREE, 0);
-
- /* finish_struct will pop this. */
- pushclass (t, 0);
-
- /* Now add a constructor which takes as parameters all the types we
- just defined. */
- ctor = build_lang_decl (FUNCTION_DECL, DECL_NAME (decl),
- build_cplus_method_type (t, TYPE_POINTER_TO (t),
- last_exception_field_types));
- /* Don't take `name'. The constructor handles that. */
- fields = TREE_CHAIN (TREE_VALUE (list_of_fieldlists));
- while (fields)
+ if (flag_rtti)
{
- tree parm = build_decl (PARM_DECL, DECL_NAME (fields), TREE_TYPE (fields));
- /* Since there is a prototype, args are passed in their own types. */
- DECL_ARG_TYPE (parm) = TREE_TYPE (parm);
-#ifdef PROMOTE_PROTOTYPES
- if ((TREE_CODE (TREE_TYPE (fields)) == INTEGER_TYPE
- || TREE_CODE (TREE_TYPE (fields)) == ENUMERAL_TYPE)
- && TYPE_PRECISION (TREE_TYPE (fields)) < TYPE_PRECISION (integer_type_node))
- DECL_ARG_TYPE (parm) = integer_type_node;
-#endif
- TREE_CHAIN (parm) = parmdecls;
- parmdecls = parm;
- fields = TREE_CHAIN (fields);
- }
- fields = TREE_VALUE (list_of_fieldlists);
- last_function_parms = nreverse (parmdecls);
-
- DECL_CONSTRUCTOR_P (ctor) = 1;
- TYPE_HAS_CONSTRUCTOR (t) = 1;
- grokclassfn (t, DECL_NAME (decl), ctor, NO_SPECIAL, NULL_TREE);
- DECL_EXTERNAL (ctor) = 1;
- TREE_STATIC (ctor) = 1;
- TREE_PUBLIC (ctor) = 0;
- DECL_INLINE (ctor) = 1;
- make_decl_rtl (ctor, NULL_PTR, 1);
- finish_decl (ctor, NULL_TREE, NULL_TREE, 0);
- TREE_CHAIN (ctor) = TREE_VALUE (list_of_fieldlists);
- TREE_VALUE (list_of_fieldlists) = ctor;
-
- finish_struct (t, list_of_fieldlists, 0);
-
- if (current_function_decl)
- error ("cannot define exception inside function scope");
- else
- {
- enum debug_info_type old_write_symbols = write_symbols;
- write_symbols = NO_DEBUG;
-
- /* Now build the constructor for this exception. */
- parmdecls = DECL_ARGUMENTS (ctor);
- start_function (NULL_TREE, ctor, 0, 1);
- store_parm_decls ();
- pushlevel (0);
- clear_last_expr ();
- push_momentary ();
- expand_start_bindings (0);
-
- /* Move all the parameters to the fields, skipping `this'. */
- parmdecls = TREE_CHAIN (parmdecls);
- /* Install `name' of this exception handler. */
- DECL_INITIAL (fields) = build_unary_op (ADDR_EXPR, edecl, 0);
- fields = TREE_CHAIN (fields);
- /* Install all the values. */
- while (fields)
- {
- /* Set up the initialization for this field. */
- DECL_INITIAL (fields) = parmdecls;
- fields = TREE_CHAIN (fields);
- parmdecls = TREE_CHAIN (parmdecls);
- }
- emit_base_init (t, 0);
-
- finish_function (DECL_SOURCE_LINE (ctor), 1);
- write_symbols = old_write_symbols;
+ exp = build_typeid (exp);
+ return build1 (ADDR_EXPR, ptr_type_node, exp);
}
+ return build_eh_type_type (TREE_TYPE (exp));
}
-void
-end_exception_decls ()
+/* This routine creates the cleanup for the exception handling object. */
+
+static void
+push_eh_cleanup ()
{
- last_exception_field_types = NULL_TREE;
- last_exception_fields = NULL_TREE;
+ /* All cleanups must last longer than normal. */
+ int yes = suspend_momentary ();
+
+ /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
+ tree cleanup = build_function_call (saved_cleanup, NULL_TREE);
+ cleanup = build (COMPOUND_EXPR, void_type_node, cleanup,
+ build_modify_expr (saved_in_catch, NOP_EXPR,
+ build_modify_expr (saved_throw_type, NOP_EXPR, integer_zero_node)));
+ expand_decl_cleanup (NULL_TREE, cleanup);
+
+ resume_momentary (yes);
}
-\f
-/* Statement-level exception semantics. */
+
+
+/* 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) */
void
-cplus_expand_start_try (implicit)
- int implicit;
+expand_start_catch_block (declspecs, declarator)
+ tree declspecs, declarator;
{
- tree call_to_setjmp;
- tree handler, ref;
-
- /* Start a new block enclosing the whole handler. */
- if (implicit)
- {
- pushlevel_temporary (1);
- }
- else
- {
- pushlevel (0);
- clear_last_expr ();
- push_momentary ();
-
- /* Encompass whole exception handler in one big binding contour.
- If RAISE should throw out of the whole TRY/EXCEPT block, call
- `expand_start_bindings' with argument of 1. */
- expand_start_bindings (0);
- }
+ rtx false_label_rtx;
+ tree decl = NULL_TREE;
+ tree init;
- /* Allocate handler in that block. It's real name will come later.
- Note that it will be the first name in this binding contour. */
- handler = get_temp_name (EHS_type, 0);
- DECL_INITIAL (handler) = error_mark_node;
- finish_decl (handler, NULL_TREE, NULL_TREE, 0);
+ if (! doing_eh (1))
+ return;
- /* Must come after call to `finish_decl', else the cleanup for the temp
- for the handler will cause the contour we just created to be popped. */
- if (implicit)
- declare_implicit_exception ();
+ /* Create a binding level for the parm. */
+ pushlevel (0);
+ expand_start_bindings (0);
- /* Catch via `setjmp'. */
- ref = build_component_ref (handler, get_identifier ("handler"), NULL_TREE, 0);
- call_to_setjmp = build_function_call (BISJ, build_tree_list (NULL_TREE, ref));
+ false_label_rtx = gen_label_rtx ();
+ push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
- /* RAISE throws to EXCEPT part. */
- expand_start_try (build_binary_op (EQ_EXPR, call_to_setjmp, integer_zero_node, 1), 0, 1);
-}
+ if (declspecs)
+ {
+ tree exp;
+ rtx call_rtx, return_value_rtx;
+ tree init_type;
-/* If KEEP is 1, then declarations in the TRY statement are worth keeping.
- If KEEP is 2, then the TRY statement was generated by the compiler.
- If KEEP is 0, the declarations in the TRY statement contain errors. */
+ decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
-tree
-cplus_expand_end_try (keep)
- int keep;
-{
- tree decls, decl, block;
+ if (decl == NULL_TREE)
+ {
+ error ("invalid catch parameter");
- if (keep < 2)
- pop_implicit_try_blocks (NULL_TREE);
+ /* This is cheap, but we want to maintain the data structures. */
+ expand_eh_region_start ();
+ return;
+ }
- decls = getdecls ();
+ /* Make sure we mark the catch param as used, otherwise we'll get
+ a warning about an unused ((anonymous)). */
+ TREE_USED (decl) = 1;
- /* Emit code to avoid falling through into a default
- handler that might come later. */
- expand_end_try ();
+ /* 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);
- /* Pops binding contour local to TRY, and get the exception handler
- object built by `...start_try'. */
- switch (keep)
- {
- case 0:
- expand_end_bindings (decls, 0, 1);
- block = poplevel (0, 0, 0);
- pop_momentary ();
- decl = getdecls ();
- break;
-
- case 1:
- expand_end_bindings (decls, 1, 1);
- block = poplevel (1, 1, 0);
- pop_momentary ();
- decl = getdecls ();
- break;
-
- default:
- decl = tree_last (decls);
- block = NULL_TREE;
- break;
- }
+ exp = saved_throw_value;
+ exp = tree_cons (NULL_TREE,
+ build_eh_type_type (TREE_TYPE (decl)),
+ tree_cons (NULL_TREE,
+ saved_throw_type,
+ tree_cons (NULL_TREE, exp, NULL_TREE)));
+ exp = build_function_call (CatchMatch, exp);
+ call_rtx = expand_call (exp, NULL_RTX, 0);
+ assemble_external (TREE_OPERAND (CatchMatch, 0));
- my_friendly_assert (TREE_CODE (decl) == VAR_DECL
- && TREE_TYPE (decl) == EHS_type, 203);
- if (block)
- {
- BLOCK_HANDLER_BLOCK (block) = 1;
- TREE_USED (block) = 1;
- }
+ return_value_rtx = hard_function_value (ptr_type_node, exp);
- /* Pass it back so that its rtl can be bound to its name
- (or vice versa). */
- return decl;
-}
+ /* did the throw type match function return TRUE? */
+ emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
+ GET_MODE (return_value_rtx), 0, 0);
-void
-cplus_expand_start_except (name, decl)
- tree name, decl;
-{
- int yes;
- tree tmp, init;
+ /* if it returned FALSE, jump over the catch block, else fall into it */
+ emit_jump_insn (gen_beq (false_label_rtx));
- expand_start_except (0, 1);
+ push_eh_cleanup ();
- /* This is internal `eh'. */
- current_exception_decl = decl;
- current_exception_name_as_rtx
- = expand_expr (build (COMPONENT_REF, ptr_type_node,
- current_exception_decl, TREE_OPERAND (EHS_name, 1)),
- 0, 0, 0);
- init = build (COMPONENT_REF, ptr_type_node, decl, TREE_OPERAND (EHS_parms, 1));
- current_exception_parms_as_rtx = expand_expr (init, 0, 0, 0);
+ init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
- if (name)
- {
- /* Get the exception object into scope (user declared `ex'). */
- tmp = pushdecl (build_decl (VAR_DECL, name, ptr_type_node));
- DECL_INITIAL (tmp) = error_mark_node;
- finish_decl (tmp, init, 0, 0);
+ /* Do we need the below two lines? */
+ /* Let `cp_finish_decl' know that this initializer is ok. */
+ DECL_INITIAL (decl) = init;
+ decl = pushdecl (decl);
+ cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
}
- current_exception_type = NULL_TREE;
- yes = suspend_momentary ();
- if (name)
+ else
{
- /* From now on, send the user to our faked-up object. */
- current_exception_object = build1 (INDIRECT_REF, void_type_node, tmp);
- IDENTIFIER_LOCAL_VALUE (name) = current_exception_object;
+ push_eh_cleanup ();
+
+ /* Fall into the catch all section. */
}
- resume_momentary (yes);
- /* Pop exception handler stack. */
- expand_assignment (EHS_decl, EHS_prev, 0, 0);
+ emit_move_insn (DECL_RTL (saved_in_catch), const1_rtx);
+
+ /* Because we are reordered out of line, we arrange
+ to rethrow in the outer context, should we encounter
+ an exception in the catch handler.
+
+ Matches the end in expand_end_catch_block (). */
+ expand_eh_region_start ();
+
+ emit_line_note (input_filename, lineno);
}
-/* Generate the call to `unhandled_exception' that is appropriate
- for this particular unhandled exception. */
-static tree
-call_to_unhandled_exception ()
+
+
+/* Call this to end a catch block. Its responsible for emitting the
+ code to handle jumping back to the correct place, and for emitting
+ the label to jump to if this catch block didn't match. */
+
+void expand_end_catch_block ()
{
- extern int lineno;
- extern tree combine_strings ();
- tree parms = tree_cons (NULL_TREE,
- combine_strings (build_string (strlen (input_filename + 1), input_filename)),
- build_tree_list (NULL_TREE, build_int_2 (lineno, 0)));
- return build_function_call (BIUE, parms);
+ rtx start_region_label_rtx;
+ rtx end_region_label_rtx;
+ tree decls, t;
+
+ if (! doing_eh (1))
+ return;
+
+ /* 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));
+
+ t = make_node (RTL_EXPR);
+ TREE_TYPE (t) = void_type_node;
+ RTL_EXPR_RTL (t) = const0_rtx;
+ TREE_SIDE_EFFECTS (t) = 1;
+ start_sequence_for_rtl_expr (t);
+ expand_internal_throw (DECL_RTL (top_label_entry (&caught_return_label_stack)));
+ RTL_EXPR_SEQUENCE (t) = get_insns ();
+ end_sequence ();
+
+ /* Matches the start in expand_start_catch_block (). */
+ expand_eh_region_end (t);
+
+ expand_leftover_cleanups ();
+
+ /* Cleanup the EH parameter. */
+ expand_end_bindings (getdecls (), kept_level_p (), 0);
+ poplevel (kept_level_p (), 1, 0);
+
+ /* label we emit to jump to if this catch block didn't match. */
+ /* This the closing } in the `if (eq) {' of the documentation. */
+ emit_label (pop_label_entry (&false_label_stack));
}
-/* Note that this must be mirror image of `...start_try'.
- DFAULT is the default clause, if there was one.
- DFAULT is ERROR_MARK_NODE when this ends an implicit handler. */
-void
-cplus_expand_end_except (dfault)
- tree dfault;
+/* unwind the stack. */
+
+static void
+do_unwind (inner_throw_label)
+ rtx inner_throw_label;
{
- extern tree expand_end_except (); /* stmt.c. */
- tree decls, raised;
+#if defined (SPARC_STACK_ALIGN) /* was sparc */
+ /* This doesn't work for the flat model sparc, I bet. */
+ tree fcall;
+ tree params;
+ rtx return_val_rtx;
+ rtx temp;
+
+ /* call to __builtin_return_address () */
+ params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
+ fcall = build_function_call (BuiltinReturnAddress, params);
+ return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
+ /* In the return, the new pc is pc+8, as the value coming in is
+ really the address of the call insn, not the next insn. */
+ temp = gen_reg_rtx (Pmode);
+ emit_move_insn (temp, inner_throw_label);
+ emit_move_insn (return_val_rtx, plus_constant (temp, -8));
+ emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, 31)));
+ easy_expand_asm ("ret");
+ easy_expand_asm ("restore");
+ emit_barrier ();
+#endif
+#if defined (ARM_FRAME_RTX) /* was __arm */
+ if (flag_omit_frame_pointer)
+ sorry ("this implementation of exception handling requires a frame pointer");
+
+ emit_move_insn (stack_pointer_rtx,
+ gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8)));
+ emit_move_insn (hard_frame_pointer_rtx,
+ gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12)));
+#endif
+#if defined (TARGET_88000) /* was m88k */
+ rtx temp_frame = frame_pointer_rtx;
- if (dfault == NULL_TREE)
- {
- /* Uncaught exception at outermost level. If raised locally,
- reraise the exception. Otherwise, generate code to call `abort'. */
- if (in_try_block (1) == 0)
- {
- expand_start_cond (build (EQ_EXPR, integer_type_node,
- exception_throw_decl, integer_zero_node), 0);
- expand_expr (call_to_unhandled_exception (), 0, VOIDmode, 0);
- expand_end_cond ();
- }
- /* Try the next handler. */
- if (! expand_escape_except ())
- compiler_error ("except nesting botch");
- }
+ temp_frame = memory_address (Pmode, temp_frame);
+ temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
- raised = expand_end_except ();
+ /* hopefully this will successfully pop the frame! */
+ emit_move_insn (frame_pointer_rtx, temp_frame);
+ emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+ emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
+ emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
+ (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
- decls = getdecls ();
- expand_end_bindings (decls, decls != 0, 1);
- poplevel (decls != 0, 1, 0);
+#if 0
+ emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
+ -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
- /* Implicit handlers do not use the momentary obstack. */
- if (dfault != error_mark_node)
- pop_momentary ();
+ emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
- if (! in_try_block (1))
- {
- /* Check that this function is not raising exceptions
- it is not supposed to. */
- while (raised)
- {
- cp_error ("exception `%D' raised but not declared raisable",
- TREE_VALUE (raised));
- raised = TREE_CHAIN (raised);
- }
- }
- else if (dfault == NULL_TREE || dfault == error_mark_node)
- {
- expand_start_cond (build (NE_EXPR, integer_type_node,
- exception_throw_decl,
- integer_zero_node), 0);
- /* We fell off the end of this try block. Try going to the next.
- The escape_label will be the beginning of the next try block. */
- if (! expand_escape_except ())
- compiler_error ("except nesting botch");
- expand_end_cond ();
- }
+ emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
+ (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
+#endif
+#endif
+#if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
+ tree fcall;
+ tree params;
+ rtx return_val_rtx;
+
+#if 0
+ /* I would like to do this here, but the move below doesn't seem to work. */
+ /* call to __builtin_return_address () */
+ params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
+ fcall = build_function_call (BuiltinReturnAddress, params);
+ return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
+
+ emit_move_insn (return_val_rtx, inner_throw_label);
+ /* So, for now, just pass throw label to stack unwinder. */
+#endif
+ params = tree_cons (NULL_TREE, make_tree (ptr_type_node,
+ inner_throw_label), NULL_TREE);
+
+ do_function_call (Unwind, params, NULL_TREE);
+ assemble_external (TREE_OPERAND (Unwind, 0));
+ emit_barrier ();
+#endif
}
-/* Generate code to raise exception RAISE_ID.
- If EXP is NULL_TREE, then PARMS is the list of parameters to use
- for constructing this exception.
- If EXP is non-NULL, then it is an already constructed object
- of the kind that we want.
- FOR_RERAISE is non-zero if this raise is called by reraise. In
- this case we do not need to emit extra gotos to avoid warning messages;
- the caller will do that once after all the exceptions it reraises
- are handled and raised. */
+/* is called from expand_exception_blocks () to generate the code in a function
+ to "throw" if anything in the function needs to perform a throw.
+
+ expands "throw" as the following pseudo code:
+
+ throw:
+ eh = find_first_exception_match (saved_pc);
+ if (!eh) goto gotta_rethrow_it;
+ goto eh;
+
+ gotta_rethrow_it:
+ saved_pc = __builtin_return_address (0);
+ pop_to_previous_level ();
+ goto throw; */
+
void
-cplus_expand_raise (raise_id, parms, exp, for_reraise)
- tree raise_id;
- tree parms;
- tree exp;
- int for_reraise;
+expand_builtin_throw ()
{
- /* Allocate new exception of appropriate type, passing
- PARMS to its constructor. */
- tree cname, name;
- tree decl;
- tree xexp = exp;
-
- cname = lookup_exception_cname (current_class_type, current_class_name, raise_id);
- if (cname == error_mark_node)
+ tree fcall;
+ tree params;
+ rtx return_val_rtx;
+ rtx gotta_rethrow_it;
+ rtx gotta_call_terminate;
+ rtx top_of_loop;
+ rtx unwind_first;
+ tree t;
+
+ if (! doing_eh (0))
return;
- name = TREE_VALUE (raise_id);
- decl = lookup_exception_object (cname, name, 1);
- if (decl == NULL_TREE)
+ if (! throw_used)
return;
- if (exp == NULL_TREE)
- {
- exp = build_method_call (NULL_TREE, name, parms, NULL_TREE, LOOKUP_COMPLAIN);
- if (exp == error_mark_node)
- return;
- }
+ params = void_list_node;
+ t = make_call_declarator (get_identifier ("__throw"), 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);
+
+ gotta_rethrow_it = gen_label_rtx ();
+ gotta_call_terminate = gen_label_rtx ();
+ top_of_loop = gen_label_rtx ();
+ unwind_first = gen_label_rtx ();
+
+ /* These two can be frontend specific. If wanted, they can go in
+ expand_throw. */
+ /* Do we have a valid object we are throwing? */
+ emit_cmp_insn (DECL_RTL (saved_throw_type), const0_rtx, EQ, NULL_RTX,
+ GET_MODE (DECL_RTL (saved_throw_type)), 0, 0);
+ emit_jump_insn (gen_beq (gotta_call_terminate));
+
+ emit_jump (unwind_first);
+
+ emit_label (top_of_loop);
+
+ /* search for an exception handler for the saved_pc */
+ return_val_rtx = do_function_call (FirstExceptionMatch,
+ tree_cons (NULL_TREE, saved_pc, NULL_TREE),
+ ptr_type_node);
+ assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
+
+ /* did we find one? */
+ emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
+ GET_MODE (return_val_rtx), 0, 0);
+
+ /* if not, jump to gotta_rethrow_it */
+ emit_jump_insn (gen_beq (gotta_rethrow_it));
+
+ /* we found it, so jump to it */
+ emit_indirect_jump (return_val_rtx);
+
+ /* code to deal with unwinding and looking for it again */
+ emit_label (gotta_rethrow_it);
+
+ /* call to __builtin_return_address () */
+#if defined (ARM_FRAME_RTX) /* was __arm */
+ /* This should be moved into arm.h:RETURN_ADDR_RTX */
+ /* This replaces a 'call' to __builtin_return_address */
+ return_val_rtx = gen_reg_rtx (Pmode);
+ emit_move_insn (return_val_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
+#else
+ params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
+ fcall = build_function_call (BuiltinReturnAddress, params);
+ return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
+#endif
- if (in_try_block (1))
- {
- expand_raise (decl);
- }
- else if (! current_function_decl)
- {
- if (xexp == NULL_TREE)
- cp_error ("invalid raise of `%D' outside of functions", decl);
- else
- cp_error ("invalid reraise of `%D' outside of functions", decl);
- }
- else
- {
- /* Test this raise against what this function permits. */
- tree names = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl));
- while (names)
- {
- if (decl == TREE_TYPE (names))
- break;
- names = TREE_CHAIN (names);
- }
- if (names == NULL_TREE)
- {
- error ("current function not declared to raise exception `%s'",
- IDENTIFIER_POINTER (name));
- return;
- }
- }
+ /* did __builtin_return_address () return a valid address? */
+ emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
+ GET_MODE (return_val_rtx), 0, 0);
- store_expr (exp, EHS_parms_as_rtx, 0);
+ emit_jump_insn (gen_beq (gotta_call_terminate));
- /* Set the global exception handler stack's NAME field
- to the `name' of this exception. The global exception
- handler stack is the container for the exception object
- we just built.
+ return_val_rtx = eh_outer_context (return_val_rtx);
- We go through a function call to make life easier when debugging. */
-#if 0
- expand_assignment (EHS_name, build_unary_op (ADDR_EXPR, decl, 0), 0, 0);
-#else
- parms = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, EHS_name, 0),
- build_tree_list (NULL_TREE,
- build_unary_op (ADDR_EXPR, decl, 0)));
- expand_expr (build_function_call (BIR, parms), 0, 0, 0);
+ /* Yes it did. */
+ emit_move_insn (eh_saved_pc_rtx, return_val_rtx);
+
+ do_unwind (gen_rtx (LABEL_REF, Pmode, top_of_loop));
+ emit_jump (top_of_loop);
+
+ /* no it didn't --> therefore we need to call terminate */
+ emit_label (gotta_call_terminate);
+ do_function_call (Terminate, NULL_TREE, NULL_TREE);
+ assemble_external (TREE_OPERAND (Terminate, 0));
+
+ {
+ rtx ret_val, return_val_rtx;
+ emit_label (unwind_first);
+ ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
+ 0, hard_frame_pointer_rtx);
+
+ /* Set it up so that we continue inside, at the top of the loop. */
+ emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
+#ifdef RETURN_ADDR_OFFSET
+ return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
+ if (return_val_rtx != ret_val)
+ emit_move_insn (ret_val, return_val_rtx);
#endif
- /* Activate thrower. If we are inside a TRY statement,
- we can cheat and not do this, saving a longjmp. */
- if (in_try_block (1) == 0)
- {
- sets_exception_throw_decl = 1;
- emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx);
- }
+ /* Fall into epilogue to unwind prologue. */
+ }
- if (xexp == NULL_TREE)
- {
- /* Invoke destructors for current procedure or handler. */
- if (! expand_escape_except ())
- compiler_error ("except nesting botch");
- /* Throw via `longjmp'... Done as side-effect of goto. */
- }
- /* To avoid spurious warning messages, we add a goto to the end
- of the function. This code is dead, and the compiler should
- know how to delete it, but for now, we are stuck with it. */
- if (! for_reraise
- && TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node)
- expand_null_return ();
+ expand_end_bindings (getdecls (), 1, 0);
+ poplevel (1, 0, 0);
+ pop_momentary ();
+
+ finish_function (lineno, 0, 0);
}
-extern tree cplus_exception_name ();
-tree
-ansi_exception_object_lookup (type)
- tree type;
+void
+expand_start_eh_spec ()
{
- tree raise_id = cplus_exception_name (type);
- tree decl;
+ expand_eh_region_start ();
+}
- decl = IDENTIFIER_GLOBAL_VALUE (raise_id);
- if (decl == NULL_TREE || TREE_CODE (decl) != VAR_DECL)
+static void
+expand_end_eh_spec (raises)
+ tree raises;
+{
+ tree expr, second_try;
+ rtx check = gen_label_rtx ();
+ rtx cont;
+ rtx ret = gen_reg_rtx (Pmode);
+ rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
+ rtx end = gen_label_rtx ();
+
+ expr = make_node (RTL_EXPR);
+ TREE_TYPE (expr) = void_type_node;
+ RTL_EXPR_RTL (expr) = const0_rtx;
+ TREE_SIDE_EFFECTS (expr) = 1;
+ start_sequence_for_rtl_expr (expr);
+ cont = gen_label_rtx ();
+ emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
+ emit_jump (check);
+ emit_label (cont);
+ jumpif (make_tree (integer_type_node, flag), end);
+ do_function_call (Terminate, NULL_TREE, NULL_TREE);
+ assemble_external (TREE_OPERAND (Terminate, 0));
+ emit_barrier ();
+ RTL_EXPR_SEQUENCE (expr) = get_insns ();
+ end_sequence ();
+
+ second_try = expr;
+
+ expr = make_node (RTL_EXPR);
+ TREE_TYPE (expr) = void_type_node;
+ RTL_EXPR_RTL (expr) = const0_rtx;
+ TREE_SIDE_EFFECTS (expr) = 1;
+ start_sequence_for_rtl_expr (expr);
+
+ cont = gen_label_rtx ();
+ emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
+ emit_jump (check);
+ emit_label (cont);
+ jumpif (make_tree (integer_type_node, flag), end);
+ expand_eh_region_start ();
+ do_function_call (Unexpected, NULL_TREE, NULL_TREE);
+ assemble_external (TREE_OPERAND (Unexpected, 0));
+ emit_barrier ();
+ expand_eh_region_end (second_try);
+
+ emit_label (check);
+ emit_move_insn (flag, const1_rtx);
+ cont = gen_label_rtx ();
+ while (raises)
{
- push_obstacks_nochange ();
- end_temporary_allocation ();
- decl = build_decl (VAR_DECL, raise_id, ptr_type_node);
- TREE_PUBLIC (decl) = 1;
- TREE_STATIC (decl) = 1;
- pushdecl_top_level (decl);
- make_decl_rtl (decl, (char*)0, 1);
- pop_obstacks ();
+ tree exp;
+ tree match_type = TREE_VALUE (raises);
+
+ if (match_type)
+ {
+ /* check TREE_VALUE (raises) here */
+ exp = saved_throw_value;
+ exp = tree_cons (NULL_TREE,
+ build_eh_type_type (match_type),
+ tree_cons (NULL_TREE,
+ saved_throw_type,
+ tree_cons (NULL_TREE, exp, NULL_TREE)));
+ exp = build_function_call (CatchMatch, exp);
+ assemble_external (TREE_OPERAND (CatchMatch, 0));
+
+ jumpif (exp, cont);
+ }
+
+ raises = TREE_CHAIN (raises);
}
- return decl;
+ emit_move_insn (flag, const0_rtx);
+ emit_label (cont);
+ emit_indirect_jump (ret);
+ emit_label (end);
+
+ RTL_EXPR_SEQUENCE (expr) = get_insns ();
+ end_sequence ();
+
+ expand_eh_region_end (expr);
}
-/* Generate code to throw an exception using EXP.
- Usng ANSI syntax and semantics.
- If EXP is NULL_TREE< re-raise instead. */
+/* This is called to expand all the toplevel exception handling
+ finalization for a function. It should only be called once per
+ function. */
void
-cplus_expand_throw (exp)
- tree exp;
+expand_exception_blocks ()
{
- tree parms;
- int for_reraise;
- /* Allocate new exception of appropriate type, passing
- PARMS to its constructor. */
- tree decl = ansi_exception_object_lookup (TREE_TYPE (exp));
- tree xexp = exp;
-
- if (in_try_block (1))
+ rtx funcend;
+ rtx insn, insns;
+ rtx eh_spec_insns = NULL_RTX;
+
+ start_sequence ();
+
+ funcend = gen_label_rtx ();
+ emit_jump (funcend);
+ /* expand_null_return (); */
+
+ start_sequence ();
+
+ /* Add all the catch clauses here. */
+ emit_insns (catch_clauses);
+ catch_clauses = NULL_RTX;
+
+ expand_leftover_cleanups ();
+
+ insns = 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)))
{
#if 1
- my_friendly_abort (35);
-#else
- expand_raise (decl);
-#endif
- }
- else if (! current_function_decl)
- error ("invalid throw outside of functions");
- else
- {
-#if 0
- /* Test this raise against what this function permits. */
- tree names = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl));
- while (names)
- {
- if (decl == TREE_TYPE (names))
- break;
- names = TREE_CHAIN (names);
- }
- if (names == NULL_TREE)
- {
- error ("current function not declared to raise exception `%s'",
- IDENTIFIER_POINTER (name));
- return;
- }
+ {
+ rtx insns;
+ /* New... */
+ start_sequence ();
+ expand_start_eh_spec ();
+ eh_spec_insns = get_insns ();
+ end_sequence ();
+ }
#endif
- }
- store_expr (exp, EHS_parms_as_rtx, 0);
+ expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
+ push_to_sequence (insns);
- /* Set the global exception handler stack's NAME field
- to the `name' of this exception. The global exception
- handler stack is the container for the exception object
- we just built.
+ /* Now expand any new ones. */
+ expand_leftover_cleanups ();
- We go through a function call to make life easier when debugging. */
-#if 0
- expand_assignment (EHS_name, build_unary_op (ADDR_EXPR, decl, 0), 0, 0);
-#else
- parms = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, EHS_name, 0),
- build_tree_list (NULL_TREE,
- build_unary_op (ADDR_EXPR, decl, 0)));
- expand_expr (build_function_call (BIR, parms), 0, 0, 0);
-#endif
+ insns = get_insns ();
+ end_sequence ();
+ }
- /* Activate thrower. If we are inside a TRY statement,
- we can cheat and not do this, saving a longjmp. */
- if (in_try_block (1) == 0)
+ if (insns)
{
- sets_exception_throw_decl = 1;
- emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx);
- }
+ /* Is this necessary? */
+ assemble_external (TREE_OPERAND (Terminate, 0));
- if (xexp == NULL_TREE)
- {
- /* Invoke destructors for current procedure or handler. */
- if (! expand_escape_except ())
- compiler_error ("except nesting botch");
- /* Throw via `longjmp'... Done as side-effect of goto. */
+ expand_eh_region_start ();
+ emit_insns (insns);
+ expand_eh_region_end (TerminateFunctionCall);
+ expand_leftover_cleanups ();
}
- /* XXX: for_reraise is never set above here. */
- /* To avoid spurious warning messages, we add a goto to the end
- of the function. This code is dead, and the compiler should
- know how to delete it, but for now, we are stuck with it. */
- if (! for_reraise
- && TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node)
- expand_null_return ();
+ {
+ /* Mark the end of the stack unwinder. */
+ rtx unwind_insns;
+ start_sequence ();
+#if 0
+ end_eh_unwinder ();
+#endif
+ unwind_insns = get_insns ();
+ end_sequence ();
+ if (unwind_insns)
+ {
+ insns = unwind_insns;
+ emit_insns (insns);
+ }
+ }
+
+ emit_label (funcend);
+
+ /* Only if we had previous insns do we want to emit the jump around
+ them. If there weren't any, then insns will remain NULL_RTX. */
+ if (insns)
+ insns = get_insns ();
+ end_sequence ();
+
+#if 1
+ if (eh_spec_insns)
+ emit_insns_after (eh_spec_insns, get_insns ());
+#else
+ if (eh_spec_insns)
+ store_after_parms (eh_spec_insns);
+#endif
+
+ insn = get_last_insn ();
+ while (GET_CODE (insn) == NOTE
+ || (GET_CODE (insn) == INSN
+ && (GET_CODE (PATTERN (insn)) == USE
+ || GET_CODE (PATTERN (insn)) == CLOBBER)))
+ insn = PREV_INSN (insn);
+
+ emit_insns_after (insns, insn);
}
tree
-cplus_expand_start_catch (raise_id)
- tree raise_id;
+start_anon_func ()
{
- tree cname = lookup_exception_cname (current_class_type, current_class_name, raise_id);
- tree decl;
- tree cond;
+ static int counter = 0;
+ int old_interface_unknown = interface_unknown;
+ char name[32];
+ tree params;
+ tree t;
- if (cname == error_mark_node)
- {
- decl = error_mark_node;
- cond = error_mark_node;
- }
- else
- {
- decl = lookup_exception_object (cname, TREE_VALUE (raise_id), 1);
- if (decl == NULL_TREE)
- cond = error_mark_node;
- else
- cond = build_binary_op (EQ_EXPR, build_unary_op (ADDR_EXPR, decl, 0),
- build (COMPONENT_REF, ptr_type_node,
- current_exception_decl,
- TREE_OPERAND (EHS_name, 1)),
- 1);
- }
- expand_start_cond (cond, 0);
+ push_cp_function_context (NULL_TREE);
+ push_to_top_level ();
- /* Does nothing right now. */
- expand_catch (decl);
- if (current_exception_type
- && TYPE_NEEDS_DESTRUCTOR (current_exception_type))
- {
- /* Make a cleanup for the name-specific exception object now in scope. */
- tree cleanup = maybe_build_cleanup (current_exception_object);
- expand_start_bindings (0);
- expand_decl_cleanup (NULL_TREE, cleanup);
- }
- return decl;
-}
-tree
-ansi_expand_start_catch (raise_type)
- tree raise_type;
-{
- tree decl = ansi_exception_object_lookup (raise_type);
- tree cond;
+ /* No need to mangle this. */
+ push_lang_context (lang_name_c);
- if (decl == NULL_TREE)
- cond = error_mark_node;
- else
- cond = build_binary_op (EQ_EXPR, build_unary_op (ADDR_EXPR, decl, 0),
- build (COMPONENT_REF, ptr_type_node,
- current_exception_decl,
- TREE_OPERAND (EHS_name, 1)),
- 1);
- expand_start_cond (cond, 0);
-
- /* Does nothing right now. */
- expand_catch (decl);
- return decl;
+ interface_unknown = 1;
+
+ params = void_list_node;
+ /* tcf stands for throw clean funciton. */
+ 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
-cplus_expand_end_catch (for_reraise)
- int for_reraise;
+end_anon_func ()
{
- if (current_exception_type
- && TYPE_NEEDS_DESTRUCTOR (current_exception_type))
- {
- /* Destroy the specific exception object now in scope. */
- expand_end_bindings (getdecls (), 0, 1);
- }
- if (for_reraise)
- {
- if (! expand_escape_except ())
- my_friendly_abort (36);
- }
- else
- {
- if (! expand_end_catch ())
- my_friendly_abort (37);
- }
- expand_end_cond ();
+ 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);
}
-/* Reraise an exception.
- If EXCEPTIONS is NULL_TREE, it means reraise whatever exception was caught.
- If EXCEPTIONS is an IDENTIFIER_NODE, it means reraise the exception
- object named by EXCEPTIONS. This must be a variable declared in
- an `except' clause.
- If EXCEPTIONS is a TREE_LIST, it is the list of exceptions we are
- willing to reraise. */
+/* 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. */
void
-cplus_expand_reraise (exceptions)
- tree exceptions;
+expand_throw (exp)
+ tree exp;
{
- tree ex_ptr;
- tree ex_object = current_exception_object;
- rtx ex_ptr_as_rtx;
+ rtx label;
- if (exceptions && TREE_CODE (exceptions) == IDENTIFIER_NODE)
- {
- /* Don't get tripped up if its TREE_TYPE is `error_mark_node'. */
- ex_object = IDENTIFIER_LOCAL_VALUE (exceptions);
- if (ex_object == NULL_TREE || TREE_CODE (ex_object) != INDIRECT_REF)
- {
- error ("`%s' is not an exception decl", IDENTIFIER_POINTER (exceptions));
- return;
- }
- my_friendly_assert (TREE_CODE (TREE_OPERAND (ex_object, 0)) == VAR_DECL,
- 204);
- exceptions = NULL_TREE;
- }
-
- ex_ptr = build1 (NOP_EXPR, ptr_type_node, TREE_OPERAND (ex_object, 0));
- ex_ptr_as_rtx = expand_expr (ex_ptr, 0, 0, 0);
+ if (! doing_eh (1))
+ return;
- /* reraise ALL, used by compiler. */
- if (exceptions == NULL_TREE)
+ if (exp)
{
- /* Now treat reraise like catch/raise. */
- expand_catch (error_mark_node);
- expand_raise (error_mark_node);
- emit_move_insn (EHS_name_as_rtx, current_exception_name_as_rtx);
- store_expr ((tree) EHS_parms_as_rtx, current_exception_parms_as_rtx, 0);
- if (in_try_block (1) == 0)
- {
- sets_exception_throw_decl = 1;
- emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx);
- }
- /* Set to zero so that destructor will not be called. */
- emit_move_insn (ex_ptr_as_rtx, const0_rtx);
- if (! expand_escape_except ())
- my_friendly_abort (38);
-
- /* To avoid spurious warning messages, we add a goto to the end
- of the function. This code is dead, and the compiler should
- know how to delete it, but for now, we are stuck with it. */
- if (TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node)
- expand_null_return ();
-
- return;
- }
+ tree throw_type;
+ tree cleanup = empty_fndecl, e;
- /* reraise from a list of exceptions. */
- while (exceptions)
- {
- tree type = lookup_exception_type (current_class_type, current_class_name,
- exceptions);
- if (type == NULL_TREE)
+ /* throw expression */
+ /* First, decay it. */
+ exp = decay_conversion (exp);
+
+ if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
{
- error ("`%s' is not an exception type",
- IDENTIFIER_POINTER (TREE_VALUE (exceptions)));
- current_exception_type = NULL_TREE;
- TREE_TYPE (ex_object) = error_mark_node;
- TREE_TYPE (ex_ptr) = error_mark_node;
+ throw_type = build_eh_type (exp);
+ exp = build_reinterpret_cast (ptr_type_node, exp);
}
else
{
- current_exception_type = type;
- /* In-place union. */
- TREE_TYPE (ex_object) = type;
- TREE_TYPE (ex_ptr) = TYPE_POINTER_TO (type);
- }
-
- /* Now treat reraise like catch/raise. */
- cplus_expand_start_catch (exceptions);
- cplus_expand_raise (exceptions, NULL_TREE, ex_ptr, 1);
- /* Set to zero so that destructor will not be called. */
- if (TREE_TYPE (ex_ptr) != error_mark_node)
- emit_move_insn (ex_ptr_as_rtx, const0_rtx);
- cplus_expand_end_catch (1);
- exceptions = TREE_CHAIN (exceptions);
- }
- /* Don't propagate any unhandled exceptions. */
- expand_expr (call_to_unhandled_exception (), 0, VOIDmode, 0);
-
- /* To avoid spurious warning messages, we add a goto to the end
- of the function. This code is dead, and the compiler should
- know how to delete it, but for now, we are stuck with it. */
- if (TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node)
- expand_null_return ();
-}
-\f
-void
-setup_exception_throw_decl ()
-{
- tree call_to_longjmp, parms;
-
- int old = suspend_momentary ();
-
- exception_throw_decl = build_decl (VAR_DECL, get_identifier (THROW_NAME), integer_type_node);
- pushdecl (exception_throw_decl);
- parms = tree_cons (NULL_TREE, EHS_handler,
- build_tree_list (0, integer_one_node));
- call_to_longjmp = build_function_call (BILJ, parms);
-
- expand_decl (exception_throw_decl);
- expand_decl_cleanup (exception_throw_decl,
- build (COND_EXPR, void_type_node,
- exception_throw_decl,
- call_to_longjmp, integer_zero_node));
- DECL_INITIAL (exception_throw_decl) = integer_zero_node;
- sets_exception_throw_decl = 0;
- resume_momentary (old);
-
- /* Cache these, since they won't change throughout the function. */
- EHS_parms_as_rtx = expand_expr (EHS_parms, 0, 0, 0);
- EHS_name_as_rtx = expand_expr (EHS_name, 0, 0, 0);
-}
+ rtx cleanup_insns;
+ tree object;
+
+ /* Make a copy of the thrown object. WP 15.1.5 */
+ exp = build_new (NULL_TREE, TREE_TYPE (exp),
+ build_tree_list (NULL_TREE, exp),
+ 0);
+
+ if (exp == error_mark_node)
+ error (" in thrown expression");
+
+ object = build_indirect_ref (exp, NULL_PTR);
+ throw_type = build_eh_type (object);
+
+ start_sequence ();
+ object = build_reinterpret_cast (TREE_TYPE (exp), saved_throw_value);
+ object = build_indirect_ref (object, NULL_PTR);
+ cleanup = maybe_build_cleanup_and_delete (object);
+ if (cleanup)
+ expand_expr (cleanup, const0_rtx, VOIDmode, 0);
+ cleanup_insns = get_insns ();
+ end_sequence ();
+
+ if (cleanup && cleanup_insns)
+ {
+ cleanup = start_anon_func ();
-void
-init_exception_processing ()
-{
- extern tree build_function_type (), define_function ();
- extern tree unhandled_exception_fndecl;
- tree cname = get_identifier ("ExceptionHandler");
- tree field, chain;
- tree ctor, dtor;
- tree jmp_buf_type = build_array_type (integer_type_node,
- build_index_type (build_int_2 (_JBLEN-1, 0)));
- tree jmp_buf_arg_type = build_pointer_type (integer_type_node);
-
- tree parmtypes = hash_tree_chain (jmp_buf_arg_type, void_list_node);
- tree setjmp_fndecl, longjmp_fndecl, raise_fndecl;
-
- int old_interface_only = interface_only;
- int old_interface_unknown = interface_unknown;
- interface_only = 1;
- interface_unknown = 0;
- EHS_type = xref_tag (record_type_node, cname, NULL_TREE, 0);
- push_lang_context (lang_name_c);
- setjmp_fndecl = define_function ("setjmp",
- build_function_type (integer_type_node,
- parmtypes),
- NOT_BUILT_IN, pushdecl, 0);
- BISJ = default_conversion (setjmp_fndecl);
- parmtypes = hash_tree_chain (jmp_buf_arg_type,
- hash_tree_chain (integer_type_node, void_list_node));
- longjmp_fndecl = define_function ("longjmp",
- build_function_type (void_type_node, parmtypes),
- NOT_BUILT_IN, pushdecl, 0);
- raise_fndecl = define_function ("__raise_exception",
- build_function_type (void_type_node,
- hash_tree_chain (ptr_type_node,
- hash_tree_chain (build_pointer_type (ptr_type_node), void_list_node))),
- NOT_BUILT_IN, pushdecl, 0);
- BILJ = default_conversion (longjmp_fndecl);
- BIR = default_conversion (raise_fndecl);
- BIUE = default_conversion (unhandled_exception_fndecl);
+ expand_expr (maybe_build_cleanup_and_delete (object),
+ const0_rtx, VOIDmode, 0);
- pop_lang_context ();
+ end_anon_func ();
- /* finish_struct will pop this. */
- pushclass (EHS_type, 0);
- field = build_lang_field_decl (FIELD_DECL, get_identifier ("parms"), ptr_type_node);
- chain = field;
- field = build_lang_field_decl (FIELD_DECL, get_identifier ("name"),
- build_pointer_type (default_function_type));
- TREE_CHAIN (field) = chain;
- chain = field;
- field = build_lang_field_decl (FIELD_DECL, get_identifier ("handler"), jmp_buf_type);
- TREE_CHAIN (field) = chain;
- chain = field;
- field = build_lang_field_decl (FIELD_DECL, get_identifier ("prev"),
- TYPE_POINTER_TO (EHS_type));
- TREE_CHAIN (field) = chain;
- chain = field;
-
- ctor = build_lang_decl (FUNCTION_DECL, cname,
- build_cplus_method_type (EHS_type, TYPE_POINTER_TO (EHS_type), void_list_node));
- DECL_CONSTRUCTOR_P (ctor) = 1;
- TREE_STATIC (ctor) = 1;
- TREE_PUBLIC (ctor) = 1;
- DECL_EXTERNAL (ctor) = 1;
- grokclassfn (EHS_type, cname, ctor, NO_SPECIAL, 0);
- grok_ctor_properties (EHS_type, ctor);
- finish_decl (pushdecl (ctor), NULL_TREE, NULL_TREE, 0);
- /* Must copy the node here because the FUNCTION_DECL
- used inside the struct ain't the same as the
- FUNCTION_DECL we stick into the global binding
- contour. */
- ctor = copy_node (ctor);
- TREE_CHAIN (ctor) = chain;
- chain = ctor;
- dtor = build_lang_decl (FUNCTION_DECL, cname,
- build_cplus_method_type (EHS_type, TYPE_POINTER_TO (EHS_type), void_list_node));
- TREE_STATIC (dtor) = 1;
- TREE_PUBLIC (dtor) = 1;
- DECL_EXTERNAL (dtor) = 1;
- grokclassfn (EHS_type, cname, dtor, DTOR_FLAG, 0);
- finish_decl (pushdecl (dtor), NULL_TREE, NULL_TREE, 0);
- /* Copy for the same reason as copying ctor. */
- dtor = copy_node (dtor);
- TREE_CHAIN (dtor) = chain;
- chain = dtor;
- TYPE_HAS_CONSTRUCTOR (EHS_type) = 1;
- TYPE_HAS_DESTRUCTOR (EHS_type) = 1;
- finish_struct (EHS_type, temp_tree_cons (NULL_TREE, chain, NULL_TREE), 0);
- interface_only = old_interface_only;
- interface_unknown = old_interface_unknown;
-}
+ mark_addressable (cleanup);
+ }
+ else
+ {
+ cleanup = empty_fndecl;
+ }
+ }
-void
-init_exception_processing_1 ()
-{
- register tree EHS_id = get_identifier ("exceptionHandlerStack");
+ if (cleanup == empty_fndecl)
+ assemble_external (empty_fndecl);
+
+ e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type);
+ expand_expr (e, const0_rtx, VOIDmode, 0);
- EHS_decl = IDENTIFIER_GLOBAL_VALUE (EHS_id);
+ e = build_modify_expr (saved_throw_value, NOP_EXPR, exp);
+ e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e);
+ expand_expr (e, const0_rtx, VOIDmode, 0);
- /* If we have no other definition, default to library implementation. */
- if (EHS_decl == NULL_TREE)
+ cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
+ cleanup = build_modify_expr (saved_cleanup, NOP_EXPR, cleanup);
+ expand_expr (cleanup, const0_rtx, VOIDmode, 0);
+ }
+ else
{
- EHS_decl = build_decl (VAR_DECL, EHS_id, TYPE_POINTER_TO (EHS_type));
- /* If we don't push this, its definition, should it be encountered,
- will not be seen. */
- EHS_decl = pushdecl (EHS_decl);
- DECL_EXTERNAL (EHS_decl) = 1;
- TREE_STATIC (EHS_decl) = 1;
- TREE_PUBLIC (EHS_decl) = 1;
- finish_decl (EHS_decl, NULL_TREE, NULL_TREE, 0);
+ /* rethrow current exception */
+ /* This part is easy, as we don't have to do anything else. */
}
- else if (TREE_CODE (EHS_decl) != VAR_DECL
- || TREE_TYPE (EHS_decl) != TYPE_POINTER_TO (EHS_type))
- fatal ("exception handling declarations conflict with compiler's internal model");
- if (EHS_prev == NULL_TREE)
+ /* This is the label that represents where in the code we were, when
+ we got an exception. This needs to be updated when we rethrow an
+ exception, so that the matching routine knows to search out. */
+ label = gen_label_rtx ();
+ emit_label (label);
+
+ expand_internal_throw (label);
+}
+
+/* Build a throw expression. */
+
+tree
+build_throw (e)
+ tree e;
+{
+ if (e != error_mark_node)
{
- register tree EHS_DECL = build1 (INDIRECT_REF, EHS_type, EHS_decl);
- EHS_prev = build_component_ref (EHS_DECL, get_identifier ("prev"), 0, 0);
- EHS_handler = build_component_ref (EHS_DECL, get_identifier ("handler"), 0, 0);
- EHS_parms = build_component_ref (EHS_DECL, get_identifier ("parms"), 0, 0);
- EHS_name = build_component_ref (EHS_DECL, get_identifier ("name"), 0, 0);
+ if (processing_template_decl)
+ return build_min (THROW_EXPR, void_type_node, e);
+ e = build1 (THROW_EXPR, void_type_node, e);
+ TREE_SIDE_EFFECTS (e) = 1;
+ TREE_USED (e) = 1;
}
+ return e;
}