summaryrefslogtreecommitdiffstats
path: root/contrib/gcc
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>1999-08-30 09:54:31 +0000
committerobrien <obrien@FreeBSD.org>1999-08-30 09:54:31 +0000
commit903d244211fbbcc99b0aacb7009d0f967bc623d9 (patch)
treee569bde071309f51fc658d32c4595b740c42b172 /contrib/gcc
parent54f868e9623a1386664ce8976a78dd31d90502e6 (diff)
downloadFreeBSD-src-903d244211fbbcc99b0aacb7009d0f967bc623d9.zip
FreeBSD-src-903d244211fbbcc99b0aacb7009d0f967bc623d9.tar.gz
Use the stock EGCS 1.1.2 file here. Our previous changes are OBE.
Diffstat (limited to 'contrib/gcc')
-rw-r--r--contrib/gcc/cp/except.c2137
1 files changed, 864 insertions, 1273 deletions
diff --git a/contrib/gcc/cp/except.c b/contrib/gcc/cp/except.c
index 40894cb..d294497 100644
--- a/contrib/gcc/cp/except.c
+++ b/contrib/gcc/cp/except.c
@@ -1,5 +1,5 @@
/* Handle exceptional things in C++.
- Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1989, 92-97, 1998 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.
@@ -22,91 +22,48 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-/* High-level class interface. */
-
#include "config.h"
+#include "system.h"
#include "tree.h"
#include "rtl.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"
-tree protect_list;
-
-extern void (*interim_eh_hook) PROTO((tree));
rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
-/* holds the fndecl for __builtin_return_address () */
+/* Holds the fndecl for __builtin_return_address. */
tree builtin_return_address_fndecl;
-tree throw_fndecl;
-
-static int
-doing_eh (do_warn)
- int do_warn;
-{
- if (! flag_handle_exceptions)
- {
- static int warned = 0;
- if (! warned && do_warn)
- {
- error ("exception handling disabled, use -fhandle-exceptions to enable.");
- warned = 1;
- }
- return 0;
- }
- return 1;
-}
-
-
-/*
-NO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer
-to supporting exception handling as per ANSI C++ working draft.
-It is a complete rewrite of all the EH stuff that was here before
- Shortcomings:
- 1. Throw specifications of functions still don't work.
- Cool Things:
- 1. Destructors are called properly :-)
- 2. No overhead for the non-exception thrown case.
- 3. Fixing shortcoming 1 is simple.
- -Tad Hunt (tad@mail.csh.rit.edu)
-
-*/
/* A couple of backend routines from m88k.c */
-/* used to cache a call to __builtin_return_address () */
-static tree BuiltinReturnAddress;
-
-
-#include <stdio.h>
-
-/* XXX - Tad: for EH */
-/* output an exception table entry */
-
-static void
-output_exception_table_entry (file, start_label, end_label, eh_label)
- FILE *file;
- rtx start_label, end_label, eh_label;
-{
- char label[100];
-
- assemble_integer (start_label, GET_MODE_SIZE (Pmode), 1);
- assemble_integer (end_label, GET_MODE_SIZE (Pmode), 1);
- assemble_integer (eh_label, GET_MODE_SIZE (Pmode), 1);
- putc ('\n', file); /* blank line */
-}
-
-static void
-easy_expand_asm (str)
- char *str;
-{
- expand_asm (build_string (strlen (str)+1, str));
-}
-
+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));
+static tree get_eh_type PROTO((void));
+static tree get_eh_caught PROTO((void));
+static tree get_eh_handlers PROTO((void));
+static tree do_pop_exception PROTO((void));
+static void process_start_catch_block PROTO((tree, tree));
+static void process_start_catch_block_old 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. */
+/* This is the startup, and finish stuff per exception table. */
/* XXX - Tad: exception handling section */
#ifndef EXCEPT_SECTION_ASM_OP
@@ -114,14 +71,6 @@ easy_expand_asm (str)
#endif
#ifdef EXCEPT_SECTION_ASM_OP
-typedef struct {
- void *start_protect;
- void *end_protect;
- void *exception_handler;
- } exception_table;
-#endif /* EXCEPT_SECTION_ASM_OP */
-
-#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
@@ -145,49 +94,9 @@ asm (TEXT_SECTION_ASM_OP);
#endif
-void
-exception_section ()
-{
-#ifdef EXCEPTION_SECTION_FUNCTION
- EXCEPTION_SECTION_FUNCTION;
-#else
-#ifdef ASM_OUTPUT_SECTION_NAME
- named_section (NULL_TREE, ".gcc_except_table");
-#else
- if (flag_pic)
- data_section ();
- else
-#if defined(TARGET_POWERPC) /* are we on a __rs6000? */
- data_section ();
-#else
- readonly_data_section ();
-#endif
-#endif
-#endif
-}
-
-
-
-
-/* from: my-cp-except.c */
-
-/* VI: ":set ts=4" */
-#if 0
-#include <stdio.h> */
-#include "config.h"
-#include "tree.h"
-#include "rtl.h"
-#include "cp-tree.h"
-#endif
#include "decl.h"
-#if 0
-#include "flags.h"
-#endif
#include "insn-flags.h"
#include "obstack.h"
-#if 0
-#include "expr.h"
-#endif
/* ======================================================================
Briefly the algorithm works like this:
@@ -198,15 +107,15 @@ exception_section ()
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 ehEntry it
- created when push_eh_entry () was called. The ehEntry structure
+ (&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 ehEntry structure. Otherwise
+ 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 ehEntry node
+ 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).
@@ -235,12 +144,12 @@ exception_section ()
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 ehQueue until we get to an entry with a NULL
+ 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 ehEntry to be output at an outer level.
+ 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
@@ -248,66 +157,21 @@ exception_section ()
===================================================================== */
-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, Throw;
+/* Used to cache "terminate" and "__throw_type_match*". */
+static tree Terminate, CatchMatch;
-/* used to cache __find_first_exception_table_match ()
- for throw (lib-except.c) */
+/* Used to cache __find_first_exception_table_match for throw. */
static tree FirstExceptionMatch;
-/* used to cache a call to __unwind_function () (lib-except.c) */
+/* Used to cache a call to __unwind_function. */
static tree Unwind;
-/* holds a ready to emit call to "terminate ()". */
-static tree TerminateFunctionCall;
-
/* ====================================================================== */
-
-/* data structures for my various quick and dirty stacks and queues
- Eventually, most of this should go away, because I think it can be
- integrated with stuff already built into the compiler. */
-
-/* =================================================================== */
-
-struct labelNode {
- rtx label;
- struct labelNode *chain;
-};
-
-
-/* this is the most important structure here. Basically this is how I store
- an exception table entry internally. */
-struct ehEntry {
- rtx start_label;
- rtx end_label;
- rtx exception_handler_label;
-
- tree finalization;
- tree context;
-};
-
-struct ehNode {
- struct ehEntry *entry;
- struct ehNode *chain;
-};
-
-struct ehStack {
- struct ehNode *top;
-};
-
-struct ehQueue {
- struct ehNode *head;
- struct ehNode *tail;
-};
/* ========================================================================= */
@@ -317,538 +181,247 @@ struct ehQueue {
========================================================================= */
-/* Holds the pc for doing "throw" */
-tree saved_pc;
-/* Holds the type of the thing being thrown. */
-tree saved_throw_type;
-/* Holds the value being thrown. */
-tree saved_throw_value;
-
-int throw_used;
-
-static rtx catch_clauses;
-static first_catch_label;
+extern rtx catch_clauses;
+extern tree const_ptr_type_node;
-static struct ehStack ehstack;
-static struct ehQueue ehqueue;
-static struct ehQueue eh_table_output_queue;
-static struct labelNode *false_label_stack = NULL;
-static struct labelNode *caught_return_label_stack = NULL;
/* ========================================================================= */
-/* function prototypes */
-static struct ehEntry *pop_eh_entry PROTO((struct ehStack *stack));
-static void enqueue_eh_entry PROTO((struct ehQueue *queue, struct ehEntry *entry));
-static rtx push_eh_entry PROTO((struct ehStack *stack));
-static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue));
-static void new_eh_queue PROTO((struct ehQueue *queue));
-static void new_eh_stack PROTO((struct ehStack *stack));
-static void push_label_entry PROTO((struct labelNode **labelstack, rtx label));
-static rtx pop_label_entry PROTO((struct labelNode **labelstack));
-static rtx top_label_entry PROTO((struct labelNode **labelstack));
-static struct ehEntry *copy_eh_entry PROTO((struct ehEntry *entry));
-
-
-
-/* All my cheesy stack/queue/misc data structure handling routines
-
- ========================================================================= */
-
-static void
-push_label_entry (labelstack, label)
- struct labelNode **labelstack;
- rtx label;
-{
- struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode));
-
- newnode->label = label;
- newnode->chain = *labelstack;
- *labelstack = newnode;
-}
-
-static rtx
-pop_label_entry (labelstack)
- struct labelNode **labelstack;
-{
- rtx label;
- struct labelNode *tempnode;
-
- if (! *labelstack) return NULL_RTX;
-
- tempnode = *labelstack;
- label = tempnode->label;
- *labelstack = (*labelstack)->chain;
- free (tempnode);
-
- return label;
-}
-
-static rtx
-top_label_entry (labelstack)
- struct labelNode **labelstack;
-{
- if (! *labelstack) return NULL_RTX;
+/* sets up all the global eh stuff that needs to be initialized at the
+ start of compilation.
- return (*labelstack)->label;
-}
+ This includes:
+ - Setting up all the function call trees. */
-/* Push to permanent obstack for rtl generation.
- One level only! */
-static struct obstack *saved_rtl_obstack;
void
-push_rtl_perm ()
-{
- extern struct obstack permanent_obstack;
- extern struct obstack *rtl_obstack;
-
- saved_rtl_obstack = rtl_obstack;
- rtl_obstack = &permanent_obstack;
-}
-
-/* Pop back to normal rtl handling. */
-static void
-pop_rtl_from_perm ()
+init_exception_processing ()
{
- extern struct obstack permanent_obstack;
- extern struct obstack *rtl_obstack;
+ /* void vtype () */
+ tree vtype = build_function_type (void_type_node, void_list_node);
- rtl_obstack = saved_rtl_obstack;
-}
-
-static rtx
-push_eh_entry (stack)
- struct ehStack *stack;
-{
- struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
- struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
-
- if (stack == NULL) {
- free (node);
- free (entry);
- return NULL_RTX;
- }
-
- /* These are saved for the exception table. */
- push_rtl_perm ();
- entry->start_label = gen_label_rtx ();
- entry->end_label = gen_label_rtx ();
- entry->exception_handler_label = gen_label_rtx ();
- pop_rtl_from_perm ();
-
- LABEL_PRESERVE_P (entry->start_label) = 1;
- LABEL_PRESERVE_P (entry->end_label) = 1;
- LABEL_PRESERVE_P (entry->exception_handler_label) = 1;
-
- entry->finalization = NULL_TREE;
- entry->context = current_function_decl;
-
- node->entry = entry;
- node->chain = stack->top;
- stack->top = node;
-
- enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
+ 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 ();
- return entry->start_label;
-}
-
-static struct ehEntry *
-pop_eh_entry (stack)
- struct ehStack *stack;
-{
- struct ehNode *tempnode;
- struct ehEntry *tempentry;
+ push_lang_context (lang_name_c);
- if (stack && (tempnode = stack->top)) {
- tempentry = tempnode->entry;
- stack->top = stack->top->chain;
- free (tempnode);
+ 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);
- return tempentry;
- }
+ pop_lang_context ();
- return NULL;
+ /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
+ be protected with __terminate. */
+ protect_cleanup_actions_with_terminate = 1;
}
-static struct ehEntry *
-copy_eh_entry (entry)
- struct ehEntry *entry;
-{
- struct ehEntry *newentry;
-
- newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
- memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry));
-
- return newentry;
-}
+/* Retrieve a pointer to the cp_eh_info node for the current exception. */
-static void
-enqueue_eh_entry (queue, entry)
- struct ehQueue *queue;
- struct ehEntry *entry;
+static tree
+call_eh_info ()
{
- struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
-
- node->entry = entry;
- node->chain = NULL;
+ tree fn;
- if (queue->head == NULL)
- {
- queue->head = node;
- }
+ fn = get_identifier ("__cp_eh_info");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
- queue->tail->chain = node;
+ tree t1, t, fields[7];
+
+ /* Declare cp_eh_info * __cp_eh_info (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);
+ /* 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, 2, 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);
+ assemble_external (fn);
+ pop_obstacks ();
}
- queue->tail = node;
+ return build_function_call (fn, NULL_TREE);
}
-static struct ehEntry *
-dequeue_eh_entry (queue)
- struct ehQueue *queue;
-{
- struct ehNode *tempnode;
- struct ehEntry *tempentry;
-
- if (queue->head == NULL)
- return NULL;
-
- tempnode = queue->head;
- queue->head = queue->head->chain;
-
- tempentry = tempnode->entry;
- free (tempnode);
-
- return tempentry;
-}
+/* Retrieve a pointer to the cp_eh_info node for the current exception
+ and save it in the current binding level. */
static void
-new_eh_queue (queue)
- struct ehQueue *queue;
+push_eh_info ()
{
- queue->head = queue->tail = NULL;
+ 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);
}
-static void
-new_eh_stack (stack)
- struct ehStack *stack;
-{
- stack->top = NULL;
-}
+/* Returns a reference to the cp_eh_info node for the current exception. */
-/* cheesyness to save some typing. returns the return value rtx */
-rtx
-do_function_call (func, params, return_type)
- tree func, params, return_type;
-{
- 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;
-}
-
-static void
-expand_internal_throw (pc)
- rtx pc;
+static tree
+get_eh_info ()
{
- tree params;
-
- emit_move_insn (DECL_RTL (saved_pc), pc);
-#ifdef JUMP_TO_THROW
- emit_indirect_jump (gen_rtx (SYMBOL_REF, Pmode, "__throw"));
-#else
- do_function_call (Throw, NULL_TREE, NULL_TREE);
-#endif
- throw_used = 1;
+ /* Look for the pointer pushed in push_eh_info. */
+ tree t = lookup_name (get_identifier ("__exception_info"), 0);
+ return build_indirect_ref (t, NULL_PTR);
}
-/* ========================================================================= */
+/* Returns a reference to the current exception object. */
-void
-lang_interim_eh (finalization)
- tree finalization;
+static tree
+get_eh_value ()
{
- if (finalization)
- end_protect (finalization);
- else
- start_protect ();
+ return build_component_ref (get_eh_info (), get_identifier ("value"),
+ NULL_TREE, 0);
}
-extern tree auto_function PROTO((tree, tree, enum built_in_function));
+/* Returns a reference to the current exception type. */
-/* 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
- - Initializing the ehqueue
- - Initializing the eh_table_output_queue
- - Initializing the ehstack
-*/
-
-void
-init_exception_processing ()
+static tree
+get_eh_type ()
{
- 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);
-
- interim_eh_hook = lang_interim_eh;
-
- push_lang_context (lang_name_c);
-
- catch_match_fndecl =
- define_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,
- pushdecl,
- 0);
- find_first_exception_match_fndecl =
- define_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,
- pushdecl,
- 0);
- unwind_fndecl =
- define_function ("__unwind_function",
- build_function_type (void_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- void_list_node)),
- NOT_BUILT_IN,
- pushdecl,
- 0);
- throw_fndecl =
- define_function ("__throw",
- build_function_type (void_type_node, void_list_node),
- NOT_BUILT_IN,
- pushdecl,
- 0);
- DECL_EXTERNAL (throw_fndecl) = 0;
- TREE_PUBLIC (throw_fndecl) = 0;
-
- 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);
- Throw = default_conversion (throw_fndecl);
- BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
-
- TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
-
- pop_lang_context ();
-
- new_eh_queue (&ehqueue);
- new_eh_queue (&eh_table_output_queue);
- new_eh_stack (&ehstack);
-
- 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, NULL_TREE);
- DECL_COMMON (d) = 1;
- cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 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, NULL_TREE);
- DECL_COMMON (d) = 1;
- cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 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, NULL_TREE);
- DECL_COMMON (d) = 1;
- cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
- saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0);
+ return build_component_ref (get_eh_info (), get_identifier ("type"),
+ NULL_TREE, 0);
}
-/* call this to begin a block of unwind protection (ie: when an object is
- constructed) */
-void
-start_protect ()
-{
- if (! doing_eh (0))
- return;
+/* Returns a reference to whether or not the current exception
+ has been caught. */
- emit_label (push_eh_entry (&ehstack));
-}
-
-/* call this to end a block of unwind protection. the finalization tree is
- the finalization which needs to be run in order to cleanly unwind through
- this level of protection. (ie: call this when a scope is exited)*/
-void
-end_protect (finalization)
- tree finalization;
+static tree
+get_eh_caught ()
{
- struct ehEntry *entry;
-
- if (! doing_eh (0))
- return;
-
- entry = pop_eh_entry (&ehstack);
-
- emit_label (entry->end_label);
- /* Put in something that takes up space, as otherwise the end
- address for the EH region could have the exact same address as
- the outer region, causing us to miss the fact that resuming
- exception handling with this PC value would be inside the outer
- region. */
- emit_insn (gen_nop ());
-
- entry->finalization = finalization;
-
- enqueue_eh_entry (&ehqueue, entry);
+ return build_component_ref (get_eh_info (), get_identifier ("caught"),
+ NULL_TREE, 0);
}
-/* call this on start of a try block. */
-void
-expand_start_try_stmts ()
-{
- if (! doing_eh (1))
- return;
+/* Returns a reference to whether or not the current exception
+ has been caught. */
- start_protect ();
-}
-
-void
-expand_end_try_stmts ()
+static tree
+get_eh_handlers ()
{
- end_protect (integer_zero_node);
+ return build_component_ref (get_eh_info (), get_identifier ("handlers"),
+ NULL_TREE, 0);
}
+/* Build a type value for use at runtime for a type that is matched
+ against by the exception handling system. */
-/* call this to start processing of all the catch blocks. */
-void
-expand_start_all_catch ()
+static tree
+build_eh_type_type (type)
+ tree type;
{
- struct ehEntry *entry;
- rtx label;
-
- if (! doing_eh (1))
- return;
-
- emit_line_note (input_filename, lineno);
- label = gen_label_rtx ();
+ char *typestring;
+ tree exp;
- /* The label for the exception handling block we will save. This is
- Lresume, in the documention. */
- emit_label (label);
-
- /* Put in something that takes up space, as otherwise the end
- address for the EH region could have the exact same address as
- the outer region, causing us to miss the fact that resuming
- exception handling with this PC value would be inside the outer
- region. */
- emit_insn (gen_nop ());
+ if (type == error_mark_node)
+ return error_mark_node;
- push_label_entry (&caught_return_label_stack, label);
+ /* peel back references, so they match. */
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
- /* Start a new sequence for all the catch blocks. We will add this
- to the gloabl sequence catch_clauses, when we have completed all
- the handlers in this handler-seq. */
- start_sequence ();
+ /* Peel off cv qualifiers. */
+ type = TYPE_MAIN_VARIANT (type);
- while (1)
+ if (flag_rtti)
{
- entry = dequeue_eh_entry (&ehqueue);
- emit_label (entry->exception_handler_label);
-
- expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
-
- /* When we get down to the matching entry, stop. */
- if (entry->finalization == integer_zero_node)
- break;
-
- /* The below can be optimized away, and we could just fall into the
- next EH handler, if we are certain they are nested. */
- /* Code to throw out to outer context, if we fall off end of the
- handler. */
- expand_internal_throw (gen_rtx (LABEL_REF,
- Pmode,
- entry->end_label));
- free (entry);
+ return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
}
-}
-/* call this to end processing of all the catch blocks. */
-void
-expand_end_all_catch ()
-{
- rtx new_catch_clause;
-
- if (! doing_eh (1))
- return;
-
- /* Code to throw out to outer context, if we fall off end of catch
- handlers. This is rethrow (Lresume, same id, same obj); in the
- documentation. */
- expand_internal_throw (gen_rtx (LABEL_REF,
- Pmode,
- top_label_entry (&caught_return_label_stack)));
-
- /* Now we have the complete catch sequence. */
- new_catch_clause = get_insns ();
- end_sequence ();
-
- /* this level of catch blocks is done, so set up the successful catch jump
- label for the next layer of catch blocks. */
- pop_label_entry (&caught_return_label_stack);
-
- /* Add the new sequence of catchs to the main one for this
- function. */
- push_to_sequence (catch_clauses);
- emit_insns (new_catch_clause);
- catch_clauses = get_insns ();
- end_sequence ();
-
- /* Here we fall through into the continuation code. */
+ typestring = build_overload_name (type, 1, 1);
+ exp = combine_strings (build_string (strlen (typestring)+1, typestring));
+ return build1 (ADDR_EXPR, ptr_type_node, exp);
}
-/* Build a type value for use at runtime for a type that is matched
- against by the exception handling system. */
+/* Build the address of a runtime type for use in the runtime matching
+ field of the new exception model */
+
static tree
-build_eh_type_type (type)
+build_eh_type_type_ref (type)
tree type;
{
char *typestring;
@@ -857,25 +430,37 @@ build_eh_type_type (type)
if (type == error_mark_node)
return error_mark_node;
- /* peel back references, so they match. */
+ /* peel back references, so they match. */
if (TREE_CODE (type) == REFERENCE_TYPE)
type = TREE_TYPE (type);
- /* Peel off cv qualifiers. */
+ /* Peel off cv qualifiers. */
type = TYPE_MAIN_VARIANT (type);
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
if (flag_rtti)
{
- return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
+ exp = get_tinfo_fn (type);
+ TREE_USED (exp) = 1;
+ mark_inline_for_output (exp);
+ exp = build1 (ADDR_EXPR, ptr_type_node, exp);
}
-
- typestring = build_overload_name (type, 1, 1);
- exp = combine_strings (build_string (strlen (typestring)+1, typestring));
- return 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);
}
+
/* 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;
@@ -888,64 +473,200 @@ build_eh_type (exp)
return build_eh_type_type (TREE_TYPE (exp));
}
-/* call this to start a catch block. Typename is the typename, and identifier
+/* 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 ()
+{
+ 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);
+}
+
+/* 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. */
+
+static tree
+do_pop_exception ()
+{
+ tree fn, cleanup;
+ fn = get_identifier ("__cp_pop_exception");
+ 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);
+ assemble_external (fn);
+ pop_obstacks ();
+ }
+
+ /* 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));
+ return cleanup;
+}
+
+/* This routine creates the cleanup for the current exception. */
+
+static void
+push_eh_cleanup ()
+{
+ int yes;
+
+ expand_expr (build_unary_op (PREINCREMENT_EXPR, get_eh_handlers (), 1),
+ const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ yes = suspend_momentary ();
+ /* All cleanups must last longer than normal. */
+ expand_decl_cleanup (NULL_TREE, do_pop_exception ());
+ resume_momentary (yes);
+}
+
+/* Build up a call to terminate on the function obstack, for use as an
+ exception handler. */
+
+static tree
+build_terminate_handler ()
+{
+ int yes = suspend_momentary ();
+ tree term = build_function_call (Terminate, NULL_TREE);
+ resume_momentary (yes);
+ return term;
+}
+
+/* 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
expand_start_catch_block (declspecs, declarator)
tree declspecs, declarator;
{
- rtx false_label_rtx;
- rtx protect_label_rtx;
- tree decl = NULL_TREE;
- tree init;
+ tree decl;
+
+ if (processing_template_decl)
+ {
+ 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);
+ }
+ return;
+ }
if (! doing_eh (1))
return;
- /* Create a binding level for the parm. */
+ if (flag_new_exceptions)
+ process_start_catch_block (declspecs, declarator);
+ else
+ process_start_catch_block_old (declspecs, declarator);
+}
+
+
+/* This function performs the expand_start_catch_block functionality for
+ exceptions implemented in the old style, where catch blocks were all
+ called, and had to check the runtime information themselves. */
+
+static void
+process_start_catch_block_old (declspecs, declarator)
+ tree declspecs, declarator;
+{
+ rtx false_label_rtx;
+ tree decl = NULL_TREE;
+ tree init;
+
+ /* Create a binding level for the eh_info and the exception object
+ cleanup. */
+ pushlevel (0);
expand_start_bindings (0);
false_label_rtx = gen_label_rtx ();
- /* This is saved for the exception table. */
- push_rtl_perm ();
- protect_label_rtx = gen_label_rtx ();
- pop_rtl_from_perm ();
- push_label_entry (&false_label_stack, false_label_rtx);
- push_label_entry (&false_label_stack, protect_label_rtx);
+ push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
+
+ emit_line_note (input_filename, lineno);
+
+ push_eh_info ();
if (declspecs)
{
+ decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
+
+ if (decl == NULL_TREE)
+ error ("invalid catch parameter");
+ }
+
+ if (decl)
+ {
tree exp;
rtx call_rtx, return_value_rtx;
tree init_type;
- decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1,
- NULL_TREE, NULL_TREE);
-
- if (decl == NULL_TREE)
- {
- error ("invalid catch parameter");
- return;
- }
+ /* Make sure we mark the catch param as used, otherwise we'll get
+ a warning about an unused ((anonymous)). */
+ TREE_USED (decl) = 1;
- /* Figure out the type that the initializer is. */
+ /* Figure out the type that the initializer is. */
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);
- exp = saved_throw_value;
- exp = tree_cons (NULL_TREE,
+ exp = get_eh_value ();
+
+ /* 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);
+
+ exp = expr_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)));
+ expr_tree_cons (NULL_TREE,
+ get_eh_type (),
+ expr_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));
return_value_rtx = hard_function_value (ptr_type_node, exp);
@@ -956,543 +677,405 @@ expand_start_catch_block (declspecs, declarator)
/* if it returned FALSE, jump over the catch block, else fall into it */
emit_jump_insn (gen_beq (false_label_rtx));
- init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
+ push_eh_cleanup ();
+
+ /* Create a binding level for the parm. */
+ pushlevel (0);
+ expand_start_bindings (0);
+
+ init = convert_from_reference (make_tree (init_type, call_rtx));
+
+ /* 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)))
+ {
+ /* 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 ());
+ }
- /* 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);
+
+ start_decl_1 (decl);
+ cp_finish_decl (decl, DECL_INITIAL (decl),
+ NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
}
else
{
- /* Fall into the catch all section. */
+ push_eh_cleanup ();
+
+ /* Create a binding level for the parm. */
+ pushlevel (0);
+ expand_start_bindings (0);
+
+ /* Fall into the catch all section. */
}
- /* This is the starting of something to protect. */
- emit_label (protect_label_rtx);
+ init = build_modify_expr (get_eh_caught (), NOP_EXPR, integer_one_node);
+ expand_expr (init, const0_rtx, VOIDmode, EXPAND_NORMAL);
emit_line_note (input_filename, lineno);
}
+/* 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 additionaal. */
-/* this is called from expand_exception_blocks and
- expand_end_catch_block to expand the toplevel finalizations for a
- function. We return the first label emitted, if any, otherwise
- return NULL_RTX. */
-static rtx
-expand_leftover_cleanups ()
+static void
+process_start_catch_block (declspecs, declarator)
+ tree declspecs, declarator;
{
- struct ehEntry *entry;
- rtx first_label = NULL_RTX;
+ tree decl = NULL_TREE;
+ tree init;
+
+ /* Create a binding level for the eh_info and the exception object
+ cleanup. */
+ pushlevel (0);
+ expand_start_bindings (0);
+
- while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
+ if (declspecs)
+ {
+ decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
+
+ if (decl == NULL_TREE)
+ error ("invalid catch parameter");
+ }
+
+ if (decl)
+ start_catch_handler (build_eh_type_type_ref (TREE_TYPE (decl)));
+ else
+ start_catch_handler (CATCH_ALL_TYPE);
+
+ emit_line_note (input_filename, lineno);
+
+ push_eh_info ();
+
+ if (decl)
{
- if (! first_label)
- first_label = entry->exception_handler_label;
- emit_label (entry->exception_handler_label);
+ tree exp;
+ tree init_type;
+
+ /* Make sure we mark the catch param as used, otherwise we'll get
+ a warning about an unused ((anonymous)). */
+ TREE_USED (decl) = 1;
- expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
+ /* 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);
- /* The below can be optimized away, and we could just fall into the
- next EH handler, if we are certain they are nested. */
- /* Code to throw out to outer context, if we fall off end of the
- handler. */
- expand_internal_throw (gen_rtx (LABEL_REF,
- Pmode,
- entry->end_label));
+ exp = get_eh_value ();
+
+ /* 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);
+
+ exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
+
+ push_eh_cleanup ();
+
+ /* Create a binding level for the parm. */
+ pushlevel (0);
+ expand_start_bindings (0);
+
+ init = convert_from_reference (exp);
+
+ /* 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)))
+ {
+ /* 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 ());
+ }
+
+ /* 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);
+ }
+ else
+ {
+ push_eh_cleanup ();
- /* leftover try block, opps. */
- if (entry->finalization == integer_zero_node)
- abort ();
+ /* Create a binding level for the parm. */
+ pushlevel (0);
+ expand_start_bindings (0);
- free (entry);
+ /* Fall into the catch all section. */
}
- return first_label;
+ init = build_modify_expr (get_eh_caught (), NOP_EXPR, integer_one_node);
+ expand_expr (init, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ emit_line_note (input_filename, lineno);
}
+
+
/* 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 ()
-{
- rtx start_protect_label_rtx;
- rtx end_protect_label_rtx;
- tree decls;
- struct ehEntry entry;
+void
+expand_end_catch_block ()
+{
if (! doing_eh (1))
return;
- /* fall to outside the try statement when done executing handler and
+ /* 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. */
- emit_jump (top_label_entry (&caught_return_label_stack));
-
- /* We end the rethrow protection region as soon as we hit a label. */
- end_protect_label_rtx = expand_leftover_cleanups ();
-
- /* Code to throw out to outer context, if we get a throw from within
- our catch handler. */
- /* These are saved for the exception table. */
- push_rtl_perm ();
- entry.exception_handler_label = gen_label_rtx ();
- pop_rtl_from_perm ();
- /* This label is Lhandler in the documentation. */
- emit_label (entry.exception_handler_label);
- expand_internal_throw (gen_rtx (LABEL_REF,
- Pmode,
- top_label_entry (&caught_return_label_stack)));
-
- /* No associated finalization. */
- entry.finalization = NULL_TREE;
- entry.context = current_function_decl;
-
- if (end_protect_label_rtx == NULL_RTX)
- end_protect_label_rtx = entry.exception_handler_label;
-
- /* Because we are emitted out of line, we have to protect this. */
- /* label for the start of the protection region. */
- start_protect_label_rtx = pop_label_entry (&false_label_stack);
+ expand_goto (top_label_entry (&caught_return_label_stack));
- /* Cleanup the EH parameter. */
- decls = getdecls ();
- expand_end_bindings (decls, decls != NULL_TREE, 0);
-
- /* label we emit to jump to if this catch block didn't match. */
+ /* 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));
+ if (! flag_new_exceptions)
+ emit_label (pop_label_entry (&false_label_stack));
+}
+
+/* An exception spec is implemented more or less like:
- /* Because we are reordered out of line, we have to protect this. */
- entry.start_label = start_protect_label_rtx;
- entry.end_label = end_protect_label_rtx;
+ try {
+ function body;
+ } catch (...) {
+ void *p[] = { typeid(raises) };
+ __check_eh_spec (p, count);
+ }
- LABEL_PRESERVE_P (entry.start_label) = 1;
- LABEL_PRESERVE_P (entry.end_label) = 1;
- LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
+ __check_eh_spec in exception.cc handles all the details. */
- /* These set up a call to throw the caught exception into the outer
- context. */
- enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
+void
+expand_start_eh_spec ()
+{
+ expand_start_try_stmts ();
}
-/* unwind the stack. */
static void
-do_unwind (inner_throw_label)
- rtx inner_throw_label;
+expand_end_eh_spec (raises)
+ tree raises;
{
-#if defined(SPARC_STACK_ALIGN) /* was sparc */
- 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));
- 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;
+ tree tmp, fn, decl, types = NULL_TREE;
+ int count = 0;
- temp_frame = memory_address (Pmode, temp_frame);
- temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
+ expand_start_all_catch ();
+ expand_start_catch_block (NULL_TREE, NULL_TREE);
- /* 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))));
+ /* 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;
+ }
-#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))));
+ types = build_nt (CONSTRUCTOR, NULL_TREE, types);
+ TREE_HAS_CONSTRUCTOR (types) = 1;
- emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
+ /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */
+ tmp = build_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);
- 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;
+ decl = decay_conversion (decl);
- /* 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);
-#if 0
- /* I would like to do this here, but doesn't seem to work. */
- 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);
+ fn = get_identifier ("__check_eh_spec");
+ 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);
- do_function_call (Unwind, params, NULL_TREE);
- assemble_external (TREE_OPERAND (Unwind, 0));
- emit_barrier ();
-#endif
+ 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);
+ assemble_external (fn);
+ pop_obstacks ();
+ }
+
+ 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. */
-/* 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.
+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 ();
- expands "throw" as the following pseudo code:
+ /* 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 ();
+ }
- throw:
- eh = find_first_exception_match (saved_pc);
- if (!eh) goto gotta_rethrow_it;
- goto eh;
+ if (catch_clauses)
+ {
+ rtx funcend = gen_label_rtx ();
+ emit_jump (funcend);
- gotta_rethrow_it:
- saved_pc = __builtin_return_address (0);
- pop_to_previous_level ();
- goto throw;
+ /* 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 ();
- */
-void
-expand_builtin_throw ()
+ 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);
+ }
+}
+
+tree
+start_anon_func ()
{
- tree fcall;
+ static int counter = 0;
+ int old_interface_unknown = interface_unknown;
+ char name[32];
tree params;
- rtx return_val_rtx;
- rtx gotta_rethrow_it;
- rtx gotta_call_terminate;
- rtx unwind_and_throw;
- rtx goto_unwind_and_throw;
- rtx top_of_loop;
- rtx unwind_first;
tree t;
- if (! doing_eh (0))
- return;
+ push_cp_function_context (NULL_TREE);
+ push_to_top_level ();
- if (! throw_used)
- return;
+ /* No need to mangle this. */
+ push_lang_context (lang_name_c);
+
+ interface_unknown = 1;
params = void_list_node;
- t = build_parse_node (CALL_EXPR, get_identifier ("__throw"), params, NULL_TREE);
+ /* 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, NULL_TREE, 0);
+ t, NULL_TREE, 0);
store_parm_decls ();
pushlevel (0);
clear_last_expr ();
push_momentary ();
expand_start_bindings (0);
+ emit_line_note (input_filename, lineno);
- gotta_rethrow_it = gen_label_rtx ();
- gotta_call_terminate = gen_label_rtx ();
- unwind_and_throw = gen_label_rtx ();
- goto_unwind_and_throw = gen_label_rtx ();
- top_of_loop = gen_label_rtx ();
- unwind_first = gen_label_rtx ();
-
- 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 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
-
- /* 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);
-
- emit_jump_insn (gen_beq (gotta_call_terminate));
-
-#if defined(ARM_FRAME_RTX) /* was __arm */
- /* On the ARM, '__builtin_return_address', must have 4
- subtracted from it. */
- emit_insn (gen_add2_insn (return_val_rtx, GEN_INT (-4)));
-
- /* If we are generating code for an ARM2/ARM3 machine or for an ARM6 in 26 bit
- mode, the condition codes must be masked out of the return value, or else
- they will confuse BuiltinReturnAddress. This does not apply to ARM6 and
- later processors when running in 32 bit mode. */
- if (!TARGET_6)
- emit_insn (gen_rtx (SET, Pmode, return_val_rtx, gen_rtx (AND, Pmode, return_val_rtx, GEN_INT (0x03fffffc))));
-#else
-#if !defined(SPARC_STACK_ALIGN) /* was sparc */
- /* On the SPARC, __builtin_return_address is already -8, no need to
- subtract any more from it. */
- return_val_rtx = plus_constant (return_val_rtx, -1);
-#endif
-#endif
+ interface_unknown = old_interface_unknown;
- /* yes it did */
- t = build_modify_expr (saved_pc, NOP_EXPR, make_tree (ptr_type_node, return_val_rtx));
- expand_expr (t, const0_rtx, VOIDmode, 0);
-
- 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 NORMAL_RETURN_ADDR_OFFSET
- return_val_rtx = plus_constant (ret_val, -NORMAL_RETURN_ADDR_OFFSET);
- if (return_val_rtx != ret_val)
- emit_move_insn (ret_val, return_val_rtx);
-#endif
+ pop_lang_context ();
- /* Fall into epilogue to unwind prologue. */
- }
+ return current_function_decl;
+}
- expand_end_bindings (getdecls(), 1, 0);
+void
+end_anon_func ()
+{
+ expand_end_bindings (getdecls (), 1, 0);
poplevel (1, 0, 0);
pop_momentary ();
finish_function (lineno, 0, 0);
-}
-
-void
-expand_start_eh_spec ()
-{
- start_protect ();
+ pop_from_top_level ();
+ pop_cp_function_context (NULL_TREE);
}
-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);
- start_protect ();
- do_function_call (Unexpected, NULL_TREE, NULL_TREE);
- assemble_external (TREE_OPERAND (Unexpected, 0));
- emit_barrier ();
- end_protect (second_try);
-
- emit_label (check);
- emit_move_insn (flag, const1_rtx);
- cont = gen_label_rtx ();
- while (raises)
- {
- 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);
- }
+/* Return a pointer to a buffer for an exception object of type TYPE. */
- raises = TREE_CHAIN (raises);
- }
- emit_move_insn (flag, const0_rtx);
- emit_label (cont);
- emit_indirect_jump (ret);
- emit_label (end);
-
- RTL_EXPR_SEQUENCE (expr) = get_insns ();
- end_sequence ();
-
- end_protect (expr);
-}
-
-/* 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 ()
+static tree
+alloc_eh_object (type)
+ tree type;
{
- static rtx funcend;
- rtx insns;
-
- 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 ();
+ tree fn, exp;
- insns = get_insns ();
- end_sequence ();
-
- /* Do this after we expand leftover cleanups, so that the end_protect
- that expand_end_eh_spec does will match the right start_protect,
- 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)));
- push_to_sequence (insns);
-
- /* Now expand any new ones. */
- expand_leftover_cleanups ();
-
- insns = get_insns ();
- end_sequence ();
- }
-
- if (insns)
+ fn = get_identifier ("__eh_alloc");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
{
- struct ehEntry entry;
-
- /* These are saved for the exception table. */
- push_rtl_perm ();
- entry.start_label = gen_label_rtx ();
- entry.end_label = gen_label_rtx ();
- entry.exception_handler_label = gen_label_rtx ();
- entry.finalization = TerminateFunctionCall;
- entry.context = current_function_decl;
- assemble_external (TREE_OPERAND (Terminate, 0));
- pop_rtl_from_perm ();
-
- LABEL_PRESERVE_P (entry.start_label) = 1;
- LABEL_PRESERVE_P (entry.end_label) = 1;
- LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
-
- emit_label (entry.start_label);
- emit_insns (insns);
-
- enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
-
- emit_label (entry.exception_handler_label);
- expand_expr (entry.finalization, const0_rtx, VOIDmode, 0);
- emit_label (entry.end_label);
- emit_barrier ();
+ /* 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);
+ assemble_external (fn);
+ pop_obstacks ();
}
- {
- /* Mark the end of the stack unwinder. */
- rtx unwind_insns;
- start_sequence ();
- end_eh_unwinder (funcend);
- expand_leftover_cleanups ();
- 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 ();
-
- emit_insns (insns);
+ 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;
}
-
-/* call this to expand a throw statement. This follows the following
+/* Expand a throw statement. This follows the following
algorithm:
1. Allocate space to save the current PC onto the stack.
@@ -1501,30 +1084,40 @@ expand_exception_blocks ()
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
expand_throw (exp)
tree exp;
{
- rtx label;
+ tree fn;
+ static tree cleanup_type;
if (! doing_eh (1))
return;
- /* 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);
-
if (exp)
{
tree throw_type;
- tree e;
+ tree cleanup = NULL_TREE, e;
/* throw expression */
- /* First, decay it. */
+ /* First, decay it. */
exp = decay_conversion (exp);
+ /* cleanup_type is void (*)(void *, int),
+ the internal type of a destructor. */
+ if (cleanup_type == NULL_TREE)
+ {
+ 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 ();
+ }
+
if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
{
throw_type = build_eh_type (exp);
@@ -1532,169 +1125,167 @@ expand_throw (exp)
}
else
{
- /* 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);
+ tree object, ptr;
- if (exp == error_mark_node)
- error (" in thrown expression");
+ /* OK, this is kind of wacky. The WP says that we call
+ terminate
- throw_type = build_eh_type (build_indirect_ref (exp, NULL_PTR));
- }
+ 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.
- e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type);
- expand_expr (e, const0_rtx, VOIDmode, 0);
- 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);
- }
- else
- {
- /* rethrow current exception */
- /* This part is easy, as we don't have to do anything else. */
- }
+ 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_internal_throw (gen_rtx (LABEL_REF, Pmode, label));
-}
+ expand_start_target_temps ();
-void
-end_protect_partials () {
- while (protect_list)
- {
- end_protect (TREE_VALUE (protect_list));
- protect_list = TREE_CHAIN (protect_list);
- }
-}
+#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))
+ {
+ tree temp = build (VAR_DECL, TREE_TYPE (exp));
+ DECL_ARTIFICIAL (temp) = 1;
+ layout_decl (temp, 0);
+ DECL_RTL (temp) = assign_temp (TREE_TYPE (exp), 2, 0, 1);
+ expand_expr (build (INIT_EXPR, TREE_TYPE (exp), temp, exp),
+ NULL_RTX, VOIDmode, 0);
+ expand_decl_cleanup (NULL_TREE, maybe_build_cleanup (temp));
+ exp = temp;
+ }
+#endif
-int
-might_have_exceptions_p ()
-{
- if (eh_table_output_queue.head)
- return 1;
- return 0;
-}
+ /* Allocate the space for the exception. */
+ ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
+ expand_expr (ptr, const0_rtx, VOIDmode, 0);
-/* Output the exception table.
- Return the number of handlers. */
-void
-emit_exception_table ()
-{
- int count = 0;
- extern FILE *asm_out_file;
- struct ehEntry *entry;
- tree eh_node_decl;
+ expand_eh_region_start ();
- if (! doing_eh (0))
- return;
+ object = build_indirect_ref (ptr, NULL_PTR);
+ exp = build_modify_expr (object, INIT_EXPR, exp);
- exception_section ();
+ if (exp == error_mark_node)
+ error (" in thrown expression");
- /* Beginning marker for table. */
- assemble_align (GET_MODE_ALIGNMENT (Pmode));
- assemble_label ("__EXCEPTION_TABLE__");
- output_exception_table_entry (asm_out_file,
- const0_rtx, const0_rtx, const0_rtx);
+ expand_expr (exp, const0_rtx, VOIDmode, 0);
+ expand_eh_region_end (build_terminate_handler ());
+ expand_end_target_temps ();
- while (entry = dequeue_eh_entry (&eh_table_output_queue))
- {
- tree context = entry->context;
+ throw_type = build_eh_type (object);
- if (context && ! TREE_ASM_WRITTEN (context))
- continue;
+ 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);
+ }
- count++;
- output_exception_table_entry (asm_out_file,
- entry->start_label, entry->end_label,
- entry->exception_handler_label);
- }
+ exp = ptr;
+ }
- /* Ending marker for table. */
- assemble_label ("__EXCEPTION_END__");
- output_exception_table_entry (asm_out_file,
- constm1_rtx, constm1_rtx, constm1_rtx);
-}
+ if (cleanup == NULL_TREE)
+ {
+ cleanup = build_int_2 (0, 0);
+ TREE_TYPE (cleanup) = cleanup_type;
+ }
-void
-register_exception_table ()
-{
- rtx addr = gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__");
+ 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);
+ assemble_external (fn);
+ pop_obstacks ();
+ }
-#ifdef MARK_LOCAL_ADDRESS
- MARK_LOCAL_ADDRESS(addr);
-#endif
+ 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);
+ }
+ else
+ {
+ /* rethrow current exception; note that it's no longer caught. */
+
+ tree fn = get_identifier ("__uncatch_exception");
+ 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);
+ assemble_external (fn);
+ pop_obstacks ();
+ }
- emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
- VOIDmode, 1,
- addr,
- Pmode);
+ exp = build_function_call (fn, NULL_TREE);
+ expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ }
+
+ expand_internal_throw ();
}
/* Build a throw expression. */
+
tree
build_throw (e)
tree e;
{
- if (e != error_mark_node)
- {
- e = build1 (THROW_EXPR, void_type_node, e);
- TREE_SIDE_EFFECTS (e) = 1;
- TREE_USED (e) = 1;
- }
- return e;
-}
+ if (e == error_mark_node)
+ return e;
-start_eh_unwinder ()
-{
- start_protect ();
-}
+ if (processing_template_decl)
+ return build_min (THROW_EXPR, void_type_node, e);
-end_eh_unwinder (end)
- rtx end;
-{
- tree expr;
- rtx return_val_rtx, ret_val, label;
-
- if (! doing_eh (0))
- return;
-
- 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);
-
- ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
- 0, hard_frame_pointer_rtx);
- return_val_rtx = copy_to_reg (ret_val);
-#ifdef NORMAL_RETURN_ADDR_OFFSET
- return_val_rtx = plus_constant (return_val_rtx, NORMAL_RETURN_ADDR_OFFSET-1);
-#else
- return_val_rtx = plus_constant (return_val_rtx, -1);
-#endif
- emit_move_insn (DECL_RTL (saved_pc), return_val_rtx);
-
-#ifdef JUMP_TO_THROW
- emit_move_insn (ret_val, gen_rtx (SYMBOL_REF, Pmode, "__throw"));
-#else
- label = gen_label_rtx ();
- emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, label));
-#endif
+ if (! flag_ansi && e == null_node)
+ {
+ cp_warning ("throwing NULL");
+ e = integer_zero_node;
+ }
-#ifdef NORMAL_RETURN_ADDR_OFFSET
- return_val_rtx = plus_constant (ret_val, -NORMAL_RETURN_ADDR_OFFSET);
- if (return_val_rtx != ret_val)
- emit_move_insn (ret_val, return_val_rtx);
-#endif
-
- emit_jump (end);
+ e = build1 (THROW_EXPR, void_type_node, e);
+ TREE_SIDE_EFFECTS (e) = 1;
+ TREE_USED (e) = 1;
-#ifndef JUMP_TO_THROW
- emit_label (label);
- do_function_call (Throw, NULL_TREE, NULL_TREE);
-#endif
-
- RTL_EXPR_SEQUENCE (expr) = get_insns ();
- end_sequence ();
- end_protect (expr);
+ return e;
}
OpenPOWER on IntegriCloud