OSDN Git Service

2000-11-07 Eric Christopher <echristo@redhat.com>
[pf3gnuchains/gcc-fork.git] / libstdc++ / exception.cc
1 // Functions for Exception Support for -*- C++ -*-
2 // Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000 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, you may use this file as part of a free software
22 // library without restriction.  Specifically, if other files instantiate
23 // templates or use macros or inline functions from this file, or you compile
24 // this file and link it with other files to produce an executable, this
25 // file does not by itself cause the resulting executable to be covered by
26 // the GNU General Public License.  This exception does not however
27 // invalidate any other reasons why the executable file might be covered by
28 // the GNU General Public License.
29
30 #pragma implementation "exception"
31
32 #include "typeinfo"
33 #include "exception"
34 #include <stddef.h>
35 #include "gansidecl.h" /* Needed to support macros used in eh-common.h. */
36 #include "eh-common.h"
37
38 /* Define terminate, unexpected, set_terminate, set_unexpected as
39    well as the default terminate func and default unexpected func.  */
40
41 extern std::terminate_handler __terminate_func __attribute__((__noreturn__));
42 using std::terminate;
43
44 void
45 std::terminate ()
46 {
47   __terminate_func ();
48 }
49
50 void
51 __default_unexpected ()
52 {
53   terminate ();
54 }
55
56 static std::unexpected_handler __unexpected_func __attribute__((__noreturn__))
57   = __default_unexpected;
58
59 std::terminate_handler
60 std::set_terminate (std::terminate_handler func)
61 {
62   std::terminate_handler old = __terminate_func;
63
64   __terminate_func = func;
65   return old;
66 }
67
68 std::unexpected_handler
69 std::set_unexpected (std::unexpected_handler func)
70 {
71   std::unexpected_handler old = __unexpected_func;
72
73   __unexpected_func = func;
74   return old;
75 }
76
77 void
78 std::unexpected ()
79 {
80   __unexpected_func ();
81 }
82
83 /* The type of a function called to clean up an exception object.
84    (These will be destructors.)  Under the old ABI, these take a
85    second argument (the `in-charge' argument), that indicates whether
86    or not do delete the object, and whether or not to destroy virtual
87    bases.  Under the new ABI, there is no second argument.  */
88 #if !defined (__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100
89 typedef void (*cleanup_fn)(void *, int);
90 /* The `2' is the value for the in-charge parameter that indicates
91    that virtual bases should be destroyed.  */
92 #define CALL_CLEANUP(FN, THIS) FN (THIS, 2)
93 #else
94 typedef void (*cleanup_fn)(void *);
95 #define CALL_CLEANUP(FN, THIS) FN (THIS)
96 #endif
97
98 /* C++-specific state about the current exception.
99    This must match init_exception_processing().
100
101    Note that handlers and caught are not redundant; when rethrown, an
102    exception can have multiple active handlers and still be considered
103    uncaught.  */
104
105 struct cp_eh_info
106 {
107   __eh_info eh_info;
108   void *value;
109   void *type;
110   cleanup_fn cleanup;
111   bool caught;
112   cp_eh_info *next;
113   long handlers;
114   void *original_value;
115 };
116
117 /* Language-specific EH info pointer, defined in libgcc2. */
118
119 extern "C" cp_eh_info **__get_eh_info ();       // actually void **
120
121 /* Exception allocate and free, defined in libgcc2. */
122 extern "C" void *__eh_alloc(size_t);
123 extern "C" void __eh_free(void *);
124
125 /* Is P the type_info node for a pointer of some kind?  */
126
127 extern bool __is_pointer (void *);
128
129
130 /* OLD Compiler hook to return a pointer to the info for the current exception.
131    Used by get_eh_info ().  This fudges the actualy returned value to
132    point to the beginning of what USE to be the cp_eh_info structure.
133    THis is so that old code that dereferences this pointer will find
134    things where it expects it to be.*/
135 extern "C" void *
136 __cp_exception_info (void)
137 {
138   return &((*__get_eh_info ())->value);
139 }
140
141 #define CP_EH_INFO ((cp_eh_info *) *__get_eh_info ())
142
143 /* Old Compiler hook to return a pointer to the info for the current exception.
144    Used by get_eh_info ().  */
145
146 extern "C" cp_eh_info *
147 __cp_eh_info (void)
148 {
149   cp_eh_info *p = CP_EH_INFO;
150   return p;
151 }
152
153 /* Compiler hook to return a pointer to the info for the current exception,
154    Set the caught bit, and increment the number of handlers that are
155    looking at this exception. This makes handlers smaller. */
156
157 extern "C" cp_eh_info *
158 __start_cp_handler (void)
159 {
160   cp_eh_info *p = CP_EH_INFO;
161   p->caught = 1;
162   p->handlers++;
163   return p;
164 }
165
166 extern "C" int __throw_type_match_rtti_2 (const void *, const void *,
167                                          void *, void **);
168
169 extern "C" void *
170 __cplus_type_matcher (__eh_info *info_, void *match_info,
171                       exception_descriptor *exception_table)
172 {
173   cp_eh_info *info = (cp_eh_info *)info_;
174
175   /* No exception table implies the old style mechanism, so don't check. */
176   if (exception_table != NULL 
177       && exception_table->lang.language != EH_LANG_C_plus_plus)
178     return NULL;
179
180   if (match_info == CATCH_ALL_TYPE)
181     return (void *)1;
182
183   /* we don't worry about version info yet, there is only one version! */
184   
185   void *match_type = match_info;
186   
187 #if !defined (__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100
188   match_type  = ((void *(*)())match_type) ();
189 #endif
190
191   if (__throw_type_match_rtti_2 (match_type, info->type,
192                                  info->original_value, &info->value))
193     // Arbitrary non-null pointer.
194     return (void *)1;
195   else
196     return NULL;
197 }
198
199 /* Compiler hook to push a new exception onto the stack.
200    Used by expand_throw().  */
201
202 extern "C" void
203 __cp_push_exception (void *value, void *type, cleanup_fn cleanup)
204 {
205   cp_eh_info *p = (cp_eh_info *) __eh_alloc (sizeof (cp_eh_info));
206
207   p->value = value;
208   p->type = type;
209   p->cleanup = cleanup;
210   p->handlers = 0;
211   p->caught = false;
212   p->original_value = value;
213
214   p->eh_info.match_function = __cplus_type_matcher;
215   p->eh_info.language = EH_LANG_C_plus_plus;
216   p->eh_info.version = 1;
217
218   cp_eh_info **q = __get_eh_info ();
219
220   p->next = *q;
221   *q = p;
222 }
223
224 /* Compiler hook to pop an exception that has been finalized.  Used by
225    push_eh_cleanup().  P is the info for the exception caught by the
226    current catch block.  */
227
228 extern "C" void
229 __cp_pop_exception (cp_eh_info *p)
230 {
231   cp_eh_info **stack = __get_eh_info ();
232   cp_eh_info **q = stack;
233
234   --p->handlers;
235
236   /* Do nothing if our exception is being rethrown (i.e. if the active
237      exception is our exception and it is uncaught).  */
238   if (p == *q && !p->caught)
239     return;
240
241   /* Don't really pop if there are still active handlers for our exception;
242      rather, push it down past any uncaught exceptions.  */
243   if (p->handlers != 0)
244     {
245       if (p == *q && p->next && !p->next->caught)
246         {
247           q = &(p->next);
248           while (1)
249             {
250               if (*q == 0 || (*q)->caught)
251                 break;
252
253               q = &((*q)->next);
254             }
255           *stack = p->next;
256           p->next = *q;
257           *q = p;
258         }
259       return;
260     }
261
262   for (; *q; q = &((*q)->next))
263     if (*q == p)
264       break;
265
266   if (! *q)
267     terminate ();
268
269   *q = p->next;
270
271   if (p->cleanup)
272     // value may have been adjusted.
273     CALL_CLEANUP (p->cleanup, p->original_value);
274
275   if (! __is_pointer (p->type))
276     __eh_free (p->original_value);  // value may have been adjusted.
277
278   __eh_free (p);
279 }
280
281 /* We're doing a rethrow.  Find the currently handled exception, mark it
282    uncaught, and move it to the top of the EH stack.  */
283
284 extern "C" void
285 __uncatch_exception (void)
286 {
287   cp_eh_info **stack = __get_eh_info ();
288   cp_eh_info **q = stack;
289   cp_eh_info *p;
290
291   while (1)
292     {
293       p = *q;
294
295       if (p == 0)
296         terminate ();
297       if (p->caught)
298         break;
299
300       q = &(p->next);
301     }
302
303   if (q != stack)
304     {
305       *q = p->next;
306       p->next = *stack;
307       *stack = p;
308     }
309
310   p->caught = false;
311 }
312
313 /* As per [except.unexpected]:
314    If an exception is thrown, we check it against the spec.  If it doesn't
315    match, we call unexpected ().  If unexpected () throws, we check that
316    exception against the spec.  If it doesn't match, if the spec allows
317    bad_exception we throw that; otherwise we call terminate ().
318
319    The compiler treats an exception spec as a try block with a generic
320    handler that just calls this function with a list of the allowed
321    exception types, so we have an active exception that can be rethrown.
322
323    This function does not return.  */   
324
325 extern "C" void
326 __check_eh_spec (int n, const void **spec)
327 {
328   cp_eh_info *p = CP_EH_INFO;
329   void *d;
330
331   for (int i = 0; i < n; ++i)
332     {
333       if (__throw_type_match_rtti_2 (spec[i], p->type, p->value, &d))
334         throw;
335     }
336
337   try
338     {
339       std::unexpected ();
340     }
341   catch (...)
342     {
343       // __exception_info is an artificial var pushed into each catch block.
344       if (p != __exception_info)
345         {
346           p = __exception_info;
347           for (int i = 0; i < n; ++i)
348             {
349               if (__throw_type_match_rtti_2 (spec[i], p->type, p->value, &d))
350                 throw;
351             }
352         }
353
354       const std::type_info &bad_exc = typeid (std::bad_exception);
355       for (int i = 0; i < n; ++i)
356         {
357           if (__throw_type_match_rtti_2 (spec[i], &bad_exc, p->value, &d))
358             throw std::bad_exception ();
359         }
360
361       terminate ();
362     }
363 }
364
365 /* Special case of the above for throw() specs.  */
366
367 extern "C" void
368 __check_null_eh_spec (void)
369 {
370   __check_eh_spec (0, 0);
371 }
372
373 // Helpers for rtti. Although these don't return, we give them return types so
374 // that the type system is not broken.
375
376 extern "C" void *
377 __throw_bad_cast ()
378 {
379   throw std::bad_cast ();
380   return 0;
381 }
382
383 extern "C" std::type_info const &
384 __throw_bad_typeid ()
385 {
386   throw std::bad_typeid ();
387   return typeid (void);
388 }
389
390 /* Has the current exception been caught?  */
391
392 bool
393 std::uncaught_exception ()
394 {
395   cp_eh_info *p = CP_EH_INFO;
396   return p && ! p->caught;
397 }
398
399 const char * std::exception::
400 what () const
401 {
402   return typeid (*this).name ();
403 }