| // Functions for Exception Support for -*- C++ -*- |
| // Copyright (C) 1994, 1995, 1996 Free Software Foundation |
| |
| // 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. |
| |
| // As a special exception, if you link this library with other files, |
| // some of which are compiled with GCC, to produce an executable, |
| // this library does not by itself cause the resulting executable |
| // to be covered by the GNU General Public License. |
| // This exception does not however invalidate any other reasons why |
| // the executable file might be covered by the GNU General Public License. |
| |
| #pragma implementation "exception" |
| |
| #include "typeinfo" |
| #include "exception" |
| |
| /* Define terminate, unexpected, set_terminate, set_unexpected as |
| well as the default terminate func and default unexpected func. */ |
| |
| extern terminate_handler __terminate_func __attribute__((__noreturn__)); |
| |
| void |
| terminate () |
| { |
| __terminate_func (); |
| } |
| |
| void |
| __default_unexpected () |
| { |
| terminate (); |
| } |
| |
| static unexpected_handler __unexpected_func = __default_unexpected; |
| |
| terminate_handler |
| set_terminate (terminate_handler func) |
| { |
| terminate_handler old = __terminate_func; |
| |
| __terminate_func = func; |
| return old; |
| } |
| |
| unexpected_handler |
| set_unexpected (unexpected_handler func) |
| { |
| unexpected_handler old = __unexpected_func; |
| |
| __unexpected_func = func; |
| return old; |
| } |
| |
| void |
| unexpected () |
| { |
| __unexpected_func (); |
| } |
| |
| /* C++-specific state about the current exception. |
| This must match init_exception_processing(). |
| |
| Note that handlers and caught are not redundant; when rethrown, an |
| exception can have multiple active handlers and still be considered |
| uncaught. */ |
| |
| struct cp_eh_info |
| { |
| void *value; |
| void *type; |
| void (*cleanup)(void *, int); |
| bool caught; |
| cp_eh_info *next; |
| long handlers; |
| }; |
| |
| /* Language-specific EH info pointer, defined in libgcc2. */ |
| |
| extern cp_eh_info *__eh_info; // actually void* |
| |
| /* Is P the type_info node for a pointer of some kind? */ |
| |
| extern bool __is_pointer (void *); |
| |
| /* Compiler hook to return a pointer to the info for the current exception. |
| Used by get_eh_info (). */ |
| |
| extern "C" cp_eh_info * |
| __cp_exception_info (void) |
| { |
| return __eh_info; |
| } |
| |
| /* Compiler hook to push a new exception onto the stack. |
| Used by expand_throw(). */ |
| |
| extern "C" void |
| __cp_push_exception (void *value, void *type, void (*cleanup)(void *, int)) |
| { |
| cp_eh_info *p = new cp_eh_info; |
| p->value = value; |
| p->type = type; |
| p->cleanup = cleanup; |
| p->handlers = 0; |
| p->caught = false; |
| p->next = __eh_info; |
| __eh_info = p; |
| } |
| |
| /* Compiler hook to pop an exception that has been finalized. Used by |
| push_eh_cleanup(). P is the info for the exception caught by the |
| current catch block. */ |
| |
| extern "C" void |
| __cp_pop_exception (cp_eh_info *p) |
| { |
| cp_eh_info **q = &__eh_info; |
| |
| --p->handlers; |
| |
| /* Don't really pop if there are still active handlers for our exception, |
| or if our exception is being rethrown (i.e. if the active exception is |
| our exception and it is uncaught). */ |
| if (p->handlers != 0 |
| || (p == *q && !p->caught)) |
| return; |
| |
| for (; *q; q = &((*q)->next)) |
| if (*q == p) |
| break; |
| |
| if (! *q) |
| terminate (); |
| |
| *q = p->next; |
| |
| if (p->cleanup) |
| /* 3 is a magic value for destructors; see build_delete(). */ |
| p->cleanup (p->value, 3); |
| else if (__is_pointer (p->type)) |
| /* do nothing; pointers are passed directly in p->value. */; |
| else |
| delete p->value; |
| |
| delete p; |
| } |
| |
| extern "C" void |
| __uncatch_exception (void) |
| { |
| cp_eh_info *p = __cp_exception_info (); |
| if (p) |
| p->caught = false; |
| /* otherwise __throw will call terminate(); don't crash here. */ |
| } |
| |
| extern "C" void |
| __throw_bad_cast (void) |
| { |
| throw bad_cast (); |
| } |
| |
| extern "C" void |
| __throw_bad_typeid (void) |
| { |
| throw bad_typeid (); |
| } |
| |
| /* Has the current exception been caught? */ |
| |
| bool |
| uncaught_exception () |
| { |
| cp_eh_info *p = __cp_exception_info (); |
| return p && ! p->caught; |
| } |
| |
| const char * exception:: |
| what () const |
| { |
| return typeid (*this).name (); |
| } |