diff options
Diffstat (limited to 'gnu/gcc2/cc1plus/cp-except.c')
| -rw-r--r-- | gnu/gcc2/cc1plus/cp-except.c | 1221 |
1 files changed, 0 insertions, 1221 deletions
diff --git a/gnu/gcc2/cc1plus/cp-except.c b/gnu/gcc2/cc1plus/cp-except.c deleted file mode 100644 index 6f5dc3b09796..000000000000 --- a/gnu/gcc2/cc1plus/cp-except.c +++ /dev/null @@ -1,1221 +0,0 @@ -/* Handle exceptional things in C++. - Copyright (C) 1989, 1992, 1993 Free Software Foundation, Inc. - Contributed by Michael Tiemann (tiemann@cygnus.com) - -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, 675 Mass Ave, Cambridge, MA 02139, USA. */ - - -/* High-level class interface. */ - -#include "config.h" -#include "tree.h" -#include "rtl.h" -#include "cp-tree.h" -#include "flags.h" -/* On Suns this can get you to the right definition if you - set the right value for TARGET. */ -#include <setjmp.h> -#ifdef sequent -/* Can you believe they forgot this? */ -#define _JBLEN 11 -#endif - -#ifndef _JBLEN -#define _JBLEN (sizeof(jmp_buf)/sizeof(int)) -#endif - -#undef NULL -#define NULL (char *)0 - -/* This should be part of `ansi_opname', or at least be defined by the std. */ -#define EXCEPTION_NAME_PREFIX "__ex" -#define EXCEPTION_NAME_LENGTH 4 - -void init_exception_processing (); -void init_exception_processing_1 (); - -/* If non-zero, a VAR_DECL whose cleanup will cause a throw to the - next exception handler. Its value says whether to throw or not. - In the case of functions which do not issue a RAISE, it should be - possible to optimize away this VAR_DECL (and overhead associated - with it). */ -tree exception_throw_decl; -/* Use this to know that we did not set `exception_throw_decl', - until GCC optimizer is smart enough to figure it out for itself. */ -int sets_exception_throw_decl; - -/* The exception `type' currently in scope, or NULL_TREE if none. */ -tree current_exception_type; - -/* The exception handler object for the given scope. */ -tree current_exception_decl; -rtx current_exception_name_as_rtx; -rtx current_exception_parms_as_rtx; - -/* The ``object'' view of the current exception parameters. - We cast up from the `parms' field to `current_exception_type'. */ -tree current_exception_object; - -/* Cache `setjmp', `longjmp', `raise_exception', and `unhandled_exception' - after default conversion. Maybe later they will get built-in. */ -static tree BISJ, BILJ, BIR, BIUE; - -/* Local variables which give the appearance that exception - handling is part of the language and the execution model. */ - -/* The type of the exception handler stack. */ -static tree EHS_type; - -/* The global handler stack. */ -tree EHS_decl; - -/* Cached component refs to fields of `EHS_decl'. */ -static tree EHS_prev, EHS_handler, EHS_parms, EHS_name; -static rtx EHS_parms_as_rtx, EHS_name_as_rtx; - -/* The parameter names of this exception type. */ - -static tree last_exception_fields; -static tree last_exception_field_types; - -/* When ID is VOID_TYPE_NODE, it means ``raise all''. - Cannot be inline, since it uses `alloca', and that - breaks code which pushes the result of this function - on the stack. */ -static tree -exception_object_name (prefix, id) - tree prefix; - tree id; -{ - /* First, cons up the `name' of this exception. */ - char *name; - int length = (id == void_type_node ? 3 : IDENTIFIER_LENGTH (id)) + EXCEPTION_NAME_LENGTH; - - if (prefix) - length += IDENTIFIER_LENGTH (prefix) + 2; - - name = (char *)alloca (length); - strcpy (name, EXCEPTION_NAME_PREFIX); - length = EXCEPTION_NAME_LENGTH; - if (prefix) - { - strcpy (name + length, IDENTIFIER_POINTER (prefix)); -#ifdef JOINER - name[length + IDENTIFIER_LENGTH (prefix)] = JOINER; -#else - name[length + IDENTIFIER_LENGTH (prefix)] = '_'; -#endif - length += IDENTIFIER_LENGTH (prefix) + 1; - } - if (id == void_type_node) - strcpy (name + length, "all"); - else - strcpy (name + length, IDENTIFIER_POINTER (id)); - return get_identifier (name); -} - -tree -lookup_exception_cname (ctype, cname, raise_id) - tree ctype, cname; - tree raise_id; -{ - tree this_cname = TREE_PURPOSE (raise_id); - if (this_cname == NULL_TREE) - { - if (cname) - { - tree name = TREE_VALUE (raise_id); - if (purpose_member (name, CLASSTYPE_TAGS (ctype))) - this_cname = cname; - } - } - else if (this_cname == void_type_node) - this_cname = NULL_TREE; - else if (TREE_CODE (this_cname) != IDENTIFIER_NODE) - { - sorry ("multiple scope refs in `cplus_expand_raise_stmt'"); - this_cname = error_mark_node; - } - return this_cname; -} - -tree -lookup_exception_tname (oname) - tree oname; -{ - return get_identifier (IDENTIFIER_POINTER (oname) + EXCEPTION_NAME_LENGTH); -} - -tree -lookup_exception_object (cname, name, complain) - tree cname, name; - int complain; -{ - tree oname; - tree decl; - - if (cname == void_type_node) - cname = NULL_TREE; - else if (cname && TREE_CODE (cname) != IDENTIFIER_NODE) - { - sorry ("multiple scope refs in `lookup_exception_object'"); - cname = NULL_TREE; - } - oname = exception_object_name (cname, name); - decl = IDENTIFIER_GLOBAL_VALUE (oname); - if (decl == NULL_TREE || TREE_CODE (decl) != VAR_DECL) - { - if (complain) - { - push_obstacks_nochange (); - - if (cname) - error ("no exception name object for name `%s::%s'", - IDENTIFIER_POINTER (cname), - IDENTIFIER_POINTER (name)); - else - error ("no exception name object for name `%s'", - IDENTIFIER_POINTER (name)); - end_temporary_allocation (); - /* Avoid further error messages. */ - pushdecl_top_level (build_lang_field_decl (VAR_DECL, - exception_object_name (cname, name), - error_mark_node)); - pop_obstacks (); - } - return NULL_TREE; - } - return decl; -} - -tree -lookup_exception_type (ctype, cname, raise_id) - tree ctype, cname; - tree raise_id; -{ - tree name = TREE_VALUE (raise_id); - tree purpose = TREE_PURPOSE (raise_id); - - if (cname && purpose == NULL_TREE) - purpose = cname; - - if (purpose && purpose != void_type_node) - { - tree link = NULL_TREE; - - if (TREE_CODE (purpose) != IDENTIFIER_NODE) - { - sorry ("multiple scope refs in `lookup_exception_type'"); - TREE_PURPOSE (raise_id) = NULL_TREE; - return NULL_TREE; - } - if (! is_aggr_typedef (purpose, 1)) - return NULL_TREE; - ctype = IDENTIFIER_TYPE_VALUE (purpose); - link = purpose_member (name, CLASSTYPE_TAGS (ctype)); - if (link) - return TREE_VALUE (link); - } - - ctype = lookup_name (name, 1); - if (ctype && TREE_CODE (ctype) == TYPE_DECL) - ctype = TREE_TYPE (ctype); - if (ctype && TREE_CODE (ctype) == RECORD_TYPE - && CLASSTYPE_DECLARED_EXCEPTION (ctype)) - return ctype; - return NULL_TREE; -} - -tree -finish_exception (e, list_of_fieldlists) - tree e; - tree list_of_fieldlists; -{ - tree parmtypes = NULL_TREE, name_field; - tree cname = TYPE_NAME (e); - - if (TREE_CODE (cname) == TYPE_DECL) - cname = DECL_NAME (cname); - - if (last_exception_fields) - error ("cannot declare exceptions within exceptions"); - if (list_of_fieldlists && ! ANON_AGGRNAME_P (cname)) - error_with_aggr_type (e, "exception name `%s' must follow body declaration"); - if (list_of_fieldlists) - { - tree prev, field; - - /* Note: no public, private, or protected allowed. */ - if (TREE_CHAIN (list_of_fieldlists)) - error ("visibility declarations invalid in exception declaration"); - else if (TREE_PURPOSE (list_of_fieldlists) != (tree)visibility_default) - error ("visibility declarations invalid in exception declaration"); - TREE_PURPOSE (list_of_fieldlists) = (tree)visibility_default; - - /* Note also: no member function declarations allowed. */ - for (prev = 0, field = TREE_VALUE (list_of_fieldlists); - field; prev = field, field = TREE_CHAIN (field)) - { - switch (TREE_CODE (field)) - { - case FIELD_DECL: - /* ok. */ - parmtypes = tree_cons (NULL_TREE, TREE_TYPE (field), parmtypes); - continue; - case FUNCTION_DECL: - error_with_decl (field, "declaration of function `%s' in exception invalid"); - break; - case VAR_DECL: - if (TREE_STATIC (field)) - error_with_decl (field, "declaration of static variable `%s' in exception invalid"); - else - error_with_decl (field, "declaration of constant field `%s' in exception invalid"); - break; - case CONST_DECL: - error_with_decl (field, "declaration of enum value `%s' in exception invalid"); - break; - case SCOPE_REF: - error ("use of `::' in exception context invalid"); - break; - } - if (prev) - TREE_CHAIN (prev) = TREE_CHAIN (field); - else - TREE_VALUE (list_of_fieldlists) = TREE_CHAIN (field); - } - } - - /* Now that we've cleaned up the fields, add a name identifier at front. */ - name_field = build_lang_field_decl (FIELD_DECL, get_identifier ("__name"), - ptr_type_node); - if (list_of_fieldlists) - { - TREE_CHAIN (name_field) = TREE_VALUE (list_of_fieldlists); - TREE_VALUE (list_of_fieldlists) = name_field; - } - else - list_of_fieldlists = build_tree_list (NULL_TREE, name_field); - - last_exception_fields = TREE_VALUE (list_of_fieldlists); - if (parmtypes) - { - last_exception_field_types = nreverse (parmtypes); - /* Set the TREE_CHAIN of what is now at the end of the - list to `void_list_node'. */ - TREE_CHAIN (parmtypes) = void_list_node; - } - else - last_exception_field_types = void_list_node; - - popclass (0); - -#if 0 - /* Remove aggregate types from the list of tags, - since these appear at global scope. */ - while (x && IS_AGGR_TYPE (TREE_VALUE (x))) - x = TREE_CHAIN (x); - CLASSTYPE_TAGS (t) = x; - y = x; - while (x) - { - if (IS_AGGR_TYPE (TREE_VALUE (x))) - TREE_CHAIN (y) = TREE_CHAIN (x); - x = TREE_CHAIN (x); - } -#endif - - if (flag_cadillac) - cadillac_finish_exception (e); - - return e; -} - -void -finish_exception_decl (cname, decl) - tree cname, decl; -{ - /* In cp-decl.h. */ - extern tree last_function_parms; - - /* An exception declaration. */ - tree t, ctor; - tree parmdecls = NULL_TREE, fields; - tree list_of_fieldlists = temp_tree_cons (NULL_TREE, - copy_list (last_exception_fields), - NULL_TREE); - tree edecl = build_lang_field_decl (VAR_DECL, - exception_object_name (cname, DECL_NAME (decl)), - ptr_type_node); - - DECL_LANGUAGE (edecl) = lang_c; - TREE_STATIC (edecl) = 1; - TREE_PUBLIC (edecl) = 1; - finish_decl (pushdecl (edecl), NULL_TREE, NULL_TREE, 0); - - /* Now instantiate the exception decl. */ - t = xref_tag (exception_type_node, DECL_NAME (decl), NULL_TREE); - - /* finish_struct will pop this. */ - pushclass (t, 0); - - /* Now add a constructor which takes as parameters all the types we - just defined. */ - ctor = build_lang_decl (FUNCTION_DECL, DECL_NAME (decl), - build_cplus_method_type (t, TYPE_POINTER_TO (t), - last_exception_field_types)); - /* Don't take `name'. The constructor handles that. */ - fields = TREE_CHAIN (TREE_VALUE (list_of_fieldlists)); - while (fields) - { - tree parm = build_decl (PARM_DECL, DECL_NAME (fields), TREE_TYPE (fields)); - /* Since there is a prototype, args are passed in their own types. */ - DECL_ARG_TYPE (parm) = TREE_TYPE (parm); -#ifdef PROMOTE_PROTOTYPES - if (TREE_CODE (TREE_TYPE (fields)) == INTEGER_TYPE - && TYPE_PRECISION (TREE_TYPE (fields)) < TYPE_PRECISION (integer_type_node)) - DECL_ARG_TYPE (parm) = integer_type_node; -#endif - TREE_CHAIN (parm) = parmdecls; - parmdecls = parm; - fields = TREE_CHAIN (fields); - } - fields = TREE_VALUE (list_of_fieldlists); - last_function_parms = nreverse (parmdecls); - - DECL_CONSTRUCTOR_P (ctor) = 1; - TYPE_HAS_CONSTRUCTOR (t) = 1; - grokclassfn (t, DECL_NAME (decl), ctor, NO_SPECIAL, NULL_TREE); - DECL_EXTERNAL (ctor) = 1; - TREE_STATIC (ctor) = 1; - TREE_PUBLIC (ctor) = 0; - DECL_INLINE (ctor) = 1; - make_decl_rtl (ctor, NULL_PTR, 1); - finish_decl (ctor, NULL_TREE, NULL_TREE, 0); - TREE_CHAIN (ctor) = TREE_VALUE (list_of_fieldlists); - TREE_VALUE (list_of_fieldlists) = ctor; - - finish_struct (t, list_of_fieldlists, 0); - - if (current_function_decl) - error ("cannot define exception inside function scope"); - else - { - enum debug_info_type old_write_symbols = write_symbols; - write_symbols = NO_DEBUG; - - /* Now build the constructor for this exception. */ - parmdecls = DECL_ARGUMENTS (ctor); - start_function (NULL_TREE, ctor, 0, 1); - store_parm_decls (); - pushlevel (0); - clear_last_expr (); - push_momentary (); - expand_start_bindings (0); - - /* Move all the parameters to the fields, skipping `this'. */ - parmdecls = TREE_CHAIN (parmdecls); - /* Install `name' of this exception handler. */ - DECL_INITIAL (fields) = build_unary_op (ADDR_EXPR, edecl, 0); - fields = TREE_CHAIN (fields); - /* Install all the values. */ - while (fields) - { - /* Set up the initialization for this field. */ - DECL_INITIAL (fields) = parmdecls; - fields = TREE_CHAIN (fields); - parmdecls = TREE_CHAIN (parmdecls); - } - emit_base_init (t, 0); - - finish_function (DECL_SOURCE_LINE (ctor), 1); - write_symbols = old_write_symbols; - } -} - -void -end_exception_decls () -{ - last_exception_field_types = NULL_TREE; - last_exception_fields = NULL_TREE; -} - -/* Statement-level exception semantics. */ - -void -cplus_expand_start_try (implicit) - int implicit; -{ - tree call_to_setjmp; - tree handler, ref; - - /* Start a new block enclosing the whole handler. */ - if (implicit) - { - pushlevel_temporary (1); - } - else - { - pushlevel (0); - clear_last_expr (); - push_momentary (); - - /* Encompass whole exception handler in one big binding contour. - If RAISE should throw out of the whole TRY/EXCEPT block, call - `expand_start_bindings' with argument of 1. */ - expand_start_bindings (0); - } - - /* Allocate handler in that block. It's real name will come later. - Note that it will be the first name in this binding contour. */ - handler = get_temp_name (EHS_type, 0); - DECL_INITIAL (handler) = error_mark_node; - finish_decl (handler, NULL_TREE, NULL_TREE, 0); - - /* Must come after call to `finish_decl', else the cleanup for the temp - for the handler will cause the contour we just created to be popped. */ - if (implicit) - declare_implicit_exception (); - - /* Catch via `setjmp'. */ - ref = build_component_ref (handler, get_identifier ("handler"), NULL_TREE, 0); - call_to_setjmp = build_function_call (BISJ, build_tree_list (NULL_TREE, ref)); - - /* RAISE throws to EXCEPT part. */ - expand_start_try (build_binary_op (EQ_EXPR, call_to_setjmp, integer_zero_node, 1), 0, 1); -} - -/* If KEEP is 1, then declarations in the TRY statement are worth keeping. - If KEEP is 2, then the TRY statement was generated by the compiler. - If KEEP is 0, the declarations in the TRY statement contain errors. */ - -tree -cplus_expand_end_try (keep) - int keep; -{ - tree decls, decl, block; - - if (keep < 2) - pop_implicit_try_blocks (NULL_TREE); - - decls = getdecls (); - - /* Emit code to avoid falling through into a default - handler that might come later. */ - expand_end_try (); - - /* Pops binding contour local to TRY, and get the exception handler - object built by `...start_try'. */ - switch (keep) - { - case 0: - expand_end_bindings (decls, 0, 1); - block = poplevel (0, 0, 0); - pop_momentary (); - decl = getdecls (); - break; - - case 1: - expand_end_bindings (decls, 1, 1); - block = poplevel (1, 1, 0); - pop_momentary (); - decl = getdecls (); - break; - - default: - decl = tree_last (decls); - block = NULL_TREE; - break; - } - - my_friendly_assert (TREE_CODE (decl) == VAR_DECL - && TREE_TYPE (decl) == EHS_type, 203); - if (block) - { - BLOCK_HANDLER_BLOCK (block) = 1; - TREE_USED (block) = 1; - } - - /* Pass it back so that its rtl can be bound to its name - (or vice versa). */ - return decl; -} - -void -cplus_expand_start_except (name, decl) - tree name, decl; -{ - int yes; - tree tmp, init; - - expand_start_except (0, 1); - - /* This is internal `eh'. */ - current_exception_decl = decl; - current_exception_name_as_rtx - = expand_expr (build (COMPONENT_REF, ptr_type_node, - current_exception_decl, TREE_OPERAND (EHS_name, 1)), - 0, 0, 0); - init = build (COMPONENT_REF, ptr_type_node, decl, TREE_OPERAND (EHS_parms, 1)); - current_exception_parms_as_rtx = expand_expr (init, 0, 0, 0); - - if (name) - { - /* Get the exception object into scope (user declared `ex'). */ - tmp = pushdecl (build_decl (VAR_DECL, name, ptr_type_node)); - DECL_INITIAL (tmp) = error_mark_node; - finish_decl (tmp, init, 0, 0); - } - current_exception_type = NULL_TREE; - yes = suspend_momentary (); - if (name) - { - /* From now on, send the user to our faked-up object. */ - current_exception_object = build1 (INDIRECT_REF, void_type_node, tmp); - IDENTIFIER_LOCAL_VALUE (name) = current_exception_object; - } - resume_momentary (yes); - - /* Pop exception handler stack. */ - expand_assignment (EHS_decl, EHS_prev, 0, 0); -} - -/* Generate the call to `unhandled_exception' that is appropriate - for this particular unhandled exception. */ -static tree -call_to_unhandled_exception () -{ - extern int lineno; - extern tree combine_strings (); - tree parms = tree_cons (NULL_TREE, - combine_strings (build_string (strlen (input_filename + 1), input_filename)), - build_tree_list (NULL_TREE, build_int_2 (lineno, 0))); - return build_function_call (BIUE, parms); -} - -/* Note that this must be mirror image of `...start_try'. - DFAULT is the default clause, if there was one. - DFAULT is ERROR_MARK_NODE when this ends an implicit handler. */ -void -cplus_expand_end_except (dfault) - tree dfault; -{ - extern tree expand_end_except (); /* stmt.c. */ - tree decls, raised; - - if (dfault == NULL_TREE) - { - /* Uncaught exception at outermost level. If raised locally, - reraise the exception. Otherwise, generate code to call `abort'. */ - if (in_try_block (1) == 0) - { - expand_start_cond (build (EQ_EXPR, integer_type_node, - exception_throw_decl, integer_zero_node), 0); - expand_expr (call_to_unhandled_exception (), 0, VOIDmode, 0); - expand_end_cond (); - } - /* Try the next handler. */ - if (! expand_escape_except ()) - compiler_error ("except nesting botch"); - } - - raised = expand_end_except (); - - decls = getdecls (); - expand_end_bindings (decls, decls != 0, 1); - poplevel (decls != 0, 1, 0); - - /* Implicit handlers do not use the momentary obstack. */ - if (dfault != error_mark_node) - pop_momentary (); - - if (! in_try_block (1)) - { - /* Check that this function is not raising exceptions - it is not supposed to. */ - while (raised) - { - error_with_decl (TREE_VALUE (raised), "exception `%s' raised but not declared raisable"); - raised = TREE_CHAIN (raised); - } - } - else if (dfault == NULL_TREE || dfault == error_mark_node) - { - expand_start_cond (build (NE_EXPR, integer_type_node, - exception_throw_decl, - integer_zero_node), 0); - /* We fell off the end of this try block. Try going to the next. - The escape_label will be the beginning of the next try block. */ - if (! expand_escape_except ()) - compiler_error ("except nesting botch"); - expand_end_cond (); - } -} - -/* Generate code to raise exception RAISE_ID. - If EXP is NULL_TREE, then PARMS is the list of parameters to use - for constructing this exception. - If EXP is non-NULL, then it is an already constructed object - of the kind that we want. - - FOR_RERAISE is non-zero if this raise is called by reraise. In - this case we do not need to emit extra gotos to avoid warning messages; - the caller will do that once after all the exceptions it reraises - are handled and raised. */ -void -cplus_expand_raise (raise_id, parms, exp, for_reraise) - tree raise_id; - tree parms; - tree exp; - int for_reraise; -{ - /* Allocate new exception of appropriate type, passing - PARMS to its constructor. */ - tree cname, name; - tree decl; - tree xexp = exp; - - cname = lookup_exception_cname (current_class_type, current_class_name, raise_id); - if (cname == error_mark_node) - return; - name = TREE_VALUE (raise_id); - - decl = lookup_exception_object (cname, name, 1); - if (decl == NULL_TREE) - return; - - if (exp == NULL_TREE) - { - exp = build_method_call (NULL_TREE, name, parms, NULL_TREE, LOOKUP_COMPLAIN); - if (exp == error_mark_node) - return; - } - - if (in_try_block (1)) - { - expand_raise (decl); - } - else if (! current_function_decl) - { - if (xexp == NULL_TREE) - error_with_decl (decl, "invalid raise of `%s' outside of functions"); - else - error_with_decl (decl, "invalid reraise of `%s' outside of functions"); - } - else - { - /* Test this raise against what this function permits. */ - tree names = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)); - while (names) - { - if (decl == TREE_TYPE (names)) - break; - names = TREE_CHAIN (names); - } - if (names == NULL_TREE) - { - error ("current function not declared to raise exception `%s'", - IDENTIFIER_POINTER (name)); - return; - } - } - - store_expr (exp, EHS_parms_as_rtx, 0); - - /* Set the global exception handler stack's NAME field - to the `name' of this exception. The global exception - handler stack is the container for the exception object - we just built. - - We go through a function call to make life easier when debugging. */ -#if 0 - expand_assignment (EHS_name, build_unary_op (ADDR_EXPR, decl, 0), 0, 0); -#else - parms = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, EHS_name, 0), - build_tree_list (NULL_TREE, - build_unary_op (ADDR_EXPR, decl, 0))); - expand_expr (build_function_call (BIR, parms), 0, 0, 0); -#endif - - /* Activate thrower. If we are inside a TRY statement, - we can cheat and not do this, saving a longjmp. */ - if (in_try_block (1) == 0) - { - sets_exception_throw_decl = 1; - emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx); - } - - if (xexp == NULL_TREE) - { - /* Invoke destructors for current procedure or handler. */ - if (! expand_escape_except ()) - compiler_error ("except nesting botch"); - /* Throw via `longjmp'... Done as side-effect of goto. */ - } - /* To avoid spurious warning messages, we add a goto to the end - of the function. This code is dead, and the compiler should - know how to delete it, but for now, we are stuck with it. */ - if (! for_reraise - && TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node) - expand_null_return (); -} - -extern tree cplus_exception_name (); - -tree -ansi_exception_object_lookup (type) - tree type; -{ - tree raise_id = cplus_exception_name (type); - tree decl; - - decl = IDENTIFIER_GLOBAL_VALUE (raise_id); - if (decl == NULL_TREE || TREE_CODE (decl) != VAR_DECL) - { - push_obstacks_nochange (); - end_temporary_allocation (); - decl = build_decl (VAR_DECL, raise_id, ptr_type_node); - TREE_PUBLIC (decl) = 1; - TREE_STATIC (decl) = 1; - pushdecl_top_level (decl); - make_decl_rtl (decl, (char*)0, 1); - pop_obstacks (); - } - return decl; -} - -/* Generate code to throw an exception using EXP. - Usng ANSI syntax and semantics. - If EXP is NULL_TREE< re-raise instead. */ - -void -cplus_expand_throw (exp) - tree exp; -{ - tree parms; - int for_reraise; - /* Allocate new exception of appropriate type, passing - PARMS to its constructor. */ - tree decl = ansi_exception_object_lookup (TREE_TYPE (exp)); - tree xexp = exp; - - if (in_try_block (1)) - { -#if 1 - my_friendly_abort (35); -#else - expand_raise (decl); -#endif - } - else if (! current_function_decl) - error ("invalid throw outside of functions"); - else - { -#if 0 - /* Test this raise against what this function permits. */ - tree names = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)); - while (names) - { - if (decl == TREE_TYPE (names)) - break; - names = TREE_CHAIN (names); - } - if (names == NULL_TREE) - { - error ("current function not declared to raise exception `%s'", - IDENTIFIER_POINTER (name)); - return; - } -#endif - } - - store_expr (exp, EHS_parms_as_rtx, 0); - - /* Set the global exception handler stack's NAME field - to the `name' of this exception. The global exception - handler stack is the container for the exception object - we just built. - - We go through a function call to make life easier when debugging. */ -#if 0 - expand_assignment (EHS_name, build_unary_op (ADDR_EXPR, decl, 0), 0, 0); -#else - parms = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, EHS_name, 0), - build_tree_list (NULL_TREE, - build_unary_op (ADDR_EXPR, decl, 0))); - expand_expr (build_function_call (BIR, parms), 0, 0, 0); -#endif - - /* Activate thrower. If we are inside a TRY statement, - we can cheat and not do this, saving a longjmp. */ - if (in_try_block (1) == 0) - { - sets_exception_throw_decl = 1; - emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx); - } - - if (xexp == NULL_TREE) - { - /* Invoke destructors for current procedure or handler. */ - if (! expand_escape_except ()) - compiler_error ("except nesting botch"); - /* Throw via `longjmp'... Done as side-effect of goto. */ - } - - /* XXX: for_reraise is never set above here. */ - /* To avoid spurious warning messages, we add a goto to the end - of the function. This code is dead, and the compiler should - know how to delete it, but for now, we are stuck with it. */ - if (! for_reraise - && TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node) - expand_null_return (); -} - -tree -cplus_expand_start_catch (raise_id) - tree raise_id; -{ - tree cname = lookup_exception_cname (current_class_type, current_class_name, raise_id); - tree decl; - tree cond; - - if (cname == error_mark_node) - { - decl = error_mark_node; - cond = error_mark_node; - } - else - { - decl = lookup_exception_object (cname, TREE_VALUE (raise_id), 1); - if (decl == NULL_TREE) - cond = error_mark_node; - else - cond = build_binary_op (EQ_EXPR, build_unary_op (ADDR_EXPR, decl, 0), - build (COMPONENT_REF, ptr_type_node, - current_exception_decl, - TREE_OPERAND (EHS_name, 1)), - 1); - } - expand_start_cond (cond, 0); - - /* Does nothing right now. */ - expand_catch (decl); - if (current_exception_type - && TYPE_NEEDS_DESTRUCTOR (current_exception_type)) - { - /* Make a cleanup for the name-specific exception object now in scope. */ - tree cleanup = maybe_build_cleanup (current_exception_object); - expand_start_bindings (0); - expand_decl_cleanup (NULL_TREE, cleanup); - } - return decl; -} -tree -ansi_expand_start_catch (raise_type) - tree raise_type; -{ - tree decl = ansi_exception_object_lookup (raise_type); - tree cond; - - if (decl == NULL_TREE) - cond = error_mark_node; - else - cond = build_binary_op (EQ_EXPR, build_unary_op (ADDR_EXPR, decl, 0), - build (COMPONENT_REF, ptr_type_node, - current_exception_decl, - TREE_OPERAND (EHS_name, 1)), - 1); - expand_start_cond (cond, 0); - - /* Does nothing right now. */ - expand_catch (decl); - return decl; -} - -void -cplus_expand_end_catch (for_reraise) - int for_reraise; -{ - if (current_exception_type - && TYPE_NEEDS_DESTRUCTOR (current_exception_type)) - { - /* Destroy the specific exception object now in scope. */ - expand_end_bindings (getdecls (), 0, 1); - } - if (for_reraise) - { - if (! expand_escape_except ()) - my_friendly_abort (36); - } - else - { - if (! expand_end_catch ()) - my_friendly_abort (37); - } - expand_end_cond (); -} - -/* Reraise an exception. - If EXCEPTIONS is NULL_TREE, it means reraise whatever exception was caught. - If EXCEPTIONS is an IDENTIFIER_NODE, it means reraise the exception - object named by EXCEPTIONS. This must be a variable declared in - an `except' clause. - If EXCEPTIONS is a TREE_LIST, it is the list of exceptions we are - willing to reraise. */ - -void -cplus_expand_reraise (exceptions) - tree exceptions; -{ - tree ex_ptr; - tree ex_object = current_exception_object; - rtx ex_ptr_as_rtx; - - if (exceptions && TREE_CODE (exceptions) == IDENTIFIER_NODE) - { - /* Don't get tripped up if its TREE_TYPE is `error_mark_node'. */ - ex_object = IDENTIFIER_LOCAL_VALUE (exceptions); - if (ex_object == NULL_TREE || TREE_CODE (ex_object) != INDIRECT_REF) - { - error ("`%s' is not an exception decl", IDENTIFIER_POINTER (exceptions)); - return; - } - my_friendly_assert (TREE_CODE (TREE_OPERAND (ex_object, 0)) == VAR_DECL, - 204); - exceptions = NULL_TREE; - } - - ex_ptr = build1 (NOP_EXPR, ptr_type_node, TREE_OPERAND (ex_object, 0)); - ex_ptr_as_rtx = expand_expr (ex_ptr, 0, 0, 0); - - /* reraise ALL, used by compiler. */ - if (exceptions == NULL_TREE) - { - /* Now treat reraise like catch/raise. */ - expand_catch (error_mark_node); - expand_raise (error_mark_node); - emit_move_insn (EHS_name_as_rtx, current_exception_name_as_rtx); - store_expr ((tree) EHS_parms_as_rtx, current_exception_parms_as_rtx, 0); - if (in_try_block (1) == 0) - { - sets_exception_throw_decl = 1; - emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx); - } - /* Set to zero so that destructor will not be called. */ - emit_move_insn (ex_ptr_as_rtx, const0_rtx); - if (! expand_escape_except ()) - my_friendly_abort (38); - - /* To avoid spurious warning messages, we add a goto to the end - of the function. This code is dead, and the compiler should - know how to delete it, but for now, we are stuck with it. */ - if (TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node) - expand_null_return (); - - return; - } - - /* reraise from a list of exceptions. */ - while (exceptions) - { - tree type = lookup_exception_type (current_class_type, current_class_name, - exceptions); - if (type == NULL_TREE) - { - error ("`%s' is not an exception type", - IDENTIFIER_POINTER (TREE_VALUE (exceptions))); - current_exception_type = NULL_TREE; - TREE_TYPE (ex_object) = error_mark_node; - TREE_TYPE (ex_ptr) = error_mark_node; - } - else - { - current_exception_type = type; - /* In-place union. */ - TREE_TYPE (ex_object) = type; - TREE_TYPE (ex_ptr) = TYPE_POINTER_TO (type); - } - - /* Now treat reraise like catch/raise. */ - cplus_expand_start_catch (exceptions); - cplus_expand_raise (exceptions, NULL_TREE, ex_ptr, 1); - /* Set to zero so that destructor will not be called. */ - if (TREE_TYPE (ex_ptr) != error_mark_node) - emit_move_insn (ex_ptr_as_rtx, const0_rtx); - cplus_expand_end_catch (1); - exceptions = TREE_CHAIN (exceptions); - } - /* Don't propagate any unhandled exceptions. */ - expand_expr (call_to_unhandled_exception (), 0, VOIDmode, 0); - - /* To avoid spurious warning messages, we add a goto to the end - of the function. This code is dead, and the compiler should - know how to delete it, but for now, we are stuck with it. */ - if (TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node) - expand_null_return (); -} - -void -setup_exception_throw_decl () -{ - tree call_to_longjmp, parms; - - int old = suspend_momentary (); - - exception_throw_decl = build_decl (VAR_DECL, get_identifier (THROW_NAME), integer_type_node); - pushdecl (exception_throw_decl); - parms = tree_cons (NULL_TREE, EHS_handler, - build_tree_list (0, integer_one_node)); - call_to_longjmp = build_function_call (BILJ, parms); - - expand_decl (exception_throw_decl); - expand_decl_cleanup (exception_throw_decl, - build (COND_EXPR, void_type_node, - exception_throw_decl, - call_to_longjmp, integer_zero_node)); - DECL_INITIAL (exception_throw_decl) = integer_zero_node; - sets_exception_throw_decl = 0; - resume_momentary (old); - - /* Cache these, since they won't change throughout the function. */ - EHS_parms_as_rtx = expand_expr (EHS_parms, 0, 0, 0); - EHS_name_as_rtx = expand_expr (EHS_name, 0, 0, 0); -} - -void -init_exception_processing () -{ - extern tree build_function_type (), define_function (); - extern tree unhandled_exception_fndecl; - tree cname = get_identifier ("ExceptionHandler"); - tree field, chain; - tree ctor, dtor; - tree jmp_buf_type = build_array_type (integer_type_node, - build_index_type (build_int_2 (_JBLEN-1, 0))); - tree jmp_buf_arg_type = build_pointer_type (integer_type_node); - - tree parmtypes = hash_tree_chain (jmp_buf_arg_type, void_list_node); - tree setjmp_fndecl, longjmp_fndecl, raise_fndecl; - - int old_interface_only = interface_only; - int old_interface_unknown = interface_unknown; - interface_only = 1; - interface_unknown = 0; - EHS_type = xref_tag (record_type_node, cname, NULL_TREE); - push_lang_context (lang_name_c); - setjmp_fndecl = define_function ("setjmp", - build_function_type (integer_type_node, - parmtypes), - NOT_BUILT_IN, pushdecl, 0); - BISJ = default_conversion (setjmp_fndecl); - parmtypes = hash_tree_chain (jmp_buf_arg_type, - hash_tree_chain (integer_type_node, void_list_node)); - longjmp_fndecl = define_function ("longjmp", - build_function_type (void_type_node, parmtypes), - NOT_BUILT_IN, pushdecl, 0); - raise_fndecl = define_function ("__raise_exception", - build_function_type (void_type_node, - hash_tree_chain (ptr_type_node, - hash_tree_chain (build_pointer_type (ptr_type_node), void_list_node))), - NOT_BUILT_IN, pushdecl, 0); - BILJ = default_conversion (longjmp_fndecl); - BIR = default_conversion (raise_fndecl); - BIUE = default_conversion (unhandled_exception_fndecl); - - pop_lang_context (); - - /* finish_struct will pop this. */ - pushclass (EHS_type, 0); - field = build_lang_field_decl (FIELD_DECL, get_identifier ("parms"), ptr_type_node); - chain = field; - field = build_lang_field_decl (FIELD_DECL, get_identifier ("name"), - build_pointer_type (default_function_type)); - TREE_CHAIN (field) = chain; - chain = field; - field = build_lang_field_decl (FIELD_DECL, get_identifier ("handler"), jmp_buf_type); - TREE_CHAIN (field) = chain; - chain = field; - field = build_lang_field_decl (FIELD_DECL, get_identifier ("prev"), - TYPE_POINTER_TO (EHS_type)); - TREE_CHAIN (field) = chain; - chain = field; - - ctor = build_lang_decl (FUNCTION_DECL, cname, - build_cplus_method_type (EHS_type, TYPE_POINTER_TO (EHS_type), void_list_node)); - DECL_CONSTRUCTOR_P (ctor) = 1; - TREE_STATIC (ctor) = 1; - TREE_PUBLIC (ctor) = 1; - DECL_EXTERNAL (ctor) = 1; - grokclassfn (EHS_type, cname, ctor, NO_SPECIAL, 0); - grok_ctor_properties (EHS_type, ctor); - finish_decl (pushdecl (ctor), NULL_TREE, NULL_TREE, 0); - /* Must copy the node here because the FUNCTION_DECL - used inside the struct ain't the same as the - FUNCTION_DECL we stick into the global binding - contour. */ - ctor = copy_node (ctor); - TREE_CHAIN (ctor) = chain; - chain = ctor; - dtor = build_lang_decl (FUNCTION_DECL, cname, - build_cplus_method_type (EHS_type, TYPE_POINTER_TO (EHS_type), void_list_node)); - TREE_STATIC (dtor) = 1; - TREE_PUBLIC (dtor) = 1; - DECL_EXTERNAL (dtor) = 1; - grokclassfn (EHS_type, cname, dtor, DTOR_FLAG, 0); - finish_decl (pushdecl (dtor), NULL_TREE, NULL_TREE, 0); - /* Copy for the same reason as copying ctor. */ - dtor = copy_node (dtor); - TREE_CHAIN (dtor) = chain; - chain = dtor; - TYPE_HAS_CONSTRUCTOR (EHS_type) = 1; - TYPE_HAS_DESTRUCTOR (EHS_type) = 1; - finish_struct (EHS_type, temp_tree_cons (NULL_TREE, chain, NULL_TREE), 0); - interface_only = old_interface_only; - interface_unknown = old_interface_unknown; -} - -void -init_exception_processing_1 () -{ - register tree EHS_id = get_identifier ("exceptionHandlerStack"); - - EHS_decl = IDENTIFIER_GLOBAL_VALUE (EHS_id); - - /* If we have no other definition, default to library implementation. */ - if (EHS_decl == NULL_TREE) - { - EHS_decl = build_decl (VAR_DECL, EHS_id, TYPE_POINTER_TO (EHS_type)); - /* If we don't push this, its definition, should it be encountered, - will not be seen. */ - EHS_decl = pushdecl (EHS_decl); - DECL_EXTERNAL (EHS_decl) = 1; - TREE_STATIC (EHS_decl) = 1; - TREE_PUBLIC (EHS_decl) = 1; - finish_decl (EHS_decl, NULL_TREE, NULL_TREE, 0); - } - else if (TREE_CODE (EHS_decl) != VAR_DECL - || TREE_TYPE (EHS_decl) != TYPE_POINTER_TO (EHS_type)) - fatal ("exception handling declarations conflict with compiler's internal model"); - - if (EHS_prev == NULL_TREE) - { - register tree EHS_DECL = build1 (INDIRECT_REF, EHS_type, EHS_decl); - EHS_prev = build_component_ref (EHS_DECL, get_identifier ("prev"), 0, 0); - EHS_handler = build_component_ref (EHS_DECL, get_identifier ("handler"), 0, 0); - EHS_parms = build_component_ref (EHS_DECL, get_identifier ("parms"), 0, 0); - EHS_name = build_component_ref (EHS_DECL, get_identifier ("name"), 0, 0); - } -} |
