aboutsummaryrefslogtreecommitdiff
path: root/contrib/gcc/cp/except.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/gcc/cp/except.c')
-rw-r--r--contrib/gcc/cp/except.c1161
1 files changed, 0 insertions, 1161 deletions
diff --git a/contrib/gcc/cp/except.c b/contrib/gcc/cp/except.c
deleted file mode 100644
index 9e2d6af592aa..000000000000
--- a/contrib/gcc/cp/except.c
+++ /dev/null
@@ -1,1161 +0,0 @@
-/* Handle exceptional things in C++.
- Copyright (C) 1989, 92-97, 1998, 1999 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.
-
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
-
-
-#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"
-
-rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
-
-/* Holds the fndecl for __builtin_return_address. */
-tree builtin_return_address_fndecl;
-
-/* A couple of backend routines from m88k.c */
-
-static void push_eh_cleanup PROTO((void));
-static tree build_eh_type_type PROTO((tree));
-static tree build_eh_type PROTO((tree));
-static void expand_end_eh_spec PROTO((tree));
-static tree call_eh_info PROTO((void));
-static void push_eh_info PROTO((void));
-static tree get_eh_info PROTO((void));
-static tree get_eh_value PROTO((void));
-#if 0
-static tree get_eh_type PROTO((void));
-static tree get_eh_caught PROTO((void));
-static tree get_eh_handlers PROTO((void));
-#endif
-static tree do_pop_exception PROTO((void));
-static void process_start_catch_block PROTO((tree, tree));
-static tree build_eh_type_type_ref PROTO((tree));
-static tree build_terminate_handler PROTO((void));
-static tree alloc_eh_object PROTO((tree));
-
-#if 0
-/* This is the startup, and finish stuff per exception table. */
-
-/* XXX - Tad: exception handling section */
-#ifndef EXCEPT_SECTION_ASM_OP
-#define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
-#endif
-
-#ifdef EXCEPT_SECTION_ASM_OP
-
- /* on machines which support it, the exception table lives in another section,
- but it needs a label so we can reference it... This sets up that
- label! */
-asm (EXCEPT_SECTION_ASM_OP);
-exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
-asm (TEXT_SECTION_ASM_OP);
-
-#endif /* EXCEPT_SECTION_ASM_OP */
-
-#ifdef EXCEPT_SECTION_ASM_OP
-
- /* we need to know where the end of the exception table is... so this
- is how we do it! */
-
-asm (EXCEPT_SECTION_ASM_OP);
-exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
-asm (TEXT_SECTION_ASM_OP);
-
-#endif /* EXCEPT_SECTION_ASM_OP */
-
-#endif
-
-#include "decl.h"
-#include "insn-flags.h"
-#include "obstack.h"
-
-/* ======================================================================
- Briefly the algorithm works like this:
-
- When a constructor or start of a try block is encountered,
- push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
- new entry in the unwind protection stack and returns a label to
- output to start the protection for that block.
-
- When a destructor or end try block is encountered, pop_eh_entry
- (&eh_stack) is called. Pop_eh_entry () returns the eh_entry it
- created when push_eh_entry () was called. The eh_entry structure
- contains three things at this point. The start protect label,
- the end protect label, and the exception handler label. The end
- protect label should be output before the call to the destructor
- (if any). If it was a destructor, then its parse tree is stored
- in the finalization variable in the eh_entry structure. Otherwise
- the finalization variable is set to NULL to reflect the fact that
- it is the end of a try block. Next, this modified eh_entry node
- is enqueued in the finalizations queue by calling
- enqueue_eh_entry (&queue,entry).
-
- +---------------------------------------------------------------+
- |XXX: Will need modification to deal with partially |
- | constructed arrays of objects |
- | |
- | Basically, this consists of keeping track of how many |
- | of the objects have been constructed already (this |
- | should be in a register though, so that shouldn't be a |
- | problem. |
- +---------------------------------------------------------------+
-
- When a catch block is encountered, there is a lot of work to be
- done.
-
- Since we don't want to generate the catch block inline with the
- regular flow of the function, we need to have some way of doing
- so. Luckily, we can use sequences to defer the catch sections.
- When the start of a catch block is encountered, we start the
- sequence. After the catch block is generated, we end the
- sequence.
-
- Next we must insure that when the catch block is executed, all
- finalizations for the matching try block have been completed. If
- any of those finalizations throw an exception, we must call
- terminate according to the ARM (section r.15.6.1). What this
- means is that we need to dequeue and emit finalizations for each
- entry in the eh_queue until we get to an entry with a NULL
- finalization field. For any of the finalization entries, if it
- is not a call to terminate (), we must protect it by giving it
- another start label, end label, and exception handler label,
- setting its finalization tree to be a call to terminate (), and
- enqueue'ing this new eh_entry to be output at an outer level.
- Finally, after all that is done, we can get around to outputting
- the catch block which basically wraps all the "catch (...) {...}"
- statements in a big if/then/else construct that matches the
- correct block to call.
-
- ===================================================================== */
-
-/* local globals for function calls
- ====================================================================== */
-
-/* Used to cache "terminate" and "__throw_type_match*". */
-static tree Terminate, CatchMatch;
-
-/* Used to cache __find_first_exception_table_match for throw. */
-static tree FirstExceptionMatch;
-
-/* Used to cache a call to __unwind_function. */
-static tree Unwind;
-
-/* ====================================================================== */
-
-
-/* ========================================================================= */
-
-
-
-/* local globals - these local globals are for storing data necessary for
- generating the exception table and code in the correct order.
-
- ========================================================================= */
-
-extern rtx catch_clauses;
-extern tree const_ptr_type_node;
-
-/* ========================================================================= */
-
-/* sets up all the global eh stuff that needs to be initialized at the
- start of compilation.
-
- This includes:
- - Setting up all the function call trees. */
-
-void
-init_exception_processing ()
-{
- /* void vtype () */
- tree vtype = build_function_type (void_type_node, void_list_node);
-
- if (flag_honor_std)
- push_namespace (get_identifier ("std"));
- Terminate = auto_function (get_identifier ("terminate"),
- vtype, NOT_BUILT_IN);
- TREE_THIS_VOLATILE (Terminate) = 1;
- if (flag_honor_std)
- pop_namespace ();
-
- push_lang_context (lang_name_c);
-
- set_exception_lang_code (EH_LANG_C_plus_plus);
- set_exception_version_code (1);
-
- CatchMatch
- = builtin_function (flag_rtti
- ? "__throw_type_match_rtti"
- : "__throw_type_match",
- build_function_type (ptr_type_node,
- tree_cons (NULL_TREE, const_ptr_type_node,
- tree_cons (NULL_TREE, const_ptr_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- void_list_node)))),
- NOT_BUILT_IN, NULL_PTR);
- FirstExceptionMatch
- = builtin_function ("__find_first_exception_table_match",
- build_function_type (ptr_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- void_list_node)),
- NOT_BUILT_IN, NULL_PTR);
- Unwind
- = builtin_function ("__unwind_function",
- build_function_type (void_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- void_list_node)),
- NOT_BUILT_IN, NULL_PTR);
-
- pop_lang_context ();
-
- /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
- be protected with __terminate. */
- protect_cleanup_actions_with_terminate = 1;
-}
-
-/* Retrieve a pointer to the cp_eh_info node for the current exception. */
-
-static tree
-call_eh_info ()
-{
- tree fn;
-
- fn = get_identifier ("__start_cp_handler");
- if (IDENTIFIER_GLOBAL_VALUE (fn))
- fn = IDENTIFIER_GLOBAL_VALUE (fn);
- else
- {
- tree t1, t, fields[7];
-
- /* Declare cp_eh_info * __start_cp_handler (void),
- as defined in exception.cc. */
- push_obstacks_nochange ();
- end_temporary_allocation ();
-
- /* struct cp_eh_info. This must match exception.cc. Note that this
- type is not pushed anywhere. */
- t1= make_lang_type (RECORD_TYPE);
- fields[0] = build_lang_field_decl (FIELD_DECL,
- get_identifier ("handler_label"), ptr_type_node);
- fields[1] = build_lang_field_decl (FIELD_DECL,
- get_identifier ("dynamic_handler_chain"), ptr_type_node);
- fields[2] = build_lang_field_decl (FIELD_DECL,
- get_identifier ("info"), ptr_type_node);
- fields[3] = build_lang_field_decl (FIELD_DECL,
- get_identifier ("table_index"), ptr_type_node);
- /* N.B.: The fourth field LEN is expected to be
- the number of fields - 1, not the total number of fields. */
- finish_builtin_type (t1, "eh_context", fields, 3, ptr_type_node);
- t1 = build_pointer_type (t1);
-
- t1= make_lang_type (RECORD_TYPE);
- fields[0] = build_lang_field_decl (FIELD_DECL,
- get_identifier ("match_function"), ptr_type_node);
- fields[1] = build_lang_field_decl (FIELD_DECL,
- get_identifier ("language"), short_integer_type_node);
- fields[2] = build_lang_field_decl (FIELD_DECL,
- get_identifier ("version"), short_integer_type_node);
- /* N.B.: The fourth field LEN is expected to be
- the number of fields - 1, not the total number of fields. */
- finish_builtin_type (t1, "__eh_info", fields, 2, ptr_type_node);
- t = make_lang_type (RECORD_TYPE);
- fields[0] = build_lang_field_decl (FIELD_DECL,
- get_identifier ("eh_info"), t1);
- fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"),
- ptr_type_node);
- fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
- ptr_type_node);
- fields[3] = build_lang_field_decl
- (FIELD_DECL, get_identifier ("cleanup"),
- build_pointer_type (build_function_type
- (ptr_type_node, tree_cons
- (NULL_TREE, ptr_type_node, void_list_node))));
- fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"),
- boolean_type_node);
- fields[5] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"),
- build_pointer_type (t));
- fields[6] = build_lang_field_decl
- (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node);
- /* N.B.: The fourth field LEN is expected to be
- the number of fields - 1, not the total number of fields. */
- finish_builtin_type (t, "cp_eh_info", fields, 6, ptr_type_node);
- t = build_pointer_type (t);
-
- /* And now the function. */
- fn = build_lang_decl (FUNCTION_DECL, fn,
- build_function_type (t, void_list_node));
- DECL_EXTERNAL (fn) = 1;
- TREE_PUBLIC (fn) = 1;
- DECL_ARTIFICIAL (fn) = 1;
- pushdecl_top_level (fn);
- make_function_rtl (fn);
- pop_obstacks ();
- }
- mark_used (fn);
- return build_function_call (fn, NULL_TREE);
-}
-
-/* Retrieve a pointer to the cp_eh_info node for the current exception
- and save it in the current binding level. */
-
-static void
-push_eh_info ()
-{
- tree decl, fn = call_eh_info ();
-
- /* Remember the pointer to the current exception info; it won't change
- during this catch block. */
- decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
- TREE_TYPE (fn));
- DECL_ARTIFICIAL (decl) = 1;
- DECL_INITIAL (decl) = fn;
- decl = pushdecl (decl);
- cp_finish_decl (decl, fn, NULL_TREE, 0, 0);
-}
-
-/* Returns a reference to the cp_eh_info node for the current exception. */
-
-static tree
-get_eh_info ()
-{
- /* Look for the pointer pushed in push_eh_info. */
- tree t = lookup_name (get_identifier ("__exception_info"), 0);
- return build_indirect_ref (t, NULL_PTR);
-}
-
-/* Returns a reference to the current exception object. */
-
-static tree
-get_eh_value ()
-{
- return build_component_ref (get_eh_info (), get_identifier ("value"),
- NULL_TREE, 0);
-}
-
-/* Returns a reference to the current exception type. */
-
-#if 0
-static tree
-get_eh_type ()
-{
- return build_component_ref (get_eh_info (), get_identifier ("type"),
- NULL_TREE, 0);
-}
-
-/* Returns a reference to whether or not the current exception
- has been caught. */
-
-static tree
-get_eh_caught ()
-{
- return build_component_ref (get_eh_info (), get_identifier ("caught"),
- NULL_TREE, 0);
-}
-
-/* Returns a reference to whether or not the current exception
- has been caught. */
-
-static tree
-get_eh_handlers ()
-{
- return build_component_ref (get_eh_info (), get_identifier ("handlers"),
- NULL_TREE, 0);
-}
-#endif
-
-/* Build a type value for use at runtime for a type that is matched
- against by the exception handling system. */
-
-static tree
-build_eh_type_type (type)
- tree type;
-{
- const char *typestring;
- tree exp;
-
- if (type == error_mark_node)
- return error_mark_node;
-
- /* peel back references, so they match. */
- if (TREE_CODE (type) == REFERENCE_TYPE)
- type = TREE_TYPE (type);
-
- /* Peel off cv qualifiers. */
- type = TYPE_MAIN_VARIANT (type);
-
- if (flag_rtti)
- return build1 (ADDR_EXPR, ptr_type_node, get_typeid_1 (type));
-
- typestring = build_overload_name (type, 1, 1);
- exp = combine_strings (build_string (strlen (typestring)+1, typestring));
- return build1 (ADDR_EXPR, ptr_type_node, exp);
-}
-
-/* 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_ref (type)
- tree type;
-{
- const char *typestring;
- tree exp;
-
- if (type == error_mark_node)
- return error_mark_node;
-
- /* peel back references, so they match. */
- if (TREE_CODE (type) == REFERENCE_TYPE)
- type = TREE_TYPE (type);
-
- /* Peel off cv qualifiers. */
- type = TYPE_MAIN_VARIANT (type);
-
- push_obstacks_nochange ();
- end_temporary_allocation ();
-
- if (flag_rtti)
- {
- exp = get_tinfo_fn (type);
- TREE_USED (exp) = 1;
- mark_inline_for_output (exp);
- exp = build1 (ADDR_EXPR, ptr_type_node, exp);
- }
- else
- {
- typestring = build_overload_name (type, 1, 1);
- exp = combine_strings (build_string (strlen (typestring)+1, typestring));
- exp = build1 (ADDR_EXPR, ptr_type_node, exp);
- }
- pop_obstacks ();
- return (exp);
-}
-
-
-/* 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;
-{
- if (flag_rtti)
- {
- exp = build_typeid (exp);
- return build1 (ADDR_EXPR, ptr_type_node, exp);
- }
- return build_eh_type_type (TREE_TYPE (exp));
-}
-
-/* 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);
- pop_obstacks ();
- }
-
- mark_used (fn);
- /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
- cleanup = lookup_name (get_identifier ("__exception_info"), 0);
- cleanup = build_function_call (fn, expr_tree_cons
- (NULL_TREE, cleanup, NULL_TREE));
- return cleanup;
-}
-
-/* This routine creates the cleanup for the current exception. */
-
-static void
-push_eh_cleanup ()
-{
- int yes;
-
- 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;
-{
- 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;
-
- process_start_catch_block (declspecs, declarator);
-}
-
-
-/* This function performs the expand_start_catch_block functionality for
- exceptions implemented in the new style. __throw determines whether
- a handler needs to be called or not, so the handler itself has to do
- nothing additional. */
-
-static void
-process_start_catch_block (declspecs, declarator)
- tree declspecs, declarator;
-{
- 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);
-
-
- 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)
- {
- 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;
-
- /* 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 = 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);
-
- start_decl_1 (decl);
- cp_finish_decl (decl, init, NULL_TREE, 0,
- LOOKUP_ONLYCONVERTING|DIRECT_BIND);
- }
- else
- {
- push_eh_cleanup ();
-
- /* Create a binding level for the parm. */
- pushlevel (0);
- expand_start_bindings (0);
-
- /* Fall into the catch all section. */
- }
-
- 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 ()
-{
- if (! doing_eh (1))
- return;
-
- /* Cleanup the EH parameter. */
- expand_end_bindings (getdecls (), kept_level_p (), 0);
- poplevel (kept_level_p (), 1, 0);
-
- /* Cleanup the EH object. */
- expand_end_bindings (getdecls (), kept_level_p (), 0);
- poplevel (kept_level_p (), 1, 0);
-
- /* Fall to outside the try statement when done executing handler and
- we fall off end of handler. This is jump Lresume in the
- documentation. */
- expand_goto (top_label_entry (&caught_return_label_stack));
-
- end_catch_handler ();
-}
-
-/* An exception spec is implemented more or less like:
-
- try {
- function body;
- } catch (...) {
- void *p[] = { typeid(raises) };
- __check_eh_spec (p, count);
- }
-
- __check_eh_spec in exception.cc handles all the details. */
-
-void
-expand_start_eh_spec ()
-{
- expand_start_try_stmts ();
-}
-
-static void
-expand_end_eh_spec (raises)
- tree raises;
-{
- tree tmp, fn, decl, types = NULL_TREE;
- int count = 0;
-
- expand_start_all_catch ();
- expand_start_catch_block (NULL_TREE, NULL_TREE);
-
- /* 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;
- }
-
- types = build_nt (CONSTRUCTOR, NULL_TREE, types);
- TREE_HAS_CONSTRUCTOR (types) = 1;
-
- /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */
- tmp = build_cplus_array_type (const_ptr_type_node, NULL_TREE);
- decl = build_decl (VAR_DECL, NULL_TREE, tmp);
- DECL_ARTIFICIAL (decl) = 1;
- DECL_INITIAL (decl) = types;
- cp_finish_decl (decl, types, NULL_TREE, 0, 0);
-
- decl = decay_conversion (decl);
-
- 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);
-
- fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
- DECL_EXTERNAL (fn) = 1;
- TREE_PUBLIC (fn) = 1;
- DECL_ARTIFICIAL (fn) = 1;
- TREE_THIS_VOLATILE (fn) = 1;
- pushdecl_top_level (fn);
- make_function_rtl (fn);
- pop_obstacks ();
- }
-
- mark_used (fn);
- tmp = expr_tree_cons (NULL_TREE, build_int_2 (count, 0), expr_tree_cons
- (NULL_TREE, decl, NULL_TREE));
- tmp = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), tmp);
- expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
-
- expand_end_catch_block ();
- expand_end_all_catch ();
-}
-
-/* This is called to expand all the toplevel exception handling
- finalization for a function. It should only be called once per
- function. */
-
-void
-expand_exception_blocks ()
-{
- do_pending_stack_adjust ();
- push_to_sequence (catch_clauses);
- expand_leftover_cleanups ();
- do_pending_stack_adjust ();
- catch_clauses = get_insns ();
- end_sequence ();
-
- /* Do this after we expand leftover cleanups, so that the
- expand_eh_region_end that expand_end_eh_spec does will match the
- right expand_eh_region_start, and make sure it comes out before
- the terminate protected region. */
- if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
- {
- expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
- do_pending_stack_adjust ();
- push_to_sequence (catch_clauses);
- expand_leftover_cleanups ();
- do_pending_stack_adjust ();
- catch_clauses = get_insns ();
- end_sequence ();
- }
-
- if (catch_clauses)
- {
- rtx funcend = gen_label_rtx ();
- emit_jump (funcend);
-
- /* We cannot protect n regions this way if we must flow into the
- EH region through the top of the region, as we have to with
- the setjmp/longjmp approach. */
- if (exceptions_via_longjmp == 0)
- expand_eh_region_start ();
-
- emit_insns (catch_clauses);
- catch_clauses = NULL_RTX;
-
- if (exceptions_via_longjmp == 0)
- expand_eh_region_end (build_terminate_handler ());
-
- expand_leftover_cleanups ();
-
- emit_label (funcend);
- }
-}
-
-tree
-start_anon_func ()
-{
- static int counter = 0;
- int old_interface_unknown = interface_unknown;
- char name[32];
- tree params;
- tree t;
-
- push_cp_function_context (NULL_TREE);
- push_to_top_level ();
-
- /* No need to mangle this. */
- push_lang_context (lang_name_c);
-
- interface_unknown = 1;
-
- params = void_list_node;
- /* tcf stands for throw clean function. */
- sprintf (name, "__tcf_%d", counter++);
- t = make_call_declarator (get_identifier (name), params, NULL_TREE,
- NULL_TREE);
- start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
- void_list_node),
- t, NULL_TREE, 0);
- store_parm_decls ();
- pushlevel (0);
- clear_last_expr ();
- push_momentary ();
- expand_start_bindings (0);
- emit_line_note (input_filename, lineno);
-
- interface_unknown = old_interface_unknown;
-
- pop_lang_context ();
-
- return current_function_decl;
-}
-
-void
-end_anon_func ()
-{
- expand_end_bindings (getdecls (), 1, 0);
- poplevel (1, 0, 0);
- pop_momentary ();
-
- finish_function (lineno, 0, 0);
-
- pop_from_top_level ();
- pop_cp_function_context (NULL_TREE);
-}
-
-/* Return a pointer to a buffer for an exception object of type TYPE. */
-
-static tree
-alloc_eh_object (type)
- tree type;
-{
- tree fn, exp;
-
- fn = get_identifier ("__eh_alloc");
- if (IDENTIFIER_GLOBAL_VALUE (fn))
- fn = IDENTIFIER_GLOBAL_VALUE (fn);
- else
- {
- /* Declare __eh_alloc (size_t), as defined in exception.cc. */
- tree tmp;
- push_obstacks_nochange ();
- end_temporary_allocation ();
- tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
- fn = build_lang_decl (FUNCTION_DECL, fn,
- build_function_type (ptr_type_node, tmp));
- DECL_EXTERNAL (fn) = 1;
- TREE_PUBLIC (fn) = 1;
- DECL_ARTIFICIAL (fn) = 1;
- pushdecl_top_level (fn);
- make_function_rtl (fn);
- pop_obstacks ();
- }
-
- mark_used (fn);
- exp = build_function_call (fn, expr_tree_cons
- (NULL_TREE, size_in_bytes (type), NULL_TREE));
- exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
- return exp;
-}
-
-/* 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
-expand_throw (exp)
- tree exp;
-{
- tree fn;
- static tree cleanup_type;
-
- if (! doing_eh (1))
- return;
-
- if (exp)
- {
- tree throw_type;
- tree cleanup = NULL_TREE, e;
-
- /* throw expression */
- /* 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 (TYPE_PTR_P (TREE_TYPE (exp)))
- throw_type = build_eh_type (exp);
- else
- {
- tree object, ptr;
-
- /* OK, this is kind of wacky. The WP says that we call
- terminate
-
- when the exception handling mechanism, after completing
- evaluation of the expression to be thrown but before the
- exception is caught (_except.throw_), calls a user function
- that exits via an uncaught exception.
-
- So we have to protect the actual initialization of the
- exception object with terminate(), but evaluate the expression
- first. We also expand the call to __eh_alloc
- first. Since there could be temps in the expression, we need
- to handle that, too. */
-
- expand_start_target_temps ();
-
-#if 0
- /* Unfortunately, this doesn't work. */
- preexpand_calls (exp);
-#else
- /* Store the throw expression into a temp. This can be less
- efficient than storing it into the allocated space directly, but
- oh well. To do this efficiently we would need to insinuate
- ourselves into expand_call. */
- if (TREE_SIDE_EFFECTS (exp))
- {
- tree temp = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp));
- DECL_ARTIFICIAL (temp) = 1;
- DECL_RTL (temp) = assign_temp (TREE_TYPE (exp), 2, 0, 1);
- DECL_INITIAL (temp) = exp;
- cp_finish_decl (temp, exp, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
- exp = temp;
- }
-#endif
-
- /* Allocate the space for the exception. */
- ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
- expand_expr (ptr, const0_rtx, VOIDmode, 0);
-
- expand_eh_region_start ();
-
- object = build_indirect_ref (ptr, NULL_PTR);
- exp = build_modify_expr (object, INIT_EXPR, exp);
-
- if (exp == error_mark_node)
- error (" in thrown expression");
-
- expand_expr (exp, const0_rtx, VOIDmode, 0);
- expand_eh_region_end (build_terminate_handler ());
- expand_end_target_temps ();
-
- throw_type = build_eh_type (object);
-
- if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
- {
- cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
- dtor_identifier, 0);
- cleanup = TREE_VALUE (cleanup);
- mark_used (cleanup);
- mark_addressable (cleanup);
- /* Pretend it's a normal function. */
- cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
- }
-
- exp = ptr;
- }
-
- /* Cast EXP to `void *' so that it will match the prototype for
- __cp_push_exception. */
- exp = convert (ptr_type_node, exp);
-
- if (cleanup == NULL_TREE)
- {
- cleanup = build_int_2 (0, 0);
- TREE_TYPE (cleanup) = cleanup_type;
- }
-
- fn = get_identifier ("__cp_push_exception");
- if (IDENTIFIER_GLOBAL_VALUE (fn))
- fn = IDENTIFIER_GLOBAL_VALUE (fn);
- else
- {
- /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
- as defined in exception.cc. */
- tree tmp;
- push_obstacks_nochange ();
- end_temporary_allocation ();
- tmp = tree_cons
- (NULL_TREE, ptr_type_node, tree_cons
- (NULL_TREE, ptr_type_node, tree_cons
- (NULL_TREE, cleanup_type, void_list_node)));
- fn = build_lang_decl (FUNCTION_DECL, fn,
- build_function_type (void_type_node, tmp));
- DECL_EXTERNAL (fn) = 1;
- TREE_PUBLIC (fn) = 1;
- DECL_ARTIFICIAL (fn) = 1;
- pushdecl_top_level (fn);
- make_function_rtl (fn);
- pop_obstacks ();
- }
-
- mark_used (fn);
- e = expr_tree_cons (NULL_TREE, exp, expr_tree_cons
- (NULL_TREE, throw_type, expr_tree_cons
- (NULL_TREE, cleanup, NULL_TREE)));
- e = build_function_call (fn, e);
- expand_expr (e, const0_rtx, VOIDmode, 0);
- }
- 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);
- pop_obstacks ();
- }
-
- mark_used (fn);
- 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)
- return e;
-
- if (processing_template_decl)
- return build_min (THROW_EXPR, void_type_node, e);
-
- if (e == null_node)
- cp_warning ("throwing NULL, which has integral, not pointer type");
-
- e = build1 (THROW_EXPR, void_type_node, e);
- TREE_SIDE_EFFECTS (e) = 1;
- TREE_USED (e) = 1;
-
- return e;
-}