]>
Commit | Line | Data |
---|---|---|
8d08fdba | 1 | /* Handle exceptional things in C++. |
c913b6f1 KG |
2 | Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, |
3 | 2000, 2001 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 MS |
7 | |
8 | This file is part of GNU CC. | |
9 | ||
10 | GNU CC is free software; you can redistribute it and/or modify | |
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 | ||
15 | GNU CC is distributed in the hope that it will be useful, | |
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 | |
21 | along with GNU CC; 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" |
8d08fdba MS |
28 | #include "tree.h" |
29 | #include "rtl.h" | |
8f17b5c5 | 30 | #include "expr.h" |
8d08fdba MS |
31 | #include "cp-tree.h" |
32 | #include "flags.h" | |
8d2733ca | 33 | #include "obstack.h" |
21451173 | 34 | #include "output.h" |
6467930b | 35 | #include "except.h" |
54f92bfb | 36 | #include "toplev.h" |
8d08fdba | 37 | |
93ca4ba7 | 38 | static void push_eh_cleanup PARAMS ((tree)); |
52a11cbf | 39 | static tree prepare_eh_type PARAMS ((tree)); |
158991b7 | 40 | static tree build_eh_type_type PARAMS ((tree)); |
52a11cbf | 41 | static tree do_begin_catch PARAMS ((void)); |
93ca4ba7 | 42 | static int dtor_nothrow PARAMS ((tree)); |
52a11cbf RH |
43 | static tree do_end_catch PARAMS ((tree)); |
44 | static void push_eh_cleanup PARAMS ((tree)); | |
45 | static bool decl_is_java_type PARAMS ((tree decl, int err)); | |
52a11cbf RH |
46 | static void initialize_handler_parm PARAMS ((tree, tree)); |
47 | static tree do_allocate_exception PARAMS ((tree)); | |
158991b7 | 48 | static int complete_ptr_ref_or_void_ptr_p PARAMS ((tree, tree)); |
d064d75a | 49 | static bool is_admissible_throw_operand PARAMS ((tree)); |
fbd40359 ZW |
50 | static int can_convert_eh PARAMS ((tree, tree)); |
51 | static void check_handlers_1 PARAMS ((tree, tree)); | |
8d2733ca | 52 | |
8d2733ca | 53 | #include "decl.h" |
8d2733ca | 54 | #include "obstack.h" |
8d2733ca | 55 | |
52a11cbf | 56 | /* Sets up all the global eh stuff that needs to be initialized at the |
bbd0d54a | 57 | start of compilation. */ |
8d08fdba | 58 | |
8d08fdba | 59 | void |
8d2733ca | 60 | init_exception_processing () |
8d08fdba | 61 | { |
52a11cbf RH |
62 | tree tmp; |
63 | ||
2c73f9f5 | 64 | if (flag_honor_std) |
6bcedb4e | 65 | push_namespace (std_identifier); |
52a11cbf RH |
66 | |
67 | /* void std::terminate (); */ | |
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; |
2c73f9f5 ML |
72 | if (flag_honor_std) |
73 | pop_namespace (); | |
8ccc31eb | 74 | |
52a11cbf | 75 | protect_cleanup_actions = build_call (terminate_node, NULL_TREE); |
6874c264 | 76 | |
52a11cbf RH |
77 | /* void __cxa_call_unexpected(void *); */ |
78 | tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node); | |
79 | tmp = build_function_type (void_type_node, tmp); | |
80 | call_unexpected_node | |
81 | = push_throw_library_fn (get_identifier ("__cxa_call_unexpected"), tmp); | |
6874c264 | 82 | |
52a11cbf RH |
83 | eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS |
84 | ? "__gxx_personality_sj0" | |
85 | : "__gxx_personality_v0"); | |
6874c264 | 86 | |
52a11cbf | 87 | lang_eh_runtime_type = build_eh_type_type; |
6874c264 JM |
88 | } |
89 | ||
6874c264 | 90 | static tree |
52a11cbf | 91 | prepare_eh_type (type) |
f30432d7 | 92 | tree type; |
8d08fdba | 93 | { |
52a11cbf RH |
94 | if (type == NULL_TREE) |
95 | return type; | |
f30432d7 MS |
96 | if (type == error_mark_node) |
97 | return error_mark_node; | |
8d2733ca | 98 | |
e92cc029 | 99 | /* peel back references, so they match. */ |
f30432d7 MS |
100 | if (TREE_CODE (type) == REFERENCE_TYPE) |
101 | type = TREE_TYPE (type); | |
8d08fdba | 102 | |
e92cc029 | 103 | /* Peel off cv qualifiers. */ |
f30432d7 | 104 | type = TYPE_MAIN_VARIANT (type); |
8d2733ca | 105 | |
52a11cbf | 106 | return type; |
8d08fdba | 107 | } |
8d08fdba | 108 | |
e5f614d7 | 109 | /* Build the address of a typeinfo decl for use in the runtime |
52a11cbf | 110 | matching field of the exception model. */ |
5816cb14 AM |
111 | |
112 | static tree | |
52a11cbf | 113 | build_eh_type_type (type) |
5816cb14 AM |
114 | tree type; |
115 | { | |
5816cb14 | 116 | tree exp; |
5816cb14 | 117 | |
93ca4ba7 JM |
118 | if (type == NULL_TREE || type == error_mark_node) |
119 | return type; | |
5816cb14 | 120 | |
52a11cbf RH |
121 | if (decl_is_java_type (type, 0)) |
122 | exp = build_java_class_ref (TREE_TYPE (type)); | |
123 | else | |
124 | exp = get_tinfo_decl (type); | |
5816cb14 | 125 | |
e5f614d7 | 126 | mark_used (exp); |
db48b831 | 127 | exp = build1 (ADDR_EXPR, ptr_type_node, exp); |
5816cb14 | 128 | |
52a11cbf | 129 | return exp; |
5816cb14 AM |
130 | } |
131 | ||
52a11cbf RH |
132 | tree |
133 | build_exc_ptr () | |
134 | { | |
135 | return build (EXC_PTR_EXPR, ptr_type_node); | |
136 | } | |
137 | ||
138 | /* Build up a call to __cxa_begin_catch, to tell the runtime that the | |
139 | exception has been handled. */ | |
93ca4ba7 | 140 | |
52a11cbf RH |
141 | static tree |
142 | do_begin_catch () | |
9c606f69 | 143 | { |
52a11cbf RH |
144 | tree fn; |
145 | ||
146 | fn = get_identifier ("__cxa_begin_catch"); | |
147 | if (IDENTIFIER_GLOBAL_VALUE (fn)) | |
148 | fn = IDENTIFIER_GLOBAL_VALUE (fn); | |
149 | else | |
9c606f69 | 150 | { |
52a11cbf RH |
151 | /* Declare void* __cxa_begin_catch (void *). */ |
152 | tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node); | |
153 | fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp)); | |
9c606f69 | 154 | } |
52a11cbf RH |
155 | |
156 | return build_function_call (fn, tree_cons (NULL_TREE, build_exc_ptr (), | |
157 | NULL_TREE)); | |
9c606f69 AM |
158 | } |
159 | ||
93ca4ba7 JM |
160 | /* Returns nonzero if cleaning up an exception of type TYPE (which can be |
161 | NULL_TREE for a ... handler) will not throw an exception. */ | |
162 | ||
163 | static int | |
164 | dtor_nothrow (type) | |
165 | tree type; | |
166 | { | |
167 | tree fn; | |
168 | ||
169 | if (type == NULL_TREE) | |
170 | return 0; | |
171 | ||
172 | if (! TYPE_HAS_DESTRUCTOR (type)) | |
173 | return 1; | |
174 | ||
175 | fn = lookup_member (type, dtor_identifier, 0, 0); | |
176 | fn = TREE_VALUE (fn); | |
177 | return TREE_NOTHROW (fn); | |
178 | } | |
179 | ||
52a11cbf | 180 | /* Build up a call to __cxa_end_catch, to destroy the exception object |
93ca4ba7 | 181 | for the current catch block if no others are currently using it. */ |
6467930b | 182 | |
c7ae64f2 | 183 | static tree |
52a11cbf | 184 | do_end_catch (type) |
93ca4ba7 | 185 | tree type; |
72b7eeff | 186 | { |
6874c264 | 187 | tree fn, cleanup; |
52a11cbf RH |
188 | |
189 | fn = get_identifier ("__cxa_end_catch"); | |
6874c264 JM |
190 | if (IDENTIFIER_GLOBAL_VALUE (fn)) |
191 | fn = IDENTIFIER_GLOBAL_VALUE (fn); | |
192 | else | |
193 | { | |
52a11cbf RH |
194 | /* Declare void __cxa_end_catch (). */ |
195 | fn = push_void_library_fn (fn, void_list_node); | |
0c11ada6 JM |
196 | /* This can throw if the destructor for the exception throws. */ |
197 | TREE_NOTHROW (fn) = 0; | |
6874c264 | 198 | } |
72b7eeff | 199 | |
52a11cbf | 200 | cleanup = build_function_call (fn, NULL_TREE); |
93ca4ba7 | 201 | TREE_NOTHROW (cleanup) = dtor_nothrow (type); |
52a11cbf | 202 | |
c0700ea5 | 203 | return cleanup; |
c7ae64f2 JM |
204 | } |
205 | ||
206 | /* This routine creates the cleanup for the current exception. */ | |
72b7eeff | 207 | |
c7ae64f2 | 208 | static void |
93ca4ba7 JM |
209 | push_eh_cleanup (type) |
210 | tree type; | |
c7ae64f2 | 211 | { |
52a11cbf | 212 | finish_decl_cleanup (NULL_TREE, do_end_catch (type)); |
f4a23343 JM |
213 | } |
214 | ||
e97f22c9 TT |
215 | /* Return nonzero value if DECL is a Java type suitable for catch or |
216 | throw. */ | |
217 | ||
52a11cbf | 218 | static bool |
e97f22c9 TT |
219 | decl_is_java_type (decl, err) |
220 | tree decl; | |
221 | int err; | |
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. */ | |
234 | cp_error ("type `%T' is disallowed in Java `throw' or `catch'", | |
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. */ | |
252 | cp_error ("type `%T' is not derived from `java::lang::Throwable'", | |
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 | |
268 | choose_personality_routine (lang) | |
269 | enum languages lang; | |
52a11cbf RH |
270 | { |
271 | static enum { | |
272 | chose_none, | |
273 | chose_cpp, | |
274 | chose_java, | |
275 | gave_error | |
276 | } state; | |
277 | ||
278 | switch (state) | |
279 | { | |
1f730ff7 ZW |
280 | case gave_error: |
281 | return; | |
52a11cbf RH |
282 | |
283 | case chose_cpp: | |
1f730ff7 ZW |
284 | if (lang != lang_cplusplus) |
285 | goto give_error; | |
286 | return; | |
287 | ||
52a11cbf | 288 | case chose_java: |
1f730ff7 ZW |
289 | if (lang != lang_java) |
290 | goto give_error; | |
291 | return; | |
292 | ||
293 | case chose_none: | |
294 | ; /* proceed to language selection */ | |
295 | } | |
296 | ||
297 | switch (lang) | |
298 | { | |
299 | case lang_cplusplus: | |
300 | state = chose_cpp; | |
52a11cbf RH |
301 | break; |
302 | ||
1f730ff7 ZW |
303 | case lang_java: |
304 | state = chose_java; | |
305 | eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS | |
306 | ? "__gcj_personality_sj0" | |
307 | : "__gcj_personality_v0"); | |
52a11cbf | 308 | break; |
1f730ff7 ZW |
309 | |
310 | default: | |
311 | abort (); | |
52a11cbf | 312 | } |
1f730ff7 ZW |
313 | return; |
314 | ||
315 | give_error: | |
316 | error ("mixing C++ and Java catches in a single translation unit"); | |
317 | state = gave_error; | |
52a11cbf RH |
318 | } |
319 | ||
b35d4555 | 320 | /* Initialize the catch parameter DECL. */ |
6467930b | 321 | |
b35d4555 | 322 | static void |
52a11cbf | 323 | initialize_handler_parm (decl, exp) |
3c5c0849 | 324 | tree decl; |
52a11cbf | 325 | tree exp; |
8d08fdba | 326 | { |
b35d4555 MM |
327 | tree init; |
328 | tree init_type; | |
329 | ||
330 | /* Make sure we mark the catch param as used, otherwise we'll get a | |
331 | warning about an unused ((anonymous)). */ | |
332 | TREE_USED (decl) = 1; | |
333 | ||
52a11cbf RH |
334 | /* Figure out the type that the initializer is. Pointers are returned |
335 | adjusted by value from __cxa_begin_catch. Others are returned by | |
336 | reference. */ | |
b35d4555 | 337 | init_type = TREE_TYPE (decl); |
52a11cbf RH |
338 | if (TREE_CODE (init_type) != POINTER_TYPE |
339 | && TREE_CODE (init_type) != REFERENCE_TYPE) | |
b35d4555 MM |
340 | init_type = build_reference_type (init_type); |
341 | ||
1f730ff7 ZW |
342 | choose_personality_routine (decl_is_java_type (init_type, 0) |
343 | ? lang_java : lang_cplusplus); | |
b35d4555 MM |
344 | |
345 | /* Since pointers are passed by value, initialize a reference to | |
52a11cbf | 346 | pointer catch parm with the address of the temporary. */ |
b35d4555 MM |
347 | if (TREE_CODE (init_type) == REFERENCE_TYPE |
348 | && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE) | |
349 | exp = build_unary_op (ADDR_EXPR, exp, 1); | |
350 | ||
52a11cbf | 351 | exp = ocp_convert (init_type, exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0); |
b35d4555 MM |
352 | |
353 | init = convert_from_reference (exp); | |
354 | ||
355 | /* If the constructor for the catch parm exits via an exception, we | |
356 | must call terminate. See eh23.C. */ | |
357 | if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) | |
faf5394a | 358 | { |
b35d4555 MM |
359 | /* Generate the copy constructor call directly so we can wrap it. |
360 | See also expand_default_init. */ | |
361 | init = ocp_convert (TREE_TYPE (decl), init, | |
362 | CONV_IMPLICIT|CONV_FORCE_TEMP, 0); | |
52a11cbf | 363 | init = build1 (MUST_NOT_THROW_EXPR, TREE_TYPE (init), init); |
faf5394a MS |
364 | } |
365 | ||
b35d4555 MM |
366 | /* Let `cp_finish_decl' know that this initializer is ok. */ |
367 | DECL_INITIAL (decl) = error_mark_node; | |
368 | decl = pushdecl (decl); | |
8d2733ca | 369 | |
b35d4555 | 370 | start_decl_1 (decl); |
cd9f6678 | 371 | cp_finish_decl (decl, init, NULL_TREE, |
b35d4555 | 372 | LOOKUP_ONLYCONVERTING|DIRECT_BIND); |
5816cb14 AM |
373 | } |
374 | ||
b35d4555 | 375 | /* Call this to start a catch block. DECL is the catch parameter. */ |
5816cb14 | 376 | |
b35d4555 MM |
377 | tree |
378 | expand_start_catch_block (decl) | |
3c5c0849 | 379 | tree decl; |
5816cb14 | 380 | { |
b35d4555 MM |
381 | tree compound_stmt_1; |
382 | tree compound_stmt_2; | |
52a11cbf RH |
383 | tree exp = NULL_TREE; |
384 | tree type; | |
385 | bool is_java; | |
5816cb14 | 386 | |
b35d4555 MM |
387 | if (! doing_eh (1)) |
388 | return NULL_TREE; | |
5816cb14 | 389 | |
b35d4555 | 390 | /* Make sure this declaration is reasonable. */ |
3c5c0849 MM |
391 | if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE)) |
392 | decl = NULL_TREE; | |
5816cb14 | 393 | |
b35d4555 MM |
394 | /* Create a binding level for the eh_info and the exception object |
395 | cleanup. */ | |
396 | compound_stmt_1 = begin_compound_stmt (/*has_no_scope=*/0); | |
826840d9 | 397 | note_level_for_catch (); |
b35d4555 | 398 | |
52a11cbf RH |
399 | if (decl) |
400 | type = prepare_eh_type (TREE_TYPE (decl)); | |
401 | else | |
402 | type = NULL_TREE; | |
403 | begin_catch_block (type); | |
404 | ||
405 | is_java = false; | |
406 | if (decl) | |
e97f22c9 | 407 | { |
52a11cbf | 408 | tree init; |
5816cb14 | 409 | |
52a11cbf RH |
410 | if (decl_is_java_type (type, 1)) |
411 | { | |
412 | /* Java only passes object via pointer and doesn't require | |
413 | adjusting. The java object is immediately before the | |
414 | generic exception header. */ | |
415 | init = build_exc_ptr (); | |
416 | init = build1 (NOP_EXPR, build_pointer_type (type), init); | |
417 | init = build (MINUS_EXPR, TREE_TYPE (init), init, | |
418 | TYPE_SIZE_UNIT (TREE_TYPE (init))); | |
3e411c3f | 419 | init = build_indirect_ref (init, NULL); |
52a11cbf RH |
420 | is_java = true; |
421 | } | |
e97f22c9 | 422 | else |
52a11cbf RH |
423 | { |
424 | /* C++ requires that we call __cxa_begin_catch to get the | |
425 | pointer to the actual object. */ | |
426 | init = do_begin_catch (); | |
427 | } | |
428 | ||
429 | exp = create_temporary_var (ptr_type_node); | |
430 | DECL_REGISTER (exp) = 1; | |
431 | cp_finish_decl (exp, init, NULL_TREE, LOOKUP_ONLYCONVERTING); | |
432 | finish_expr_stmt (build_modify_expr (exp, INIT_EXPR, init)); | |
e97f22c9 TT |
433 | } |
434 | else | |
52a11cbf RH |
435 | finish_expr_stmt (do_begin_catch ()); |
436 | ||
437 | /* C++ requires that we call __cxa_end_catch at the end of | |
438 | processing the exception. */ | |
439 | if (! is_java) | |
440 | push_eh_cleanup (type); | |
5816cb14 | 441 | |
b35d4555 MM |
442 | /* Create a binding level for the parm. */ |
443 | compound_stmt_2 = begin_compound_stmt (/*has_no_scope=*/0); | |
5816cb14 | 444 | |
b35d4555 | 445 | if (decl) |
52a11cbf | 446 | initialize_handler_parm (decl, exp); |
5816cb14 | 447 | |
b35d4555 | 448 | return build_tree_list (compound_stmt_1, compound_stmt_2); |
5816cb14 AM |
449 | } |
450 | ||
f30432d7 | 451 | |
8d2733ca MS |
452 | /* Call this to end a catch block. Its responsible for emitting the |
453 | code to handle jumping back to the correct place, and for emitting | |
454 | the label to jump to if this catch block didn't match. */ | |
6467930b | 455 | |
824b9a4c | 456 | void |
b35d4555 MM |
457 | expand_end_catch_block (blocks) |
458 | tree blocks; | |
8d08fdba | 459 | { |
b35d4555 MM |
460 | tree compound_stmt_1 = blocks ? TREE_PURPOSE (blocks): NULL_TREE; |
461 | tree compound_stmt_2 = blocks ? TREE_VALUE (blocks): NULL_TREE; | |
462 | ||
f30432d7 MS |
463 | if (! doing_eh (1)) |
464 | return; | |
8d2733ca | 465 | |
0dde4175 JM |
466 | /* The exception being handled is rethrown if control reaches the end of |
467 | a handler of the function-try-block of a constructor or destructor. */ | |
468 | if (in_function_try_handler | |
469 | && (DECL_CONSTRUCTOR_P (current_function_decl) | |
470 | || DECL_DESTRUCTOR_P (current_function_decl))) | |
b35d4555 | 471 | finish_expr_stmt (build_throw (NULL_TREE)); |
0dde4175 | 472 | |
c7ae64f2 | 473 | /* Cleanup the EH parameter. */ |
b35d4555 | 474 | finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_2); |
46e8c075 | 475 | /* Cleanup the EH object. */ |
4a6ef811 | 476 | finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1); |
8d2733ca | 477 | } |
8d08fdba | 478 | |
b35d4555 | 479 | tree |
52a11cbf | 480 | begin_eh_spec_block () |
f30432d7 | 481 | { |
52a11cbf RH |
482 | tree r = build_stmt (EH_SPEC_BLOCK, NULL_TREE, NULL_TREE); |
483 | add_stmt (r); | |
484 | return r; | |
f30432d7 MS |
485 | } |
486 | ||
b35d4555 | 487 | void |
52a11cbf RH |
488 | finish_eh_spec_block (raw_raises, eh_spec_block) |
489 | tree raw_raises; | |
490 | tree eh_spec_block; | |
f30432d7 | 491 | { |
52a11cbf | 492 | tree raises; |
0c11ada6 | 493 | |
52a11cbf | 494 | RECHAIN_STMTS (eh_spec_block, EH_SPEC_STMTS (eh_spec_block)); |
6c20b7e9 | 495 | |
52a11cbf RH |
496 | /* Strip cv quals, etc, from the specification types. */ |
497 | for (raises = NULL_TREE; | |
498 | raw_raises && TREE_VALUE (raw_raises); | |
499 | raw_raises = TREE_CHAIN (raw_raises)) | |
500 | raises = tree_cons (NULL_TREE, prepare_eh_type (TREE_VALUE (raw_raises)), | |
501 | raises); | |
6c20b7e9 | 502 | |
52a11cbf | 503 | EH_SPEC_RAISES (eh_spec_block) = raises; |
f30432d7 MS |
504 | } |
505 | ||
52a11cbf | 506 | /* Return a pointer to a buffer for an exception object of type TYPE. */ |
6467930b | 507 | |
52a11cbf RH |
508 | static tree |
509 | do_allocate_exception (type) | |
510 | tree type; | |
8d08fdba | 511 | { |
52a11cbf | 512 | tree fn; |
eb448459 | 513 | |
52a11cbf RH |
514 | fn = get_identifier ("__cxa_allocate_exception"); |
515 | if (IDENTIFIER_GLOBAL_VALUE (fn)) | |
516 | fn = IDENTIFIER_GLOBAL_VALUE (fn); | |
517 | else | |
f30432d7 | 518 | { |
52a11cbf RH |
519 | /* Declare void *__cxa_allocate_exception(size_t). */ |
520 | tree tmp = tree_cons (NULL_TREE, c_size_type_node, void_list_node); | |
521 | fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp)); | |
e00737d2 | 522 | } |
52a11cbf RH |
523 | |
524 | return build_function_call (fn, tree_cons (NULL_TREE, size_in_bytes (type), | |
525 | NULL_TREE)); | |
8d08fdba MS |
526 | } |
527 | ||
2ac8a0f9 JM |
528 | #if 0 |
529 | /* Call __cxa_free_exception from a cleanup. This is never invoked | |
530 | directly. */ | |
f4a23343 | 531 | |
c6160f8f | 532 | static tree |
52a11cbf RH |
533 | do_free_exception (ptr) |
534 | tree ptr; | |
f4a23343 | 535 | { |
52a11cbf | 536 | tree fn; |
f4a23343 | 537 | |
52a11cbf | 538 | fn = get_identifier ("__cxa_free_exception"); |
f4a23343 JM |
539 | if (IDENTIFIER_GLOBAL_VALUE (fn)) |
540 | fn = IDENTIFIER_GLOBAL_VALUE (fn); | |
541 | else | |
542 | { | |
52a11cbf RH |
543 | /* Declare void __cxa_free_exception (void *). */ |
544 | fn = push_void_library_fn (fn, tree_cons (NULL_TREE, ptr_type_node, | |
545 | void_list_node)); | |
f4a23343 JM |
546 | } |
547 | ||
52a11cbf | 548 | return build_function_call (fn, tree_cons (NULL_TREE, ptr, NULL_TREE)); |
f4a23343 | 549 | } |
2ac8a0f9 | 550 | #endif |
f4a23343 | 551 | |
52a11cbf | 552 | /* Build a throw expression. */ |
6467930b | 553 | |
52a11cbf RH |
554 | tree |
555 | build_throw (exp) | |
8d2733ca | 556 | tree exp; |
8d08fdba | 557 | { |
6874c264 | 558 | tree fn; |
8d08fdba | 559 | |
52a11cbf RH |
560 | if (exp == error_mark_node) |
561 | return exp; | |
562 | ||
563 | if (processing_template_decl) | |
564 | return build_min (THROW_EXPR, void_type_node, exp); | |
565 | ||
566 | if (exp == null_node) | |
567 | cp_warning ("throwing NULL, which has integral, not pointer type"); | |
568 | ||
569 | if (exp != NULL_TREE) | |
570 | { | |
571 | if (!is_admissible_throw_operand (exp)) | |
572 | return error_mark_node; | |
573 | } | |
574 | ||
8d2733ca | 575 | if (! doing_eh (1)) |
59ccf49d | 576 | return error_mark_node; |
8d08fdba | 577 | |
52a11cbf | 578 | if (exp && decl_is_java_type (TREE_TYPE (exp), 1)) |
e97f22c9 | 579 | { |
52a11cbf | 580 | tree fn = get_identifier ("_Jv_Throw"); |
e97f22c9 TT |
581 | if (IDENTIFIER_GLOBAL_VALUE (fn)) |
582 | fn = IDENTIFIER_GLOBAL_VALUE (fn); | |
583 | else | |
584 | { | |
52a11cbf | 585 | /* Declare void _Jv_Throw (void *). */ |
0c11ada6 JM |
586 | tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node); |
587 | tmp = build_function_type (ptr_type_node, tmp); | |
c00996a3 | 588 | fn = push_throw_library_fn (fn, tmp); |
e97f22c9 TT |
589 | } |
590 | ||
52a11cbf | 591 | exp = build_function_call (fn, tree_cons (NULL_TREE, exp, NULL_TREE)); |
e97f22c9 TT |
592 | } |
593 | else if (exp) | |
8d2733ca | 594 | { |
faae18ab | 595 | tree throw_type; |
52a11cbf | 596 | tree cleanup; |
59ccf49d MM |
597 | tree stmt_expr; |
598 | tree compound_stmt; | |
52a11cbf RH |
599 | tree object, ptr; |
600 | tree tmp; | |
601 | ||
602 | fn = get_identifier ("__cxa_throw"); | |
603 | if (IDENTIFIER_GLOBAL_VALUE (fn)) | |
604 | fn = IDENTIFIER_GLOBAL_VALUE (fn); | |
605 | else | |
606 | { | |
607 | /* The CLEANUP_TYPE is the internal type of a destructor. */ | |
608 | if (cleanup_type == NULL_TREE) | |
609 | { | |
610 | tmp = void_list_node; | |
611 | tmp = tree_cons (NULL_TREE, ptr_type_node, tmp); | |
612 | tmp = build_function_type (void_type_node, tmp); | |
613 | cleanup_type = build_pointer_type (tmp); | |
614 | } | |
615 | ||
616 | /* Declare void __cxa_throw (void*, void*, void (*)(void*)). */ | |
617 | /* ??? Second argument is supposed to be "std::type_info*". */ | |
618 | tmp = void_list_node; | |
619 | tmp = tree_cons (NULL_TREE, cleanup_type, tmp); | |
620 | tmp = tree_cons (NULL_TREE, ptr_type_node, tmp); | |
621 | tmp = tree_cons (NULL_TREE, ptr_type_node, tmp); | |
622 | tmp = build_function_type (void_type_node, tmp); | |
623 | fn = push_throw_library_fn (fn, tmp); | |
624 | } | |
59ccf49d MM |
625 | |
626 | begin_init_stmts (&stmt_expr, &compound_stmt); | |
faae18ab | 627 | |
a3b49ccd | 628 | /* throw expression */ |
e92cc029 | 629 | /* First, decay it. */ |
f30432d7 | 630 | exp = decay_conversion (exp); |
a3b49ccd | 631 | |
52a11cbf RH |
632 | /* OK, this is kind of wacky. The standard says that we call |
633 | terminate when the exception handling mechanism, after | |
634 | completing evaluation of the expression to be thrown but | |
635 | before the exception is caught (_except.throw_), calls a | |
636 | user function that exits via an uncaught exception. | |
637 | ||
638 | So we have to protect the actual initialization of the | |
639 | exception object with terminate(), but evaluate the | |
640 | expression first. Since there could be temps in the | |
641 | expression, we need to handle that, too. We also expand | |
642 | the call to __cxa_allocate_exception first (which doesn't | |
643 | matter, since it can't throw). */ | |
644 | ||
645 | my_friendly_assert (stmts_are_full_exprs_p () == 1, 19990926); | |
646 | ||
647 | /* Store the throw expression into a temp. This can be less | |
648 | efficient than storing it into the allocated space directly, but | |
649 | if we allocated the space first we would have to deal with | |
650 | cleaning it up if evaluating this expression throws. */ | |
651 | if (TREE_SIDE_EFFECTS (exp)) | |
298d6f60 | 652 | { |
52a11cbf RH |
653 | tmp = create_temporary_var (TREE_TYPE (exp)); |
654 | DECL_INITIAL (tmp) = exp; | |
655 | cp_finish_decl (tmp, exp, NULL_TREE, LOOKUP_ONLYCONVERTING); | |
656 | exp = tmp; | |
298d6f60 | 657 | } |
6874c264 | 658 | |
52a11cbf RH |
659 | /* Allocate the space for the exception. */ |
660 | ptr = create_temporary_var (ptr_type_node); | |
661 | DECL_REGISTER (ptr) = 1; | |
662 | cp_finish_decl (ptr, NULL_TREE, NULL_TREE, LOOKUP_ONLYCONVERTING); | |
663 | tmp = do_allocate_exception (TREE_TYPE (exp)); | |
664 | tmp = build_modify_expr (ptr, INIT_EXPR, tmp); | |
665 | finish_expr_stmt (tmp); | |
f4a23343 | 666 | |
52a11cbf | 667 | object = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (exp)), ptr); |
3e411c3f | 668 | object = build_indirect_ref (object, NULL); |
faae18ab | 669 | |
52a11cbf RH |
670 | exp = build_modify_expr (object, INIT_EXPR, exp); |
671 | if (exp == error_mark_node) | |
672 | error (" in thrown expression"); | |
f4a23343 | 673 | |
2ac8a0f9 | 674 | exp = build1 (MUST_NOT_THROW_EXPR, TREE_TYPE (exp), exp); |
52a11cbf | 675 | finish_expr_stmt (exp); |
72b7eeff | 676 | |
52a11cbf | 677 | throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object))); |
f4a23343 | 678 | |
52a11cbf RH |
679 | if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object))) |
680 | { | |
681 | cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)), | |
682 | complete_dtor_identifier, 0); | |
683 | cleanup = TREE_VALUE (cleanup); | |
684 | mark_used (cleanup); | |
685 | mark_addressable (cleanup); | |
686 | /* Pretend it's a normal function. */ | |
687 | cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup); | |
f30432d7 | 688 | } |
52a11cbf | 689 | else |
6874c264 JM |
690 | { |
691 | cleanup = build_int_2 (0, 0); | |
692 | TREE_TYPE (cleanup) = cleanup_type; | |
693 | } | |
72b7eeff | 694 | |
52a11cbf RH |
695 | tmp = tree_cons (NULL_TREE, cleanup, NULL_TREE); |
696 | tmp = tree_cons (NULL_TREE, throw_type, tmp); | |
697 | tmp = tree_cons (NULL_TREE, ptr, tmp); | |
698 | tmp = build_function_call (fn, tmp); | |
699 | ||
700 | /* ??? Indicate that this function call throws throw_type. */ | |
72b7eeff | 701 | |
52a11cbf | 702 | finish_expr_stmt (tmp); |
59ccf49d MM |
703 | |
704 | exp = finish_init_stmts (stmt_expr, compound_stmt); | |
8d2733ca MS |
705 | } |
706 | else | |
a3b49ccd | 707 | { |
52a11cbf | 708 | /* Rethrow current exception. */ |
6874c264 | 709 | |
52a11cbf | 710 | tree fn = get_identifier ("__cxa_rethrow"); |
6874c264 JM |
711 | if (IDENTIFIER_GLOBAL_VALUE (fn)) |
712 | fn = IDENTIFIER_GLOBAL_VALUE (fn); | |
713 | else | |
52a11cbf RH |
714 | { |
715 | /* Declare void __cxa_rethrow (void). */ | |
716 | fn = push_throw_library_fn | |
717 | (fn, build_function_type (void_type_node, void_list_node)); | |
718 | } | |
6874c264 JM |
719 | |
720 | exp = build_function_call (fn, NULL_TREE); | |
a3b49ccd | 721 | } |
8d2733ca | 722 | |
52a11cbf | 723 | exp = build1 (THROW_EXPR, void_type_node, exp); |
02020185 | 724 | |
52a11cbf | 725 | return exp; |
8d08fdba | 726 | } |
4cfbc546 NS |
727 | |
728 | /* Make sure TYPE is complete, pointer to complete, reference to | |
729 | complete, or pointer to cv void. Issue diagnostic on failure. | |
730 | Return the zero on failure and non-zero on success. FROM can be | |
731 | the expr or decl from whence TYPE came, if available. */ | |
732 | ||
733 | static int | |
734 | complete_ptr_ref_or_void_ptr_p (type, from) | |
735 | tree type; | |
736 | tree from; | |
737 | { | |
738 | int is_ptr; | |
739 | ||
740 | /* Check complete. */ | |
741 | type = complete_type_or_else (type, from); | |
742 | if (!type) | |
743 | return 0; | |
744 | ||
745 | /* Or a pointer or ref to one, or cv void *. */ | |
746 | is_ptr = TREE_CODE (type) == POINTER_TYPE; | |
747 | if (is_ptr || TREE_CODE (type) == REFERENCE_TYPE) | |
748 | { | |
749 | tree core = TREE_TYPE (type); | |
750 | ||
b72801e2 | 751 | if (is_ptr && VOID_TYPE_P (core)) |
4cfbc546 NS |
752 | /* OK */; |
753 | else if (!complete_type_or_else (core, from)) | |
754 | return 0; | |
755 | } | |
756 | return 1; | |
757 | } | |
758 | ||
d064d75a GDR |
759 | /* Return truth-value if EXPRESSION is admissible in throw-expression, |
760 | i.e. if it is not of incomplete type or a pointer/reference to such | |
761 | a type or of an abstract class type. */ | |
762 | ||
763 | static bool | |
764 | is_admissible_throw_operand (expr) | |
765 | tree expr; | |
766 | { | |
767 | tree type = TREE_TYPE (expr); | |
768 | ||
769 | /* 15.1/4 [...] The type of the throw-expression shall not be an | |
770 | incomplete type, or a pointer or a reference to an incomplete | |
771 | type, other than void*, const void*, volatile void*, or | |
772 | const volatile void*. Except for these restriction and the | |
773 | restrictions on type matching mentioned in 15.3, the operand | |
774 | of throw is treated exactly as a function argument in a call | |
775 | (5.2.2) or the operand of a return statement. */ | |
776 | if (!complete_ptr_ref_or_void_ptr_p (type, expr)) | |
777 | return false; | |
778 | ||
779 | /* 10.4/3 An abstract class shall not be used as a parameter type, | |
780 | as a function return type or as type of an explicit | |
781 | conversion. */ | |
782 | else if (CLASS_TYPE_P (type) && CLASSTYPE_PURE_VIRTUALS (type)) | |
783 | { | |
784 | cp_error ("Expression '%E' of abstract class type '%T' cannot be used in throw-expression", expr, type); | |
785 | return false; | |
786 | } | |
787 | ||
788 | return true; | |
789 | } | |
790 | ||
1660cb3a JM |
791 | /* Returns nonzero if FN is a declaration of a standard C library |
792 | function which is known not to throw. | |
793 | ||
794 | [lib.res.on.exception.handling]: None of the functions from the | |
795 | Standard C library shall report an error by throwing an | |
796 | exception, unless it calls a program-supplied function that | |
797 | throws an exception. */ | |
798 | ||
799 | #include "cfns.h" | |
800 | ||
801 | int | |
802 | nothrow_libfn_p (fn) | |
803 | tree fn; | |
804 | { | |
805 | tree id; | |
806 | ||
807 | if (TREE_PUBLIC (fn) | |
808 | && DECL_EXTERNAL (fn) | |
92643fea | 809 | && DECL_NAMESPACE_SCOPE_P (fn) |
eb68cb58 | 810 | && DECL_EXTERN_C_P (fn)) |
1660cb3a JM |
811 | /* OK */; |
812 | else | |
813 | /* Can't be a C library function. */ | |
814 | return 0; | |
815 | ||
816 | id = DECL_ASSEMBLER_NAME (fn); | |
817 | return !!libc_name_p (IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id)); | |
818 | } | |
2bc9f1d1 JM |
819 | |
820 | /* Returns nonzero if an exception of type FROM will be caught by a | |
821 | handler for type TO, as per [except.handle]. */ | |
822 | ||
823 | static int | |
824 | can_convert_eh (to, from) | |
825 | tree to, from; | |
826 | { | |
827 | if (TREE_CODE (to) == REFERENCE_TYPE) | |
828 | to = TREE_TYPE (to); | |
829 | if (TREE_CODE (from) == REFERENCE_TYPE) | |
830 | from = TREE_TYPE (from); | |
831 | ||
832 | if (TREE_CODE (to) == POINTER_TYPE && TREE_CODE (from) == POINTER_TYPE) | |
833 | { | |
834 | to = TREE_TYPE (to); | |
835 | from = TREE_TYPE (from); | |
836 | ||
837 | if (! at_least_as_qualified_p (to, from)) | |
838 | return 0; | |
839 | ||
840 | if (TREE_CODE (to) == VOID_TYPE) | |
841 | return 1; | |
842 | ||
843 | /* else fall through */ | |
844 | } | |
845 | ||
2d46ec83 | 846 | if (CLASS_TYPE_P (to) && CLASS_TYPE_P (from) |
2bc9f1d1 JM |
847 | && PUBLICLY_UNIQUELY_DERIVED_P (to, from)) |
848 | return 1; | |
849 | ||
850 | return 0; | |
851 | } | |
852 | ||
853 | /* Check whether any of HANDLERS are shadowed by another handler accepting | |
854 | TYPE. Note that the shadowing may not be complete; even if an exception | |
855 | of type B would be caught by a handler for A, there could be a derived | |
856 | class C for which A is an ambiguous base but B is not, so the handler | |
857 | for B would catch an exception of type C. */ | |
858 | ||
859 | static void | |
860 | check_handlers_1 (master, handlers) | |
861 | tree master; | |
862 | tree handlers; | |
863 | { | |
864 | tree type = TREE_TYPE (master); | |
865 | tree handler; | |
866 | ||
867 | for (handler = handlers; handler; handler = TREE_CHAIN (handler)) | |
868 | if (TREE_TYPE (handler) | |
869 | && can_convert_eh (type, TREE_TYPE (handler))) | |
870 | { | |
871 | lineno = STMT_LINENO (handler); | |
872 | cp_warning ("exception of type `%T' will be caught", | |
873 | TREE_TYPE (handler)); | |
874 | lineno = STMT_LINENO (master); | |
875 | cp_warning (" by earlier handler for `%T'", type); | |
876 | break; | |
877 | } | |
878 | } | |
879 | ||
880 | /* Given a chain of HANDLERs, make sure that they're OK. */ | |
881 | ||
882 | void | |
883 | check_handlers (handlers) | |
884 | tree handlers; | |
885 | { | |
886 | tree handler; | |
887 | int save_line = lineno; | |
888 | for (handler = handlers; handler; handler = TREE_CHAIN (handler)) | |
889 | { | |
890 | if (TREE_CHAIN (handler) == NULL_TREE) | |
891 | /* No more handlers; nothing to shadow. */; | |
892 | else if (TREE_TYPE (handler) == NULL_TREE) | |
893 | { | |
894 | lineno = STMT_LINENO (handler); | |
895 | cp_pedwarn | |
896 | ("`...' handler must be the last handler for its try block"); | |
897 | } | |
898 | else | |
899 | check_handlers_1 (handler, TREE_CHAIN (handler)); | |
900 | } | |
901 | lineno = save_line; | |
902 | } |