]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/gcc/cp/exception.cc
Import data for 3.0.2.
[FreeBSD/FreeBSD.git] / contrib / gcc / cp / exception.cc
1 // Functions for Exception Support for -*- C++ -*-
2 // Copyright (C) 1994, 95-97, 1998 Free Software Foundation
3
4 // This file is part of GNU CC.
5
6 // GNU CC is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2, or (at your option)
9 // any later version.
10
11 // GNU CC is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15
16 // You should have received a copy of the GNU General Public License
17 // along with GNU CC; see the file COPYING.  If not, write to
18 // the Free Software Foundation, 59 Temple Place - Suite 330,
19 // Boston, MA 02111-1307, USA. 
20
21 // As a special exception, if you link this library with other files,
22 // some of which are compiled with GCC, to produce an executable,
23 // this library does not by itself cause the resulting executable
24 // to be covered by the GNU General Public License.
25 // This exception does not however invalidate any other reasons why
26 // the executable file might be covered by the GNU General Public License.
27
28 #pragma implementation "exception"
29
30 #include "typeinfo"
31 #include "exception"
32 #include <stddef.h>
33 #include "gansidecl.h" /* Needed to support macros used in eh-common.h. */
34 #include "eh-common.h"
35
36 /* Define terminate, unexpected, set_terminate, set_unexpected as
37    well as the default terminate func and default unexpected func.  */
38
39 extern std::terminate_handler __terminate_func __attribute__((__noreturn__));
40 using std::terminate;
41
42 void
43 std::terminate ()
44 {
45   __terminate_func ();
46 }
47
48 void
49 __default_unexpected ()
50 {
51   terminate ();
52 }
53
54 static std::unexpected_handler __unexpected_func __attribute__((__noreturn__))
55   = __default_unexpected;
56
57 std::terminate_handler
58 std::set_terminate (std::terminate_handler func)
59 {
60   std::terminate_handler old = __terminate_func;
61
62   __terminate_func = func;
63   return old;
64 }
65
66 std::unexpected_handler
67 std::set_unexpected (std::unexpected_handler func)
68 {
69   std::unexpected_handler old = __unexpected_func;
70
71   __unexpected_func = func;
72   return old;
73 }
74
75 void
76 std::unexpected ()
77 {
78   __unexpected_func ();
79 }
80
81 /* C++-specific state about the current exception.
82    This must match init_exception_processing().
83
84    Note that handlers and caught are not redundant; when rethrown, an
85    exception can have multiple active handlers and still be considered
86    uncaught.  */
87
88 struct cp_eh_info
89 {
90   __eh_info eh_info;
91   void *value;
92   void *type;
93   void (*cleanup)(void *, int);
94   bool caught;
95   cp_eh_info *next;
96   long handlers;
97   void *original_value;
98 };
99
100 /* Language-specific EH info pointer, defined in libgcc2. */
101
102 extern "C" cp_eh_info **__get_eh_info ();       // actually void **
103
104 /* Is P the type_info node for a pointer of some kind?  */
105
106 extern bool __is_pointer (void *);
107
108
109 /* OLD Compiler hook to return a pointer to the info for the current exception.
110    Used by get_eh_info ().  This fudges the actualy returned value to
111    point to the beginning of what USE to be the cp_eh_info structure.
112    THis is so that old code that dereferences this pointer will find
113    things where it expects it to be.*/
114 extern "C" void *
115 __cp_exception_info (void)
116 {
117   return &((*__get_eh_info ())->value);
118 }
119
120 #define CP_EH_INFO ((cp_eh_info *) *__get_eh_info ())
121
122 /* Old Compiler hook to return a pointer to the info for the current exception.
123    Used by get_eh_info ().  */
124
125 extern "C" cp_eh_info *
126 __cp_eh_info (void)
127 {
128   cp_eh_info *p = CP_EH_INFO;
129   return p;
130 }
131
132 /* Compiler hook to return a pointer to the info for the current exception,
133    Set the caught bit, and increment the number of handlers that are
134    looking at this exception. This makes handlers smaller. */
135
136 extern "C" cp_eh_info *
137 __start_cp_handler (void)
138 {
139   cp_eh_info *p = CP_EH_INFO;
140   p->caught = 1;
141   p->handlers++;
142   return p;
143 }
144
145 /* Allocate a buffer for a cp_eh_info and an exception object of size SIZE,
146    and return a pointer to the beginning of the object's space.  */
147
148 extern "C" void * malloc (size_t);
149 extern "C" void *
150 __eh_alloc (size_t size)
151 {
152   void *p = malloc (size);
153   if (p == 0)
154     terminate ();
155   return p;
156 }
157
158 /* Free the memory for an cp_eh_info and associated exception, given
159    a pointer to the cp_eh_info.  */
160
161 extern "C" void free (void *);
162 extern "C" void
163 __eh_free (void *p)
164 {
165   free (p);
166 }
167
168
169 typedef void * (* rtimetype) (void);
170
171 extern "C" void *
172 __cplus_type_matcher (cp_eh_info *info, rtimetype match_info, 
173                                  exception_descriptor *exception_table)
174 {
175   void *ret;
176
177   /* No exception table implies the old style mechanism, so don't check. */
178   if (exception_table != NULL 
179       && exception_table->lang.language != EH_LANG_C_plus_plus)
180     return NULL;
181
182   if (match_info == CATCH_ALL_TYPE)
183     return info->value;
184
185   /* we don't worry about version info yet, there is only one version! */
186   
187   void *match_type = match_info ();
188   ret = __throw_type_match_rtti (match_type, info->type, info->original_value);
189   /* change value of exception */
190   if (ret)
191     info->value = ret;
192   return ret;
193 }
194
195
196 /* Compiler hook to push a new exception onto the stack.
197    Used by expand_throw().  */
198
199 extern "C" void
200 __cp_push_exception (void *value, void *type, void (*cleanup)(void *, int))
201 {
202   cp_eh_info *p = (cp_eh_info *) __eh_alloc (sizeof (cp_eh_info));
203
204   p->value = value;
205   p->type = type;
206   p->cleanup = cleanup;
207   p->handlers = 0;
208   p->caught = false;
209   p->original_value = value;
210
211   p->eh_info.match_function = __cplus_type_matcher;
212   p->eh_info.language = EH_LANG_C_plus_plus;
213   p->eh_info.version = 1;
214
215   cp_eh_info **q = __get_eh_info ();
216
217   p->next = *q;
218   *q = p;
219 }
220
221 /* Compiler hook to pop an exception that has been finalized.  Used by
222    push_eh_cleanup().  P is the info for the exception caught by the
223    current catch block.  */
224
225 extern "C" void
226 __cp_pop_exception (cp_eh_info *p)
227 {
228   cp_eh_info **q = __get_eh_info ();
229
230   --p->handlers;
231
232   /* Don't really pop if there are still active handlers for our exception,
233      or if our exception is being rethrown (i.e. if the active exception is
234      our exception and it is uncaught).  */
235   if (p->handlers != 0
236       || (p == *q && !p->caught))
237     return;
238
239   for (; *q; q = &((*q)->next))
240     if (*q == p)
241       break;
242
243   if (! *q)
244     terminate ();
245
246   *q = p->next;
247
248   if (p->cleanup)
249     /* 2 is a magic value for destructors; see build_delete().  */
250     p->cleanup (p->original_value, 2);  // value may have been adjusted.
251
252   if (! __is_pointer (p->type))
253     __eh_free (p->original_value);  // value may have been adjusted.
254
255   __eh_free (p);
256 }
257
258 extern "C" void
259 __uncatch_exception (void)
260 {
261   cp_eh_info *p = CP_EH_INFO;
262   if (p == 0)
263     terminate ();
264   p->caught = false;
265 }
266
267 /* As per [except.unexpected]:
268    If an exception is thrown, we check it against the spec.  If it doesn't
269    match, we call unexpected ().  If unexpected () throws, we check that
270    exception against the spec.  If it doesn't match, if the spec allows
271    bad_exception we throw that; otherwise we call terminate ().
272
273    The compiler treats an exception spec as a try block with a generic
274    handler that just calls this function with a list of the allowed
275    exception types, so we have an active exception that can be rethrown.
276
277    This function does not return.  */   
278
279 extern "C" void
280 __check_eh_spec (int n, const void **spec)
281 {
282   cp_eh_info *p = CP_EH_INFO;
283
284   for (int i = 0; i < n; ++i)
285     {
286       if (__throw_type_match_rtti (spec[i], p->type, p->value))
287         throw;
288     }
289
290   try
291     {
292       std::unexpected ();
293     }
294   catch (...)
295     {
296       // __exception_info is an artificial var pushed into each catch block.
297       if (p != __exception_info)
298         {
299           p = __exception_info;
300           for (int i = 0; i < n; ++i)
301             {
302               if (__throw_type_match_rtti (spec[i], p->type, p->value))
303                 throw;
304             }
305         }
306
307       const std::type_info &bad_exc = typeid (std::bad_exception);
308       for (int i = 0; i < n; ++i)
309         {
310           if (__throw_type_match_rtti (spec[i], &bad_exc, p->value))
311             throw std::bad_exception ();
312         }
313
314       terminate ();
315     }
316 }
317
318 extern "C" void
319 __throw_bad_cast (void)
320 {
321   throw std::bad_cast ();
322 }
323
324 extern "C" void
325 __throw_bad_typeid (void)
326 {
327   throw std::bad_typeid ();
328 }
329
330 /* Has the current exception been caught?  */
331
332 bool
333 std::uncaught_exception ()
334 {
335   cp_eh_info *p = CP_EH_INFO;
336   return p && ! p->caught;
337 }
338
339 const char * std::exception::
340 what () const
341 {
342   return typeid (*this).name ();
343 }