]>
Commit | Line | Data |
---|---|---|
8d08fdba | 1 | /* Handle exceptional things in C++. |
c913b6f1 | 2 | Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, |
43c6a96a | 3 | 2000, 2001, 2002, 2003 Free Software Foundation, Inc. |
8d2733ca MS |
4 | Contributed by Michael Tiemann <tiemann@cygnus.com> |
5 | Rewritten by Mike Stump <mrs@cygnus.com>, based upon an | |
6 | initial re-implementation courtesy Tad Hunt. | |
8d08fdba | 7 | |
f5adbb8d | 8 | This file is part of GCC. |
8d08fdba | 9 | |
f5adbb8d | 10 | GCC is free software; you can redistribute it and/or modify |
8d08fdba MS |
11 | it under the terms of the GNU General Public License as published by |
12 | the Free Software Foundation; either version 2, or (at your option) | |
13 | any later version. | |
14 | ||
f5adbb8d | 15 | GCC is distributed in the hope that it will be useful, |
8d08fdba MS |
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | GNU General Public License for more details. | |
19 | ||
20 | You should have received a copy of the GNU General Public License | |
f5adbb8d | 21 | along with GCC; see the file COPYING. If not, write to |
e9fa0c7c RK |
22 | the Free Software Foundation, 59 Temple Place - Suite 330, |
23 | Boston, MA 02111-1307, USA. */ | |
8d08fdba MS |
24 | |
25 | ||
8d08fdba | 26 | #include "config.h" |
8d052bc7 | 27 | #include "system.h" |
4977bab6 ZW |
28 | #include "coretypes.h" |
29 | #include "tm.h" | |
8d08fdba MS |
30 | #include "tree.h" |
31 | #include "rtl.h" | |
8f17b5c5 | 32 | #include "expr.h" |
e78d8e51 | 33 | #include "libfuncs.h" |
8d08fdba MS |
34 | #include "cp-tree.h" |
35 | #include "flags.h" | |
21451173 | 36 | #include "output.h" |
6467930b | 37 | #include "except.h" |
54f92bfb | 38 | #include "toplev.h" |
6f30f1f1 | 39 | #include "tree-inline.h" |
8d08fdba | 40 | |
5cc3d3b8 GDR |
41 | static void push_eh_cleanup (tree); |
42 | static tree prepare_eh_type (tree); | |
43 | static tree build_eh_type_type (tree); | |
44 | static tree do_begin_catch (void); | |
45 | static int dtor_nothrow (tree); | |
46 | static tree do_end_catch (tree); | |
5cc3d3b8 GDR |
47 | static bool decl_is_java_type (tree decl, int err); |
48 | static void initialize_handler_parm (tree, tree); | |
49 | static tree do_allocate_exception (tree); | |
50 | static tree stabilize_throw_expr (tree, tree *); | |
51 | static tree wrap_cleanups_r (tree *, int *, void *); | |
52 | static int complete_ptr_ref_or_void_ptr_p (tree, tree); | |
53 | static bool is_admissible_throw_operand (tree); | |
54 | static int can_convert_eh (tree, tree); | |
55 | static void check_handlers_1 (tree, tree); | |
56 | static tree cp_protect_cleanup_actions (void); | |
8d2733ca | 57 | |
52a11cbf | 58 | /* Sets up all the global eh stuff that needs to be initialized at the |
bbd0d54a | 59 | start of compilation. */ |
8d08fdba | 60 | |
8d08fdba | 61 | void |
5cc3d3b8 | 62 | init_exception_processing (void) |
8d08fdba | 63 | { |
52a11cbf RH |
64 | tree tmp; |
65 | ||
52a11cbf | 66 | /* void std::terminate (); */ |
1dbb6023 | 67 | push_namespace (std_identifier); |
52a11cbf RH |
68 | tmp = build_function_type (void_type_node, void_list_node); |
69 | terminate_node = build_cp_library_fn_ptr ("terminate", tmp); | |
9cd64686 | 70 | TREE_THIS_VOLATILE (terminate_node) = 1; |
0c11ada6 | 71 | TREE_NOTHROW (terminate_node) = 1; |
1dbb6023 | 72 | pop_namespace (); |
8ccc31eb | 73 | |
52a11cbf RH |
74 | /* void __cxa_call_unexpected(void *); */ |
75 | tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node); | |
76 | tmp = build_function_type (void_type_node, tmp); | |
77 | call_unexpected_node | |
78 | = push_throw_library_fn (get_identifier ("__cxa_call_unexpected"), tmp); | |
6874c264 | 79 | |
52a11cbf RH |
80 | eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS |
81 | ? "__gxx_personality_sj0" | |
82 | : "__gxx_personality_v0"); | |
6874c264 | 83 | |
52a11cbf | 84 | lang_eh_runtime_type = build_eh_type_type; |
e6855a2d | 85 | lang_protect_cleanup_actions = &cp_protect_cleanup_actions; |
6874c264 JM |
86 | } |
87 | ||
e6855a2d | 88 | /* Returns an expression to be executed if an unhandled exception is |
aba649ba | 89 | propagated out of a cleanup region. */ |
e6855a2d MM |
90 | |
91 | static tree | |
5cc3d3b8 | 92 | cp_protect_cleanup_actions (void) |
e6855a2d MM |
93 | { |
94 | /* [except.terminate] | |
95 | ||
96 | When the destruction of an object during stack unwinding exits | |
97 | using an exception ... void terminate(); is called. */ | |
98 | return build_call (terminate_node, NULL_TREE); | |
99 | } | |
100 | ||
6874c264 | 101 | static tree |
5cc3d3b8 | 102 | prepare_eh_type (tree type) |
8d08fdba | 103 | { |
52a11cbf RH |
104 | if (type == NULL_TREE) |
105 | return type; | |
f30432d7 MS |
106 | if (type == error_mark_node) |
107 | return error_mark_node; | |
8d2733ca | 108 | |
e92cc029 | 109 | /* peel back references, so they match. */ |
f30432d7 MS |
110 | if (TREE_CODE (type) == REFERENCE_TYPE) |
111 | type = TREE_TYPE (type); | |
8d08fdba | 112 | |
e92cc029 | 113 | /* Peel off cv qualifiers. */ |
f30432d7 | 114 | type = TYPE_MAIN_VARIANT (type); |
8d2733ca | 115 | |
52a11cbf | 116 | return type; |
8d08fdba | 117 | } |
8d08fdba | 118 | |
e5f614d7 | 119 | /* Build the address of a typeinfo decl for use in the runtime |
c6002625 | 120 | matching field of the exception model. */ |
5816cb14 AM |
121 | |
122 | static tree | |
5cc3d3b8 | 123 | build_eh_type_type (tree type) |
5816cb14 | 124 | { |
5816cb14 | 125 | tree exp; |
5816cb14 | 126 | |
93ca4ba7 JM |
127 | if (type == NULL_TREE || type == error_mark_node) |
128 | return type; | |
5816cb14 | 129 | |
52a11cbf RH |
130 | if (decl_is_java_type (type, 0)) |
131 | exp = build_java_class_ref (TREE_TYPE (type)); | |
132 | else | |
133 | exp = get_tinfo_decl (type); | |
5816cb14 | 134 | |
e5f614d7 | 135 | mark_used (exp); |
db48b831 | 136 | exp = build1 (ADDR_EXPR, ptr_type_node, exp); |
5816cb14 | 137 | |
52a11cbf | 138 | return exp; |
5816cb14 AM |
139 | } |
140 | ||
52a11cbf | 141 | tree |
5cc3d3b8 | 142 | build_exc_ptr (void) |
52a11cbf RH |
143 | { |
144 | return build (EXC_PTR_EXPR, ptr_type_node); | |
145 | } | |
146 | ||
147 | /* Build up a call to __cxa_begin_catch, to tell the runtime that the | |
148 | exception has been handled. */ | |
93ca4ba7 | 149 | |
52a11cbf | 150 | static tree |
5cc3d3b8 | 151 | do_begin_catch (void) |
9c606f69 | 152 | { |
52a11cbf RH |
153 | tree fn; |
154 | ||
155 | fn = get_identifier ("__cxa_begin_catch"); | |
156 | if (IDENTIFIER_GLOBAL_VALUE (fn)) | |
157 | fn = IDENTIFIER_GLOBAL_VALUE (fn); | |
158 | else | |
9c606f69 | 159 | { |
52a11cbf RH |
160 | /* Declare void* __cxa_begin_catch (void *). */ |
161 | tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node); | |
162 | fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp)); | |
9c606f69 | 163 | } |
52a11cbf RH |
164 | |
165 | return build_function_call (fn, tree_cons (NULL_TREE, build_exc_ptr (), | |
166 | NULL_TREE)); | |
9c606f69 AM |
167 | } |
168 | ||
93ca4ba7 JM |
169 | /* Returns nonzero if cleaning up an exception of type TYPE (which can be |
170 | NULL_TREE for a ... handler) will not throw an exception. */ | |
171 | ||
172 | static int | |
5cc3d3b8 | 173 | dtor_nothrow (tree type) |
93ca4ba7 | 174 | { |
93ca4ba7 JM |
175 | if (type == NULL_TREE) |
176 | return 0; | |
177 | ||
178 | if (! TYPE_HAS_DESTRUCTOR (type)) | |
179 | return 1; | |
180 | ||
50ad9642 | 181 | return TREE_NOTHROW (CLASSTYPE_DESTRUCTORS (type)); |
93ca4ba7 JM |
182 | } |
183 | ||
52a11cbf | 184 | /* Build up a call to __cxa_end_catch, to destroy the exception object |
93ca4ba7 | 185 | for the current catch block if no others are currently using it. */ |
6467930b | 186 | |
c7ae64f2 | 187 | static tree |
5cc3d3b8 | 188 | do_end_catch (tree type) |
72b7eeff | 189 | { |
6874c264 | 190 | tree fn, cleanup; |
52a11cbf RH |
191 | |
192 | fn = get_identifier ("__cxa_end_catch"); | |
6874c264 JM |
193 | if (IDENTIFIER_GLOBAL_VALUE (fn)) |
194 | fn = IDENTIFIER_GLOBAL_VALUE (fn); | |
195 | else | |
196 | { | |
52a11cbf RH |
197 | /* Declare void __cxa_end_catch (). */ |
198 | fn = push_void_library_fn (fn, void_list_node); | |
0c11ada6 JM |
199 | /* This can throw if the destructor for the exception throws. */ |
200 | TREE_NOTHROW (fn) = 0; | |
6874c264 | 201 | } |
72b7eeff | 202 | |
52a11cbf | 203 | cleanup = build_function_call (fn, NULL_TREE); |
93ca4ba7 | 204 | TREE_NOTHROW (cleanup) = dtor_nothrow (type); |
52a11cbf | 205 | |
c0700ea5 | 206 | return cleanup; |
c7ae64f2 JM |
207 | } |
208 | ||
209 | /* This routine creates the cleanup for the current exception. */ | |
72b7eeff | 210 | |
c7ae64f2 | 211 | static void |
5cc3d3b8 | 212 | push_eh_cleanup (tree type) |
c7ae64f2 | 213 | { |
52a11cbf | 214 | finish_decl_cleanup (NULL_TREE, do_end_catch (type)); |
f4a23343 JM |
215 | } |
216 | ||
e97f22c9 TT |
217 | /* Return nonzero value if DECL is a Java type suitable for catch or |
218 | throw. */ | |
219 | ||
52a11cbf | 220 | static bool |
5cc3d3b8 | 221 | decl_is_java_type (tree decl, int err) |
e97f22c9 | 222 | { |
52a11cbf RH |
223 | bool r = (TREE_CODE (decl) == POINTER_TYPE |
224 | && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE | |
225 | && TYPE_FOR_JAVA (TREE_TYPE (decl))); | |
e97f22c9 TT |
226 | |
227 | if (err) | |
228 | { | |
229 | if (TREE_CODE (decl) == REFERENCE_TYPE | |
230 | && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE | |
231 | && TYPE_FOR_JAVA (TREE_TYPE (decl))) | |
232 | { | |
233 | /* Can't throw a reference. */ | |
33bd39a2 | 234 | error ("type `%T' is disallowed in Java `throw' or `catch'", |
e97f22c9 TT |
235 | decl); |
236 | } | |
237 | ||
238 | if (r) | |
239 | { | |
240 | tree jthrow_node | |
241 | = IDENTIFIER_GLOBAL_VALUE (get_identifier ("jthrowable")); | |
400500c4 | 242 | |
e97f22c9 | 243 | if (jthrow_node == NULL_TREE) |
400500c4 RK |
244 | fatal_error |
245 | ("call to Java `catch' or `throw' with `jthrowable' undefined"); | |
246 | ||
e97f22c9 TT |
247 | jthrow_node = TREE_TYPE (TREE_TYPE (jthrow_node)); |
248 | ||
249 | if (! DERIVED_FROM_P (jthrow_node, TREE_TYPE (decl))) | |
250 | { | |
251 | /* Thrown object must be a Throwable. */ | |
33bd39a2 | 252 | error ("type `%T' is not derived from `java::lang::Throwable'", |
e97f22c9 TT |
253 | TREE_TYPE (decl)); |
254 | } | |
255 | } | |
256 | } | |
257 | ||
258 | return r; | |
259 | } | |
260 | ||
1f730ff7 ZW |
261 | /* Select the personality routine to be used for exception handling, |
262 | or issue an error if we need two different ones in the same | |
263 | translation unit. | |
264 | ??? At present eh_personality_libfunc is set to | |
265 | __gxx_personality_(sj|v)0 in init_exception_processing - should it | |
266 | be done here instead? */ | |
267 | void | |
5cc3d3b8 | 268 | choose_personality_routine (enum languages lang) |
52a11cbf RH |
269 | { |
270 | static enum { | |
271 | chose_none, | |
272 | chose_cpp, | |
273 | chose_java, | |
274 | gave_error | |
275 | } state; | |
276 | ||
277 | switch (state) | |
278 | { | |
1f730ff7 ZW |
279 | case gave_error: |
280 | return; | |
52a11cbf RH |
281 | |
282 | case chose_cpp: | |
1f730ff7 ZW |
283 | if (lang != lang_cplusplus) |
284 | goto give_error; | |
285 | return; | |
286 | ||
52a11cbf | 287 | case chose_java: |
1f730ff7 ZW |
288 | if (lang != lang_java) |
289 | goto give_error; | |
290 | return; | |
291 | ||
292 | case chose_none: | |
293 | ; /* proceed to language selection */ | |
294 | } | |
295 | ||
296 | switch (lang) | |
297 | { | |
298 | case lang_cplusplus: | |
299 | state = chose_cpp; | |
52a11cbf RH |
300 | break; |
301 | ||
1f730ff7 ZW |
302 | case lang_java: |
303 | state = chose_java; | |
304 | eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS | |
305 | ? "__gcj_personality_sj0" | |
306 | : "__gcj_personality_v0"); | |
52a11cbf | 307 | break; |
1f730ff7 ZW |
308 | |
309 | default: | |
310 | abort (); | |
52a11cbf | 311 | } |
1f730ff7 ZW |
312 | return; |
313 | ||
314 | give_error: | |
315 | error ("mixing C++ and Java catches in a single translation unit"); | |
316 | state = gave_error; | |
52a11cbf RH |
317 | } |
318 | ||
b35d4555 | 319 | /* Initialize the catch parameter DECL. */ |
6467930b | 320 | |
b35d4555 | 321 | static void |
5cc3d3b8 | 322 | initialize_handler_parm (tree decl, tree exp) |
8d08fdba | 323 | { |
b35d4555 MM |
324 | tree init; |
325 | tree init_type; | |
326 | ||
327 | /* Make sure we mark the catch param as used, otherwise we'll get a | |
328 | warning about an unused ((anonymous)). */ | |
329 | TREE_USED (decl) = 1; | |
330 | ||
52a11cbf RH |
331 | /* Figure out the type that the initializer is. Pointers are returned |
332 | adjusted by value from __cxa_begin_catch. Others are returned by | |
333 | reference. */ | |
b35d4555 | 334 | init_type = TREE_TYPE (decl); |
c93586fa | 335 | if (! TYPE_PTR_P (init_type) |
52a11cbf | 336 | && TREE_CODE (init_type) != REFERENCE_TYPE) |
b35d4555 MM |
337 | init_type = build_reference_type (init_type); |
338 | ||
1f730ff7 ZW |
339 | choose_personality_routine (decl_is_java_type (init_type, 0) |
340 | ? lang_java : lang_cplusplus); | |
b35d4555 MM |
341 | |
342 | /* Since pointers are passed by value, initialize a reference to | |
52a11cbf | 343 | pointer catch parm with the address of the temporary. */ |
c93586fa RS |
344 | if (TREE_CODE (init_type) == REFERENCE_TYPE |
345 | && TYPE_PTR_P (TREE_TYPE (init_type))) | |
b35d4555 MM |
346 | exp = build_unary_op (ADDR_EXPR, exp, 1); |
347 | ||
52a11cbf | 348 | exp = ocp_convert (init_type, exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0); |
b35d4555 MM |
349 | |
350 | init = convert_from_reference (exp); | |
351 | ||
352 | /* If the constructor for the catch parm exits via an exception, we | |
353 | must call terminate. See eh23.C. */ | |
354 | if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) | |
faf5394a | 355 | { |
b35d4555 MM |
356 | /* Generate the copy constructor call directly so we can wrap it. |
357 | See also expand_default_init. */ | |
358 | init = ocp_convert (TREE_TYPE (decl), init, | |
359 | CONV_IMPLICIT|CONV_FORCE_TEMP, 0); | |
52a11cbf | 360 | init = build1 (MUST_NOT_THROW_EXPR, TREE_TYPE (init), init); |
faf5394a MS |
361 | } |
362 | ||
b35d4555 MM |
363 | /* Let `cp_finish_decl' know that this initializer is ok. */ |
364 | DECL_INITIAL (decl) = error_mark_node; | |
365 | decl = pushdecl (decl); | |
8d2733ca | 366 | |
b35d4555 | 367 | start_decl_1 (decl); |
cd9f6678 | 368 | cp_finish_decl (decl, init, NULL_TREE, |
b35d4555 | 369 | LOOKUP_ONLYCONVERTING|DIRECT_BIND); |
5816cb14 AM |
370 | } |
371 | ||
b35d4555 | 372 | /* Call this to start a catch block. DECL is the catch parameter. */ |
5816cb14 | 373 | |
b35d4555 | 374 | tree |
5cc3d3b8 | 375 | expand_start_catch_block (tree decl) |
5816cb14 | 376 | { |
52a11cbf RH |
377 | tree exp = NULL_TREE; |
378 | tree type; | |
379 | bool is_java; | |
5816cb14 | 380 | |
b35d4555 MM |
381 | if (! doing_eh (1)) |
382 | return NULL_TREE; | |
5816cb14 | 383 | |
b35d4555 | 384 | /* Make sure this declaration is reasonable. */ |
3c5c0849 MM |
385 | if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE)) |
386 | decl = NULL_TREE; | |
5816cb14 | 387 | |
52a11cbf RH |
388 | if (decl) |
389 | type = prepare_eh_type (TREE_TYPE (decl)); | |
390 | else | |
391 | type = NULL_TREE; | |
52a11cbf RH |
392 | |
393 | is_java = false; | |
394 | if (decl) | |
e97f22c9 | 395 | { |
52a11cbf | 396 | tree init; |
5816cb14 | 397 | |
52a11cbf RH |
398 | if (decl_is_java_type (type, 1)) |
399 | { | |
400 | /* Java only passes object via pointer and doesn't require | |
401 | adjusting. The java object is immediately before the | |
402 | generic exception header. */ | |
403 | init = build_exc_ptr (); | |
404 | init = build1 (NOP_EXPR, build_pointer_type (type), init); | |
405 | init = build (MINUS_EXPR, TREE_TYPE (init), init, | |
406 | TYPE_SIZE_UNIT (TREE_TYPE (init))); | |
3e411c3f | 407 | init = build_indirect_ref (init, NULL); |
52a11cbf RH |
408 | is_java = true; |
409 | } | |
e97f22c9 | 410 | else |
52a11cbf RH |
411 | { |
412 | /* C++ requires that we call __cxa_begin_catch to get the | |
413 | pointer to the actual object. */ | |
414 | init = do_begin_catch (); | |
415 | } | |
416 | ||
417 | exp = create_temporary_var (ptr_type_node); | |
418 | DECL_REGISTER (exp) = 1; | |
419 | cp_finish_decl (exp, init, NULL_TREE, LOOKUP_ONLYCONVERTING); | |
420 | finish_expr_stmt (build_modify_expr (exp, INIT_EXPR, init)); | |
e97f22c9 TT |
421 | } |
422 | else | |
52a11cbf RH |
423 | finish_expr_stmt (do_begin_catch ()); |
424 | ||
425 | /* C++ requires that we call __cxa_end_catch at the end of | |
426 | processing the exception. */ | |
427 | if (! is_java) | |
428 | push_eh_cleanup (type); | |
5816cb14 | 429 | |
b35d4555 | 430 | if (decl) |
52a11cbf | 431 | initialize_handler_parm (decl, exp); |
5816cb14 | 432 | |
1a6025b4 | 433 | return type; |
5816cb14 AM |
434 | } |
435 | ||
f30432d7 | 436 | |
8d2733ca MS |
437 | /* Call this to end a catch block. Its responsible for emitting the |
438 | code to handle jumping back to the correct place, and for emitting | |
439 | the label to jump to if this catch block didn't match. */ | |
6467930b | 440 | |
824b9a4c | 441 | void |
5cc3d3b8 | 442 | expand_end_catch_block (void) |
8d08fdba | 443 | { |
f30432d7 MS |
444 | if (! doing_eh (1)) |
445 | return; | |
8d2733ca | 446 | |
0dde4175 JM |
447 | /* The exception being handled is rethrown if control reaches the end of |
448 | a handler of the function-try-block of a constructor or destructor. */ | |
449 | if (in_function_try_handler | |
450 | && (DECL_CONSTRUCTOR_P (current_function_decl) | |
451 | || DECL_DESTRUCTOR_P (current_function_decl))) | |
b35d4555 | 452 | finish_expr_stmt (build_throw (NULL_TREE)); |
8d2733ca | 453 | } |
8d08fdba | 454 | |
b35d4555 | 455 | tree |
5cc3d3b8 | 456 | begin_eh_spec_block (void) |
f30432d7 | 457 | { |
52a11cbf RH |
458 | tree r = build_stmt (EH_SPEC_BLOCK, NULL_TREE, NULL_TREE); |
459 | add_stmt (r); | |
460 | return r; | |
f30432d7 MS |
461 | } |
462 | ||
b35d4555 | 463 | void |
5cc3d3b8 | 464 | finish_eh_spec_block (tree raw_raises, tree eh_spec_block) |
f30432d7 | 465 | { |
52a11cbf | 466 | tree raises; |
0c11ada6 | 467 | |
52a11cbf | 468 | RECHAIN_STMTS (eh_spec_block, EH_SPEC_STMTS (eh_spec_block)); |
6c20b7e9 | 469 | |
52a11cbf RH |
470 | /* Strip cv quals, etc, from the specification types. */ |
471 | for (raises = NULL_TREE; | |
472 | raw_raises && TREE_VALUE (raw_raises); | |
473 | raw_raises = TREE_CHAIN (raw_raises)) | |
474 | raises = tree_cons (NULL_TREE, prepare_eh_type (TREE_VALUE (raw_raises)), | |
475 | raises); | |
6c20b7e9 | 476 | |
52a11cbf | 477 | EH_SPEC_RAISES (eh_spec_block) = raises; |
f30432d7 MS |
478 | } |
479 | ||
52a11cbf | 480 | /* Return a pointer to a buffer for an exception object of type TYPE. */ |
6467930b | 481 | |
52a11cbf | 482 | static tree |
5cc3d3b8 | 483 | do_allocate_exception (tree type) |
8d08fdba | 484 | { |
52a11cbf | 485 | tree fn; |
eb448459 | 486 | |
52a11cbf RH |
487 | fn = get_identifier ("__cxa_allocate_exception"); |
488 | if (IDENTIFIER_GLOBAL_VALUE (fn)) | |
489 | fn = IDENTIFIER_GLOBAL_VALUE (fn); | |
490 | else | |
f30432d7 | 491 | { |
52a11cbf | 492 | /* Declare void *__cxa_allocate_exception(size_t). */ |
c9f8536c | 493 | tree tmp = tree_cons (NULL_TREE, size_type_node, void_list_node); |
52a11cbf | 494 | fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp)); |
e00737d2 | 495 | } |
52a11cbf RH |
496 | |
497 | return build_function_call (fn, tree_cons (NULL_TREE, size_in_bytes (type), | |
498 | NULL_TREE)); | |
8d08fdba MS |
499 | } |
500 | ||
2ac8a0f9 JM |
501 | #if 0 |
502 | /* Call __cxa_free_exception from a cleanup. This is never invoked | |
6f30f1f1 | 503 | directly, but see the comment for stabilize_throw_expr. */ |
f4a23343 | 504 | |
c6160f8f | 505 | static tree |
5cc3d3b8 | 506 | do_free_exception (tree ptr) |
f4a23343 | 507 | { |
52a11cbf | 508 | tree fn; |
f4a23343 | 509 | |
52a11cbf | 510 | fn = get_identifier ("__cxa_free_exception"); |
f4a23343 JM |
511 | if (IDENTIFIER_GLOBAL_VALUE (fn)) |
512 | fn = IDENTIFIER_GLOBAL_VALUE (fn); | |
513 | else | |
514 | { | |
52a11cbf RH |
515 | /* Declare void __cxa_free_exception (void *). */ |
516 | fn = push_void_library_fn (fn, tree_cons (NULL_TREE, ptr_type_node, | |
517 | void_list_node)); | |
f4a23343 JM |
518 | } |
519 | ||
52a11cbf | 520 | return build_function_call (fn, tree_cons (NULL_TREE, ptr, NULL_TREE)); |
f4a23343 | 521 | } |
2ac8a0f9 | 522 | #endif |
f4a23343 | 523 | |
6f30f1f1 JM |
524 | /* Wrap all cleanups for TARGET_EXPRs in MUST_NOT_THROW_EXPR. |
525 | Called from build_throw via walk_tree_without_duplicates. */ | |
526 | ||
527 | static tree | |
5cc3d3b8 GDR |
528 | wrap_cleanups_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, |
529 | void *data ATTRIBUTE_UNUSED) | |
6f30f1f1 JM |
530 | { |
531 | tree exp = *tp; | |
532 | tree cleanup; | |
533 | ||
534 | /* Don't walk into types. */ | |
535 | if (TYPE_P (exp)) | |
536 | { | |
537 | *walk_subtrees = 0; | |
538 | return NULL_TREE; | |
539 | } | |
540 | if (TREE_CODE (exp) != TARGET_EXPR) | |
541 | return NULL_TREE; | |
542 | ||
543 | cleanup = TARGET_EXPR_CLEANUP (exp); | |
544 | if (cleanup) | |
545 | { | |
4e8dca1c | 546 | cleanup = build1 (MUST_NOT_THROW_EXPR, void_type_node, cleanup); |
6f30f1f1 JM |
547 | TARGET_EXPR_CLEANUP (exp) = cleanup; |
548 | } | |
549 | ||
550 | /* Keep iterating. */ | |
551 | return NULL_TREE; | |
552 | } | |
553 | ||
554 | /* Like stabilize_expr, but specifically for a thrown expression. When | |
555 | throwing a temporary class object, we want to construct it directly into | |
556 | the thrown exception, so we look past the TARGET_EXPR and stabilize the | |
557 | arguments of the call instead. | |
558 | ||
559 | The case where EXP is a call to a function returning a class is a bit of | |
560 | a grey area in the standard; it's unclear whether or not it should be | |
561 | allowed to throw. I'm going to say no, as that allows us to optimize | |
562 | this case without worrying about deallocating the exception object if it | |
563 | does. The alternatives would be either not optimizing this case, or | |
564 | wrapping the initialization in a TRY_CATCH_EXPR to call do_free_exception | |
565 | rather than in a MUST_NOT_THROW_EXPR, for this case only. */ | |
566 | ||
567 | static tree | |
5cc3d3b8 | 568 | stabilize_throw_expr (tree exp, tree *initp) |
6f30f1f1 JM |
569 | { |
570 | tree init_expr; | |
571 | ||
572 | if (TREE_CODE (exp) == TARGET_EXPR | |
573 | && TREE_CODE (TARGET_EXPR_INITIAL (exp)) == AGGR_INIT_EXPR | |
574 | && flag_elide_constructors) | |
575 | { | |
576 | tree aggr_init = AGGR_INIT_EXPR_CHECK (TARGET_EXPR_INITIAL (exp)); | |
577 | tree args = TREE_OPERAND (aggr_init, 1); | |
578 | tree newargs = NULL_TREE; | |
579 | tree *p = &newargs; | |
580 | ||
581 | init_expr = void_zero_node; | |
582 | for (; args; args = TREE_CHAIN (args)) | |
583 | { | |
bab076f7 | 584 | tree arg = TREE_VALUE (args); |
6f30f1f1 | 585 | tree arg_init_expr; |
6f30f1f1 | 586 | |
c246c65d JM |
587 | arg = stabilize_expr (arg, &arg_init_expr); |
588 | ||
589 | if (TREE_SIDE_EFFECTS (arg_init_expr)) | |
590 | init_expr = build (COMPOUND_EXPR, void_type_node, init_expr, | |
591 | arg_init_expr); | |
bab076f7 | 592 | *p = tree_cons (NULL_TREE, arg, NULL_TREE); |
6f30f1f1 JM |
593 | p = &TREE_CHAIN (*p); |
594 | } | |
595 | TREE_OPERAND (aggr_init, 1) = newargs; | |
596 | } | |
597 | else | |
598 | { | |
599 | exp = stabilize_expr (exp, &init_expr); | |
600 | } | |
601 | ||
602 | *initp = init_expr; | |
603 | return exp; | |
604 | } | |
605 | ||
52a11cbf | 606 | /* Build a throw expression. */ |
6467930b | 607 | |
52a11cbf | 608 | tree |
5cc3d3b8 | 609 | build_throw (tree exp) |
8d08fdba | 610 | { |
6874c264 | 611 | tree fn; |
8d08fdba | 612 | |
52a11cbf RH |
613 | if (exp == error_mark_node) |
614 | return exp; | |
615 | ||
616 | if (processing_template_decl) | |
617 | return build_min (THROW_EXPR, void_type_node, exp); | |
618 | ||
619 | if (exp == null_node) | |
33bd39a2 | 620 | warning ("throwing NULL, which has integral, not pointer type"); |
52a11cbf RH |
621 | |
622 | if (exp != NULL_TREE) | |
623 | { | |
624 | if (!is_admissible_throw_operand (exp)) | |
625 | return error_mark_node; | |
626 | } | |
627 | ||
8d2733ca | 628 | if (! doing_eh (1)) |
59ccf49d | 629 | return error_mark_node; |
8d08fdba | 630 | |
52a11cbf | 631 | if (exp && decl_is_java_type (TREE_TYPE (exp), 1)) |
e97f22c9 | 632 | { |
52a11cbf | 633 | tree fn = get_identifier ("_Jv_Throw"); |
e97f22c9 TT |
634 | if (IDENTIFIER_GLOBAL_VALUE (fn)) |
635 | fn = IDENTIFIER_GLOBAL_VALUE (fn); | |
636 | else | |
637 | { | |
52a11cbf | 638 | /* Declare void _Jv_Throw (void *). */ |
0c11ada6 JM |
639 | tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node); |
640 | tmp = build_function_type (ptr_type_node, tmp); | |
c00996a3 | 641 | fn = push_throw_library_fn (fn, tmp); |
e97f22c9 TT |
642 | } |
643 | ||
52a11cbf | 644 | exp = build_function_call (fn, tree_cons (NULL_TREE, exp, NULL_TREE)); |
e97f22c9 TT |
645 | } |
646 | else if (exp) | |
8d2733ca | 647 | { |
faae18ab | 648 | tree throw_type; |
52a11cbf | 649 | tree cleanup; |
52a11cbf RH |
650 | tree object, ptr; |
651 | tree tmp; | |
6f30f1f1 | 652 | tree temp_expr, allocate_expr; |
52a11cbf RH |
653 | |
654 | fn = get_identifier ("__cxa_throw"); | |
655 | if (IDENTIFIER_GLOBAL_VALUE (fn)) | |
656 | fn = IDENTIFIER_GLOBAL_VALUE (fn); | |
657 | else | |
658 | { | |
659 | /* The CLEANUP_TYPE is the internal type of a destructor. */ | |
660 | if (cleanup_type == NULL_TREE) | |
661 | { | |
662 | tmp = void_list_node; | |
663 | tmp = tree_cons (NULL_TREE, ptr_type_node, tmp); | |
664 | tmp = build_function_type (void_type_node, tmp); | |
665 | cleanup_type = build_pointer_type (tmp); | |
666 | } | |
667 | ||
668 | /* Declare void __cxa_throw (void*, void*, void (*)(void*)). */ | |
669 | /* ??? Second argument is supposed to be "std::type_info*". */ | |
670 | tmp = void_list_node; | |
671 | tmp = tree_cons (NULL_TREE, cleanup_type, tmp); | |
672 | tmp = tree_cons (NULL_TREE, ptr_type_node, tmp); | |
673 | tmp = tree_cons (NULL_TREE, ptr_type_node, tmp); | |
674 | tmp = build_function_type (void_type_node, tmp); | |
675 | fn = push_throw_library_fn (fn, tmp); | |
676 | } | |
59ccf49d | 677 | |
a3b49ccd | 678 | /* throw expression */ |
e92cc029 | 679 | /* First, decay it. */ |
f30432d7 | 680 | exp = decay_conversion (exp); |
a3b49ccd | 681 | |
52a11cbf RH |
682 | /* OK, this is kind of wacky. The standard says that we call |
683 | terminate when the exception handling mechanism, after | |
684 | completing evaluation of the expression to be thrown but | |
685 | before the exception is caught (_except.throw_), calls a | |
686 | user function that exits via an uncaught exception. | |
687 | ||
688 | So we have to protect the actual initialization of the | |
689 | exception object with terminate(), but evaluate the | |
690 | expression first. Since there could be temps in the | |
691 | expression, we need to handle that, too. We also expand | |
692 | the call to __cxa_allocate_exception first (which doesn't | |
693 | matter, since it can't throw). */ | |
694 | ||
6f30f1f1 JM |
695 | /* Pre-evaluate the thrown expression first, since if we allocated |
696 | the space first we would have to deal with cleaning it up if | |
697 | evaluating this expression throws. */ | |
698 | exp = stabilize_throw_expr (exp, &temp_expr); | |
6874c264 | 699 | |
52a11cbf | 700 | /* Allocate the space for the exception. */ |
6f30f1f1 JM |
701 | allocate_expr = do_allocate_exception (TREE_TYPE (exp)); |
702 | allocate_expr = get_target_expr (allocate_expr); | |
703 | ptr = TARGET_EXPR_SLOT (allocate_expr); | |
52a11cbf | 704 | object = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (exp)), ptr); |
3e411c3f | 705 | object = build_indirect_ref (object, NULL); |
faae18ab | 706 | |
6f30f1f1 JM |
707 | /* And initialize the exception object. */ |
708 | exp = build_init (object, exp, LOOKUP_ONLYCONVERTING); | |
52a11cbf | 709 | if (exp == error_mark_node) |
6f30f1f1 JM |
710 | { |
711 | error (" in thrown expression"); | |
712 | return error_mark_node; | |
713 | } | |
f4a23343 | 714 | |
4e8dca1c | 715 | exp = build1 (MUST_NOT_THROW_EXPR, void_type_node, exp); |
6f30f1f1 JM |
716 | /* Prepend the allocation. */ |
717 | exp = build (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp); | |
718 | if (temp_expr != void_zero_node) | |
719 | { | |
720 | /* Prepend the calculation of the throw expression. Also, force | |
721 | any cleanups from the expression to be evaluated here so that | |
722 | we don't have to do them during unwinding. But first wrap | |
723 | them in MUST_NOT_THROW_EXPR, since they are run after the | |
724 | exception object is initialized. */ | |
725 | walk_tree_without_duplicates (&temp_expr, wrap_cleanups_r, 0); | |
726 | exp = build (COMPOUND_EXPR, TREE_TYPE (exp), temp_expr, exp); | |
727 | exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp); | |
728 | } | |
72b7eeff | 729 | |
52a11cbf | 730 | throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object))); |
f4a23343 | 731 | |
52a11cbf RH |
732 | if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object))) |
733 | { | |
734 | cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)), | |
735 | complete_dtor_identifier, 0); | |
50ad9642 | 736 | cleanup = BASELINK_FUNCTIONS (cleanup); |
52a11cbf | 737 | mark_used (cleanup); |
dffd7eb6 | 738 | cxx_mark_addressable (cleanup); |
52a11cbf RH |
739 | /* Pretend it's a normal function. */ |
740 | cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup); | |
f30432d7 | 741 | } |
52a11cbf | 742 | else |
6874c264 JM |
743 | { |
744 | cleanup = build_int_2 (0, 0); | |
745 | TREE_TYPE (cleanup) = cleanup_type; | |
746 | } | |
72b7eeff | 747 | |
52a11cbf RH |
748 | tmp = tree_cons (NULL_TREE, cleanup, NULL_TREE); |
749 | tmp = tree_cons (NULL_TREE, throw_type, tmp); | |
750 | tmp = tree_cons (NULL_TREE, ptr, tmp); | |
52a11cbf | 751 | /* ??? Indicate that this function call throws throw_type. */ |
6f30f1f1 | 752 | tmp = build_function_call (fn, tmp); |
72b7eeff | 753 | |
6f30f1f1 JM |
754 | /* Tack on the initialization stuff. */ |
755 | exp = build (COMPOUND_EXPR, TREE_TYPE (tmp), exp, tmp); | |
8d2733ca MS |
756 | } |
757 | else | |
a3b49ccd | 758 | { |
52a11cbf | 759 | /* Rethrow current exception. */ |
6874c264 | 760 | |
52a11cbf | 761 | tree fn = get_identifier ("__cxa_rethrow"); |
6874c264 JM |
762 | if (IDENTIFIER_GLOBAL_VALUE (fn)) |
763 | fn = IDENTIFIER_GLOBAL_VALUE (fn); | |
764 | else | |
52a11cbf RH |
765 | { |
766 | /* Declare void __cxa_rethrow (void). */ | |
767 | fn = push_throw_library_fn | |
768 | (fn, build_function_type (void_type_node, void_list_node)); | |
769 | } | |
6874c264 | 770 | |
6f30f1f1 JM |
771 | /* ??? Indicate that this function call allows exceptions of the type |
772 | of the enclosing catch block (if known). */ | |
6874c264 | 773 | exp = build_function_call (fn, NULL_TREE); |
a3b49ccd | 774 | } |
8d2733ca | 775 | |
52a11cbf | 776 | exp = build1 (THROW_EXPR, void_type_node, exp); |
02020185 | 777 | |
52a11cbf | 778 | return exp; |
8d08fdba | 779 | } |
4cfbc546 NS |
780 | |
781 | /* Make sure TYPE is complete, pointer to complete, reference to | |
782 | complete, or pointer to cv void. Issue diagnostic on failure. | |
838dfd8a | 783 | Return the zero on failure and nonzero on success. FROM can be |
4cfbc546 NS |
784 | the expr or decl from whence TYPE came, if available. */ |
785 | ||
786 | static int | |
5cc3d3b8 | 787 | complete_ptr_ref_or_void_ptr_p (tree type, tree from) |
4cfbc546 NS |
788 | { |
789 | int is_ptr; | |
790 | ||
791 | /* Check complete. */ | |
792 | type = complete_type_or_else (type, from); | |
793 | if (!type) | |
794 | return 0; | |
795 | ||
796 | /* Or a pointer or ref to one, or cv void *. */ | |
797 | is_ptr = TREE_CODE (type) == POINTER_TYPE; | |
798 | if (is_ptr || TREE_CODE (type) == REFERENCE_TYPE) | |
799 | { | |
800 | tree core = TREE_TYPE (type); | |
801 | ||
b72801e2 | 802 | if (is_ptr && VOID_TYPE_P (core)) |
4cfbc546 NS |
803 | /* OK */; |
804 | else if (!complete_type_or_else (core, from)) | |
805 | return 0; | |
806 | } | |
807 | return 1; | |
808 | } | |
809 | ||
d064d75a GDR |
810 | /* Return truth-value if EXPRESSION is admissible in throw-expression, |
811 | i.e. if it is not of incomplete type or a pointer/reference to such | |
812 | a type or of an abstract class type. */ | |
813 | ||
814 | static bool | |
5cc3d3b8 | 815 | is_admissible_throw_operand (tree expr) |
d064d75a GDR |
816 | { |
817 | tree type = TREE_TYPE (expr); | |
818 | ||
819 | /* 15.1/4 [...] The type of the throw-expression shall not be an | |
820 | incomplete type, or a pointer or a reference to an incomplete | |
821 | type, other than void*, const void*, volatile void*, or | |
822 | const volatile void*. Except for these restriction and the | |
823 | restrictions on type matching mentioned in 15.3, the operand | |
824 | of throw is treated exactly as a function argument in a call | |
825 | (5.2.2) or the operand of a return statement. */ | |
826 | if (!complete_ptr_ref_or_void_ptr_p (type, expr)) | |
827 | return false; | |
828 | ||
829 | /* 10.4/3 An abstract class shall not be used as a parameter type, | |
830 | as a function return type or as type of an explicit | |
831 | conversion. */ | |
832 | else if (CLASS_TYPE_P (type) && CLASSTYPE_PURE_VIRTUALS (type)) | |
833 | { | |
33bd39a2 | 834 | error ("expression '%E' of abstract class type '%T' cannot be used in throw-expression", expr, type); |
d064d75a GDR |
835 | return false; |
836 | } | |
837 | ||
838 | return true; | |
839 | } | |
840 | ||
1660cb3a JM |
841 | /* Returns nonzero if FN is a declaration of a standard C library |
842 | function which is known not to throw. | |
843 | ||
844 | [lib.res.on.exception.handling]: None of the functions from the | |
845 | Standard C library shall report an error by throwing an | |
846 | exception, unless it calls a program-supplied function that | |
847 | throws an exception. */ | |
848 | ||
849 | #include "cfns.h" | |
850 | ||
851 | int | |
5cc3d3b8 | 852 | nothrow_libfn_p (tree fn) |
1660cb3a JM |
853 | { |
854 | tree id; | |
855 | ||
856 | if (TREE_PUBLIC (fn) | |
857 | && DECL_EXTERNAL (fn) | |
92643fea | 858 | && DECL_NAMESPACE_SCOPE_P (fn) |
eb68cb58 | 859 | && DECL_EXTERN_C_P (fn)) |
1660cb3a JM |
860 | /* OK */; |
861 | else | |
862 | /* Can't be a C library function. */ | |
863 | return 0; | |
864 | ||
865 | id = DECL_ASSEMBLER_NAME (fn); | |
866 | return !!libc_name_p (IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id)); | |
867 | } | |
2bc9f1d1 JM |
868 | |
869 | /* Returns nonzero if an exception of type FROM will be caught by a | |
870 | handler for type TO, as per [except.handle]. */ | |
871 | ||
872 | static int | |
5cc3d3b8 | 873 | can_convert_eh (tree to, tree from) |
2bc9f1d1 JM |
874 | { |
875 | if (TREE_CODE (to) == REFERENCE_TYPE) | |
876 | to = TREE_TYPE (to); | |
877 | if (TREE_CODE (from) == REFERENCE_TYPE) | |
878 | from = TREE_TYPE (from); | |
879 | ||
880 | if (TREE_CODE (to) == POINTER_TYPE && TREE_CODE (from) == POINTER_TYPE) | |
881 | { | |
882 | to = TREE_TYPE (to); | |
883 | from = TREE_TYPE (from); | |
884 | ||
885 | if (! at_least_as_qualified_p (to, from)) | |
886 | return 0; | |
887 | ||
888 | if (TREE_CODE (to) == VOID_TYPE) | |
889 | return 1; | |
890 | ||
891 | /* else fall through */ | |
892 | } | |
893 | ||
2d46ec83 | 894 | if (CLASS_TYPE_P (to) && CLASS_TYPE_P (from) |
2bc9f1d1 JM |
895 | && PUBLICLY_UNIQUELY_DERIVED_P (to, from)) |
896 | return 1; | |
897 | ||
898 | return 0; | |
899 | } | |
900 | ||
901 | /* Check whether any of HANDLERS are shadowed by another handler accepting | |
902 | TYPE. Note that the shadowing may not be complete; even if an exception | |
903 | of type B would be caught by a handler for A, there could be a derived | |
904 | class C for which A is an ambiguous base but B is not, so the handler | |
905 | for B would catch an exception of type C. */ | |
906 | ||
907 | static void | |
5cc3d3b8 | 908 | check_handlers_1 (tree master, tree handlers) |
2bc9f1d1 JM |
909 | { |
910 | tree type = TREE_TYPE (master); | |
911 | tree handler; | |
912 | ||
913 | for (handler = handlers; handler; handler = TREE_CHAIN (handler)) | |
914 | if (TREE_TYPE (handler) | |
915 | && can_convert_eh (type, TREE_TYPE (handler))) | |
916 | { | |
d479d37f | 917 | input_line = STMT_LINENO (handler); |
33bd39a2 | 918 | warning ("exception of type `%T' will be caught", |
2bc9f1d1 | 919 | TREE_TYPE (handler)); |
d479d37f | 920 | input_line = STMT_LINENO (master); |
33bd39a2 | 921 | warning (" by earlier handler for `%T'", type); |
2bc9f1d1 JM |
922 | break; |
923 | } | |
924 | } | |
925 | ||
926 | /* Given a chain of HANDLERs, make sure that they're OK. */ | |
927 | ||
928 | void | |
5cc3d3b8 | 929 | check_handlers (tree handlers) |
2bc9f1d1 JM |
930 | { |
931 | tree handler; | |
d479d37f NS |
932 | int save_line = input_line; |
933 | ||
2bc9f1d1 JM |
934 | for (handler = handlers; handler; handler = TREE_CHAIN (handler)) |
935 | { | |
936 | if (TREE_CHAIN (handler) == NULL_TREE) | |
937 | /* No more handlers; nothing to shadow. */; | |
938 | else if (TREE_TYPE (handler) == NULL_TREE) | |
939 | { | |
d479d37f | 940 | input_line = STMT_LINENO (handler); |
33bd39a2 | 941 | pedwarn |
2bc9f1d1 JM |
942 | ("`...' handler must be the last handler for its try block"); |
943 | } | |
944 | else | |
945 | check_handlers_1 (handler, TREE_CHAIN (handler)); | |
946 | } | |
d479d37f | 947 | input_line = save_line; |
2bc9f1d1 | 948 | } |