]> gcc.gnu.org Git - gcc.git/blame - gcc/cp/except.c
Daily bump.
[gcc.git] / gcc / cp / except.c
CommitLineData
8d08fdba 1/* Handle exceptional things in C++.
a6ecf8b6 2 Copyright (C) 1989, 92-97, 1998, 1999 Free Software Foundation, Inc.
8d2733ca
MS
3 Contributed by Michael Tiemann <tiemann@cygnus.com>
4 Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
5 initial re-implementation courtesy Tad Hunt.
8d08fdba
MS
6
7This file is part of GNU CC.
8
9GNU CC is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
11the Free Software Foundation; either version 2, or (at your option)
12any later version.
13
14GNU CC is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with GNU CC; see the file COPYING. If not, write to
e9fa0c7c
RK
21the Free Software Foundation, 59 Temple Place - Suite 330,
22Boston, MA 02111-1307, USA. */
8d08fdba
MS
23
24
8d08fdba 25#include "config.h"
8d052bc7 26#include "system.h"
8d08fdba
MS
27#include "tree.h"
28#include "rtl.h"
29#include "cp-tree.h"
30#include "flags.h"
8d2733ca
MS
31#include "obstack.h"
32#include "expr.h"
21451173 33#include "output.h"
6467930b 34#include "except.h"
0021b564 35#include "defaults.h"
54f92bfb 36#include "toplev.h"
9a0d1e1b 37#include "eh-common.h"
8d08fdba 38
49c249e1 39static void push_eh_cleanup PROTO((void));
49c249e1 40static tree build_eh_type_type PROTO((tree));
69ac77ce
JL
41static tree call_eh_info PROTO((void));
42static void push_eh_info PROTO((void));
43static tree get_eh_info PROTO((void));
44static tree get_eh_value PROTO((void));
87603ed0 45#if 0
69ac77ce
JL
46static tree get_eh_type PROTO((void));
47static tree get_eh_caught PROTO((void));
48static tree get_eh_handlers PROTO((void));
e833cb11 49#endif
69ac77ce 50static tree do_pop_exception PROTO((void));
5816cb14 51static tree build_eh_type_type_ref PROTO((tree));
c6160f8f
JM
52static tree build_terminate_handler PROTO((void));
53static tree alloc_eh_object PROTO((tree));
4cfbc546 54static int complete_ptr_ref_or_void_ptr_p PROTO((tree, tree));
b35d4555 55static void initialize_handler_parm PROTO((tree));
59ccf49d 56static tree expand_throw PROTO((tree));
8d2733ca 57
8d2733ca 58#if 0
e92cc029 59/* This is the startup, and finish stuff per exception table. */
8d08fdba 60
8d2733ca
MS
61/* XXX - Tad: exception handling section */
62#ifndef EXCEPT_SECTION_ASM_OP
63#define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
64#endif
8d08fdba 65
8d2733ca 66#ifdef EXCEPT_SECTION_ASM_OP
8d08fdba 67
8d2733ca
MS
68 /* on machines which support it, the exception table lives in another section,
69 but it needs a label so we can reference it... This sets up that
70 label! */
71asm (EXCEPT_SECTION_ASM_OP);
72exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
73asm (TEXT_SECTION_ASM_OP);
8d08fdba 74
8d2733ca 75#endif /* EXCEPT_SECTION_ASM_OP */
8d08fdba 76
8d2733ca
MS
77#ifdef EXCEPT_SECTION_ASM_OP
78
79 /* we need to know where the end of the exception table is... so this
80 is how we do it! */
81
82asm (EXCEPT_SECTION_ASM_OP);
83exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
84asm (TEXT_SECTION_ASM_OP);
85
86#endif /* EXCEPT_SECTION_ASM_OP */
87
88#endif
8d08fdba 89
8d2733ca 90#include "decl.h"
8d2733ca
MS
91#include "insn-flags.h"
92#include "obstack.h"
8d2733ca
MS
93
94/* ======================================================================
95 Briefly the algorithm works like this:
96
97 When a constructor or start of a try block is encountered,
98 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
99 new entry in the unwind protection stack and returns a label to
100 output to start the protection for that block.
101
102 When a destructor or end try block is encountered, pop_eh_entry
6467930b
MS
103 (&eh_stack) is called. Pop_eh_entry () returns the eh_entry it
104 created when push_eh_entry () was called. The eh_entry structure
8d2733ca
MS
105 contains three things at this point. The start protect label,
106 the end protect label, and the exception handler label. The end
107 protect label should be output before the call to the destructor
108 (if any). If it was a destructor, then its parse tree is stored
6467930b 109 in the finalization variable in the eh_entry structure. Otherwise
8d2733ca 110 the finalization variable is set to NULL to reflect the fact that
38e01259 111 it is the end of a try block. Next, this modified eh_entry node
8d2733ca
MS
112 is enqueued in the finalizations queue by calling
113 enqueue_eh_entry (&queue,entry).
114
115 +---------------------------------------------------------------+
116 |XXX: Will need modification to deal with partially |
117 | constructed arrays of objects |
118 | |
119 | Basically, this consists of keeping track of how many |
120 | of the objects have been constructed already (this |
121 | should be in a register though, so that shouldn't be a |
122 | problem. |
123 +---------------------------------------------------------------+
124
125 When a catch block is encountered, there is a lot of work to be
126 done.
127
128 Since we don't want to generate the catch block inline with the
129 regular flow of the function, we need to have some way of doing
f30432d7
MS
130 so. Luckily, we can use sequences to defer the catch sections.
131 When the start of a catch block is encountered, we start the
132 sequence. After the catch block is generated, we end the
133 sequence.
134
8d2733ca
MS
135 Next we must insure that when the catch block is executed, all
136 finalizations for the matching try block have been completed. If
137 any of those finalizations throw an exception, we must call
138 terminate according to the ARM (section r.15.6.1). What this
139 means is that we need to dequeue and emit finalizations for each
6467930b 140 entry in the eh_queue until we get to an entry with a NULL
8d2733ca
MS
141 finalization field. For any of the finalization entries, if it
142 is not a call to terminate (), we must protect it by giving it
143 another start label, end label, and exception handler label,
144 setting its finalization tree to be a call to terminate (), and
6467930b 145 enqueue'ing this new eh_entry to be output at an outer level.
8d2733ca
MS
146 Finally, after all that is done, we can get around to outputting
147 the catch block which basically wraps all the "catch (...) {...}"
148 statements in a big if/then/else construct that matches the
149 correct block to call.
150
151 ===================================================================== */
152
8d2733ca
MS
153/* ====================================================================== */
154
8d2733ca 155/* sets up all the global eh stuff that needs to be initialized at the
bbd0d54a 156 start of compilation. */
8d08fdba 157
8d08fdba 158void
8d2733ca 159init_exception_processing ()
8d08fdba 160{
6633d636
MS
161 /* void vtype () */
162 tree vtype = build_function_type (void_type_node, void_list_node);
163
2c73f9f5
ML
164 if (flag_honor_std)
165 push_namespace (get_identifier ("std"));
c2a37c55 166 terminate_node = auto_function (get_identifier ("terminate"), vtype);
9cd64686 167 TREE_THIS_VOLATILE (terminate_node) = 1;
2c73f9f5
ML
168 if (flag_honor_std)
169 pop_namespace ();
8ccc31eb 170
9a0d1e1b
AM
171 set_exception_lang_code (EH_LANG_C_plus_plus);
172 set_exception_version_code (1);
9a0d1e1b 173
eb66be0e
MS
174 /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
175 be protected with __terminate. */
176 protect_cleanup_actions_with_terminate = 1;
8d2733ca
MS
177}
178
95e8dcba 179/* Retrieve a pointer to the cp_eh_info node for the current exception. */
6874c264 180
95e8dcba
JM
181static tree
182call_eh_info ()
6874c264 183{
95e8dcba 184 tree fn;
6874c264 185
e6cfb550 186 fn = get_identifier ("__start_cp_handler");
6874c264
JM
187 if (IDENTIFIER_GLOBAL_VALUE (fn))
188 fn = IDENTIFIER_GLOBAL_VALUE (fn);
189 else
190 {
a1622f83 191 tree t1, t, fields[7];
6874c264 192
e6cfb550 193 /* Declare cp_eh_info * __start_cp_handler (void),
6874c264 194 as defined in exception.cc. */
6874c264
JM
195
196 /* struct cp_eh_info. This must match exception.cc. Note that this
197 type is not pushed anywhere. */
33848bb0 198 t1= make_aggr_type (RECORD_TYPE);
4ce3d537 199 fields[0] = build_lang_decl (FIELD_DECL,
9a0d1e1b 200 get_identifier ("handler_label"), ptr_type_node);
4ce3d537 201 fields[1] = build_lang_decl (FIELD_DECL,
9a0d1e1b 202 get_identifier ("dynamic_handler_chain"), ptr_type_node);
4ce3d537 203 fields[2] = build_lang_decl (FIELD_DECL,
9a0d1e1b 204 get_identifier ("info"), ptr_type_node);
4ce3d537 205 fields[3] = build_lang_decl (FIELD_DECL,
e6cfb550 206 get_identifier ("table_index"), ptr_type_node);
9a0d1e1b
AM
207 /* N.B.: The fourth field LEN is expected to be
208 the number of fields - 1, not the total number of fields. */
e6cfb550 209 finish_builtin_type (t1, "eh_context", fields, 3, ptr_type_node);
9a0d1e1b
AM
210 t1 = build_pointer_type (t1);
211
33848bb0 212 t1= make_aggr_type (RECORD_TYPE);
4ce3d537 213 fields[0] = build_lang_decl (FIELD_DECL,
9a0d1e1b 214 get_identifier ("match_function"), ptr_type_node);
4ce3d537 215 fields[1] = build_lang_decl (FIELD_DECL,
9a0d1e1b 216 get_identifier ("language"), short_integer_type_node);
4ce3d537 217 fields[2] = build_lang_decl (FIELD_DECL,
9a0d1e1b
AM
218 get_identifier ("version"), short_integer_type_node);
219 /* N.B.: The fourth field LEN is expected to be
220 the number of fields - 1, not the total number of fields. */
5816cb14 221 finish_builtin_type (t1, "__eh_info", fields, 2, ptr_type_node);
33848bb0 222 t = make_aggr_type (RECORD_TYPE);
4ce3d537
MM
223 fields[0] = build_lang_decl (FIELD_DECL,
224 get_identifier ("eh_info"), t1);
225 fields[1] = build_lang_decl (FIELD_DECL, get_identifier ("value"),
226 ptr_type_node);
227 fields[2] = build_lang_decl (FIELD_DECL, get_identifier ("type"),
228 ptr_type_node);
229 fields[3] = build_lang_decl
6874c264
JM
230 (FIELD_DECL, get_identifier ("cleanup"),
231 build_pointer_type (build_function_type
232 (ptr_type_node, tree_cons
233 (NULL_TREE, ptr_type_node, void_list_node))));
4ce3d537
MM
234 fields[4] = build_lang_decl (FIELD_DECL, get_identifier ("caught"),
235 boolean_type_node);
236 fields[5] = build_lang_decl (FIELD_DECL, get_identifier ("next"),
237 build_pointer_type (t));
238 fields[6] = build_lang_decl
20b90169 239 (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node);
cf9d67e3
BK
240 /* N.B.: The fourth field LEN is expected to be
241 the number of fields - 1, not the total number of fields. */
a1622f83 242 finish_builtin_type (t, "cp_eh_info", fields, 6, ptr_type_node);
6874c264
JM
243 t = build_pointer_type (t);
244
245 /* And now the function. */
246 fn = build_lang_decl (FUNCTION_DECL, fn,
247 build_function_type (t, void_list_node));
248 DECL_EXTERNAL (fn) = 1;
249 TREE_PUBLIC (fn) = 1;
250 DECL_ARTIFICIAL (fn) = 1;
251 pushdecl_top_level (fn);
252 make_function_rtl (fn);
6874c264 253 }
a6ecf8b6 254 mark_used (fn);
95e8dcba
JM
255 return build_function_call (fn, NULL_TREE);
256}
257
258/* Retrieve a pointer to the cp_eh_info node for the current exception
259 and save it in the current binding level. */
260
261static void
262push_eh_info ()
263{
264 tree decl, fn = call_eh_info ();
6874c264
JM
265
266 /* Remember the pointer to the current exception info; it won't change
267 during this catch block. */
268 decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
269 TREE_TYPE (fn));
270 DECL_ARTIFICIAL (decl) = 1;
271 DECL_INITIAL (decl) = fn;
272 decl = pushdecl (decl);
cd9f6678 273 cp_finish_decl (decl, fn, NULL_TREE, 0);
6874c264
JM
274}
275
276/* Returns a reference to the cp_eh_info node for the current exception. */
277
278static tree
279get_eh_info ()
280{
281 /* Look for the pointer pushed in push_eh_info. */
282 tree t = lookup_name (get_identifier ("__exception_info"), 0);
283 return build_indirect_ref (t, NULL_PTR);
284}
285
286/* Returns a reference to the current exception object. */
287
288static tree
289get_eh_value ()
290{
291 return build_component_ref (get_eh_info (), get_identifier ("value"),
292 NULL_TREE, 0);
293}
294
295/* Returns a reference to the current exception type. */
296
87603ed0 297#if 0
6874c264
JM
298static tree
299get_eh_type ()
300{
301 return build_component_ref (get_eh_info (), get_identifier ("type"),
302 NULL_TREE, 0);
303}
304
305/* Returns a reference to whether or not the current exception
306 has been caught. */
307
308static tree
309get_eh_caught ()
310{
311 return build_component_ref (get_eh_info (), get_identifier ("caught"),
312 NULL_TREE, 0);
313}
314
20b90169
JM
315/* Returns a reference to whether or not the current exception
316 has been caught. */
317
318static tree
319get_eh_handlers ()
320{
321 return build_component_ref (get_eh_info (), get_identifier ("handlers"),
322 NULL_TREE, 0);
323}
e833cb11 324#endif
20b90169 325
f30432d7
MS
326/* Build a type value for use at runtime for a type that is matched
327 against by the exception handling system. */
6467930b 328
f30432d7
MS
329static tree
330build_eh_type_type (type)
331 tree type;
8d08fdba 332{
f30432d7
MS
333 if (type == error_mark_node)
334 return error_mark_node;
8d2733ca 335
e92cc029 336 /* peel back references, so they match. */
f30432d7
MS
337 if (TREE_CODE (type) == REFERENCE_TYPE)
338 type = TREE_TYPE (type);
8d08fdba 339
e92cc029 340 /* Peel off cv qualifiers. */
f30432d7 341 type = TYPE_MAIN_VARIANT (type);
8d2733ca 342
db48b831 343 return build1 (ADDR_EXPR, ptr_type_node, get_typeid_1 (type));
8d08fdba 344}
8d08fdba 345
db48b831
JM
346/* Build the address of a typeinfo function for use in the runtime
347 matching field of the new exception model */
5816cb14
AM
348
349static tree
350build_eh_type_type_ref (type)
351 tree type;
352{
5816cb14 353 tree exp;
5816cb14
AM
354
355 if (type == error_mark_node)
356 return error_mark_node;
357
358 /* peel back references, so they match. */
359 if (TREE_CODE (type) == REFERENCE_TYPE)
360 type = TREE_TYPE (type);
361
362 /* Peel off cv qualifiers. */
363 type = TYPE_MAIN_VARIANT (type);
364
db48b831
JM
365 exp = get_tinfo_fn (type);
366 exp = build1 (ADDR_EXPR, ptr_type_node, exp);
5816cb14 367
5816cb14
AM
368 return (exp);
369}
370
9c606f69 371/* This routine is called to mark all the symbols representing runtime
ae673f14 372 type functions in the exception table as having been referenced.
9c606f69
AM
373 This will make sure code is emitted for them. Called from finish_file. */
374void
375mark_all_runtime_matches ()
376{
377 int x,num;
378 void **ptr;
379 tree exp;
380
381 num = find_all_handler_type_matches (&ptr);
382 if (num == 0 || ptr == NULL)
383 return;
384
385 for (x=0; x <num; x++)
386 {
387 exp = (tree) ptr[x];
388 if (TREE_CODE (exp) == ADDR_EXPR)
389 {
390 exp = TREE_OPERAND (exp, 0);
391 if (TREE_CODE (exp) == FUNCTION_DECL)
392 TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (exp)) = 1;
393 }
394 }
395
396 free (ptr);
397}
398
c7ae64f2
JM
399/* Build up a call to __cp_pop_exception, to destroy the exception object
400 for the current catch block. HANDLER is either true or false, telling
401 the library whether or not it is being called from an exception handler;
402 if it is, it avoids destroying the object on rethrow. */
6467930b 403
c7ae64f2 404static tree
de35891e 405do_pop_exception ()
72b7eeff 406{
6874c264 407 tree fn, cleanup;
6874c264
JM
408 fn = get_identifier ("__cp_pop_exception");
409 if (IDENTIFIER_GLOBAL_VALUE (fn))
410 fn = IDENTIFIER_GLOBAL_VALUE (fn);
411 else
412 {
c7ae64f2
JM
413 /* Declare void __cp_pop_exception (void *),
414 as defined in exception.cc. */
c7ae64f2
JM
415 fn = build_lang_decl
416 (FUNCTION_DECL, fn,
417 build_function_type (void_type_node, tree_cons
de35891e 418 (NULL_TREE, ptr_type_node, void_list_node)));
6874c264
JM
419 DECL_EXTERNAL (fn) = 1;
420 TREE_PUBLIC (fn) = 1;
421 DECL_ARTIFICIAL (fn) = 1;
422 pushdecl_top_level (fn);
423 make_function_rtl (fn);
6874c264 424 }
72b7eeff 425
a6ecf8b6 426 mark_used (fn);
72b7eeff 427 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
c7ae64f2 428 cleanup = lookup_name (get_identifier ("__exception_info"), 0);
e1b3e07d 429 cleanup = build_function_call (fn, tree_cons
de35891e 430 (NULL_TREE, cleanup, NULL_TREE));
c0700ea5 431 return cleanup;
c7ae64f2
JM
432}
433
434/* This routine creates the cleanup for the current exception. */
72b7eeff 435
c7ae64f2
JM
436static void
437push_eh_cleanup ()
438{
b35d4555 439 finish_decl_cleanup (NULL_TREE, do_pop_exception ());
c7ae64f2 440}
72b7eeff 441
f4a23343
JM
442/* Build up a call to terminate on the function obstack, for use as an
443 exception handler. */
444
c6160f8f 445static tree
f4a23343
JM
446build_terminate_handler ()
447{
80048418 448 return build_function_call (terminate_node, NULL_TREE);
f4a23343
JM
449}
450
b35d4555 451/* Initialize the catch parameter DECL. */
6467930b 452
b35d4555
MM
453static void
454initialize_handler_parm (decl)
3c5c0849 455 tree decl;
8d08fdba 456{
b35d4555
MM
457 tree exp;
458 tree init;
459 tree init_type;
460
461 /* Make sure we mark the catch param as used, otherwise we'll get a
462 warning about an unused ((anonymous)). */
463 TREE_USED (decl) = 1;
464
465 /* Figure out the type that the initializer is. */
466 init_type = TREE_TYPE (decl);
467 if (TREE_CODE (init_type) != REFERENCE_TYPE
468 && TREE_CODE (init_type) != POINTER_TYPE)
469 init_type = build_reference_type (init_type);
470
471 exp = get_eh_value ();
472
473 /* Since pointers are passed by value, initialize a reference to
474 pointer catch parm with the address of the value slot. */
475 if (TREE_CODE (init_type) == REFERENCE_TYPE
476 && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
477 exp = build_unary_op (ADDR_EXPR, exp, 1);
478
479 exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
480
481 init = convert_from_reference (exp);
482
483 /* If the constructor for the catch parm exits via an exception, we
484 must call terminate. See eh23.C. */
485 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
faf5394a 486 {
b35d4555
MM
487 /* Generate the copy constructor call directly so we can wrap it.
488 See also expand_default_init. */
489 init = ocp_convert (TREE_TYPE (decl), init,
490 CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
491 init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
492 build_terminate_handler ());
faf5394a
MS
493 }
494
b35d4555
MM
495 /* Let `cp_finish_decl' know that this initializer is ok. */
496 DECL_INITIAL (decl) = error_mark_node;
497 decl = pushdecl (decl);
8d2733ca 498
b35d4555 499 start_decl_1 (decl);
cd9f6678 500 cp_finish_decl (decl, init, NULL_TREE,
b35d4555 501 LOOKUP_ONLYCONVERTING|DIRECT_BIND);
5816cb14
AM
502}
503
b35d4555 504/* Call this to start a catch block. DECL is the catch parameter. */
5816cb14 505
b35d4555
MM
506tree
507expand_start_catch_block (decl)
3c5c0849 508 tree decl;
5816cb14 509{
b35d4555
MM
510 tree compound_stmt_1;
511 tree compound_stmt_2;
512 tree type;
5816cb14 513
b35d4555
MM
514 if (! doing_eh (1))
515 return NULL_TREE;
5816cb14 516
b35d4555 517 /* Make sure this declaration is reasonable. */
3c5c0849
MM
518 if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE))
519 decl = NULL_TREE;
5816cb14 520
b35d4555
MM
521 /* Create a binding level for the eh_info and the exception object
522 cleanup. */
523 compound_stmt_1 = begin_compound_stmt (/*has_no_scope=*/0);
524
5816cb14 525 if (decl)
b35d4555 526 type = build_eh_type_type_ref (TREE_TYPE (decl));
5816cb14 527 else
b35d4555
MM
528 type = NULL_TREE;
529 begin_catch_block (type);
5816cb14
AM
530
531 push_eh_info ();
b35d4555 532 push_eh_cleanup ();
5816cb14 533
b35d4555
MM
534 /* Create a binding level for the parm. */
535 compound_stmt_2 = begin_compound_stmt (/*has_no_scope=*/0);
5816cb14 536
b35d4555
MM
537 if (decl)
538 initialize_handler_parm (decl);
5816cb14 539
b35d4555 540 return build_tree_list (compound_stmt_1, compound_stmt_2);
5816cb14
AM
541}
542
f30432d7 543
8d2733ca
MS
544/* Call this to end a catch block. Its responsible for emitting the
545 code to handle jumping back to the correct place, and for emitting
546 the label to jump to if this catch block didn't match. */
6467930b 547
824b9a4c 548void
b35d4555
MM
549expand_end_catch_block (blocks)
550 tree blocks;
8d08fdba 551{
b35d4555
MM
552 tree compound_stmt_1 = blocks ? TREE_PURPOSE (blocks): NULL_TREE;
553 tree compound_stmt_2 = blocks ? TREE_VALUE (blocks): NULL_TREE;
554
f30432d7
MS
555 if (! doing_eh (1))
556 return;
8d2733ca 557
0dde4175
JM
558 /* The exception being handled is rethrown if control reaches the end of
559 a handler of the function-try-block of a constructor or destructor. */
560 if (in_function_try_handler
561 && (DECL_CONSTRUCTOR_P (current_function_decl)
562 || DECL_DESTRUCTOR_P (current_function_decl)))
b35d4555 563 finish_expr_stmt (build_throw (NULL_TREE));
0dde4175 564
c7ae64f2 565 /* Cleanup the EH parameter. */
b35d4555 566 finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_2);
46e8c075 567 /* Cleanup the EH object. */
4a6ef811 568 finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1);
8d2733ca 569}
8d08fdba 570
6c20b7e9
JM
571/* An exception spec is implemented more or less like:
572
573 try {
574 function body;
575 } catch (...) {
576 void *p[] = { typeid(raises) };
577 __check_eh_spec (p, count);
578 }
579
580 __check_eh_spec in exception.cc handles all the details. */
8d2733ca 581
b35d4555 582tree
f30432d7
MS
583expand_start_eh_spec ()
584{
b35d4555 585 return begin_try_block ();
f30432d7
MS
586}
587
b35d4555
MM
588void
589expand_end_eh_spec (raises, try_block)
f30432d7 590 tree raises;
b35d4555 591 tree try_block;
f30432d7 592{
6c20b7e9 593 tree tmp, fn, decl, types = NULL_TREE;
b35d4555
MM
594 tree blocks;
595 tree handler;
6c20b7e9 596 int count = 0;
f30432d7 597
b35d4555
MM
598 finish_try_block (try_block);
599 handler = begin_handler ();
600 blocks = finish_handler_parms (NULL_TREE, handler);
f30432d7 601
6c20b7e9
JM
602 /* Build up an array of type_infos. */
603 for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
604 {
e1b3e07d 605 types = tree_cons
6c20b7e9
JM
606 (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
607 ++count;
608 }
eb66be0e 609
6c20b7e9
JM
610 types = build_nt (CONSTRUCTOR, NULL_TREE, types);
611 TREE_HAS_CONSTRUCTOR (types) = 1;
6874c264 612
6c20b7e9 613 /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */
52bf7d5d 614 tmp = build_cplus_array_type (const_ptr_type_node, NULL_TREE);
6c20b7e9
JM
615 decl = build_decl (VAR_DECL, NULL_TREE, tmp);
616 DECL_ARTIFICIAL (decl) = 1;
617 DECL_INITIAL (decl) = types;
46e8c075 618 DECL_CONTEXT (decl) = current_function_decl;
cd9f6678 619 cp_finish_decl (decl, types, NULL_TREE, 0);
6c20b7e9
JM
620
621 decl = decay_conversion (decl);
6874c264 622
6c20b7e9
JM
623 fn = get_identifier ("__check_eh_spec");
624 if (IDENTIFIER_GLOBAL_VALUE (fn))
625 fn = IDENTIFIER_GLOBAL_VALUE (fn);
626 else
f30432d7 627 {
6c20b7e9
JM
628 tmp = tree_cons
629 (NULL_TREE, integer_type_node, tree_cons
630 (NULL_TREE, TREE_TYPE (decl), void_list_node));
631 tmp = build_function_type (void_type_node, tmp);
f30432d7 632
6c20b7e9
JM
633 fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
634 DECL_EXTERNAL (fn) = 1;
635 TREE_PUBLIC (fn) = 1;
636 DECL_ARTIFICIAL (fn) = 1;
637 TREE_THIS_VOLATILE (fn) = 1;
638 pushdecl_top_level (fn);
639 make_function_rtl (fn);
6c20b7e9
JM
640 }
641
a6ecf8b6 642 mark_used (fn);
e1b3e07d
MM
643 tmp = tree_cons (NULL_TREE, build_int_2 (count, 0),
644 tree_cons (NULL_TREE, decl, NULL_TREE));
6c20b7e9 645 tmp = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), tmp);
b35d4555 646 finish_expr_stmt (tmp);
6c20b7e9 647
b35d4555
MM
648 finish_handler (blocks, handler);
649 finish_handler_sequence (try_block);
f30432d7
MS
650}
651
8d2733ca
MS
652/* This is called to expand all the toplevel exception handling
653 finalization for a function. It should only be called once per
654 function. */
6467930b 655
8d08fdba 656void
8d2733ca 657expand_exception_blocks ()
8d08fdba 658{
92b96838 659 do_pending_stack_adjust ();
eb448459 660
e00737d2 661 if (catch_clauses)
f30432d7 662 {
e00737d2
MS
663 rtx funcend = gen_label_rtx ();
664 emit_jump (funcend);
665
eb66be0e
MS
666 /* We cannot protect n regions this way if we must flow into the
667 EH region through the top of the region, as we have to with
668 the setjmp/longjmp approach. */
669 if (exceptions_via_longjmp == 0)
fb98cff6 670 expand_eh_region_start ();
f30432d7 671
e00737d2
MS
672 emit_insns (catch_clauses);
673 catch_clauses = NULL_RTX;
eb66be0e
MS
674
675 if (exceptions_via_longjmp == 0)
f4a23343 676 expand_eh_region_end (build_terminate_handler ());
eb66be0e 677
4a6ef811
MM
678 emit_insns (catch_clauses);
679 catch_clauses = NULL_RTX;
e00737d2
MS
680 emit_label (funcend);
681 }
8d08fdba
MS
682}
683
f4a23343
JM
684/* Return a pointer to a buffer for an exception object of type TYPE. */
685
c6160f8f 686static tree
f4a23343
JM
687alloc_eh_object (type)
688 tree type;
689{
690 tree fn, exp;
691
692 fn = get_identifier ("__eh_alloc");
693 if (IDENTIFIER_GLOBAL_VALUE (fn))
694 fn = IDENTIFIER_GLOBAL_VALUE (fn);
695 else
696 {
697 /* Declare __eh_alloc (size_t), as defined in exception.cc. */
698 tree tmp;
f4a23343
JM
699 tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
700 fn = build_lang_decl (FUNCTION_DECL, fn,
701 build_function_type (ptr_type_node, tmp));
702 DECL_EXTERNAL (fn) = 1;
703 TREE_PUBLIC (fn) = 1;
704 DECL_ARTIFICIAL (fn) = 1;
705 pushdecl_top_level (fn);
706 make_function_rtl (fn);
f4a23343
JM
707 }
708
a6ecf8b6 709 mark_used (fn);
e1b3e07d 710 exp = build_function_call (fn, tree_cons
f4a23343
JM
711 (NULL_TREE, size_in_bytes (type), NULL_TREE));
712 exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
713 return exp;
714}
715
6467930b 716/* Expand a throw statement. This follows the following
8d2733ca
MS
717 algorithm:
718
719 1. Allocate space to save the current PC onto the stack.
720 2. Generate and emit a label and save its address into the
e1cd6e56 721 newly allocated stack space since we can't save the pc directly.
8d2733ca
MS
722 3. If this is the first call to throw in this function:
723 generate a label for the throw block
724 4. jump to the throw block label. */
6467930b 725
225ff119 726static tree
8d2733ca
MS
727expand_throw (exp)
728 tree exp;
8d08fdba 729{
6874c264 730 tree fn;
8d08fdba 731
8d2733ca 732 if (! doing_eh (1))
59ccf49d 733 return error_mark_node;
8d08fdba 734
8d2733ca
MS
735 if (exp)
736 {
faae18ab 737 tree throw_type;
6874c264 738 tree cleanup = NULL_TREE, e;
59ccf49d
MM
739 tree stmt_expr;
740 tree compound_stmt;
741 tree try_block;
742
743 begin_init_stmts (&stmt_expr, &compound_stmt);
faae18ab 744
a3b49ccd 745 /* throw expression */
e92cc029 746 /* First, decay it. */
f30432d7 747 exp = decay_conversion (exp);
a3b49ccd 748
6874c264
JM
749 /* cleanup_type is void (*)(void *, int),
750 the internal type of a destructor. */
751 if (cleanup_type == NULL_TREE)
59ccf49d
MM
752 cleanup_type = build_pointer_type
753 (build_function_type
754 (void_type_node, tree_cons
755 (NULL_TREE, ptr_type_node, tree_cons
756 (NULL_TREE, integer_type_node, void_list_node))));
6874c264 757
08b24bda 758 if (TYPE_PTR_P (TREE_TYPE (exp)))
db48b831 759 throw_type = build_eh_type_type (TREE_TYPE (exp));
f30432d7
MS
760 else
761 {
f4a23343
JM
762 tree object, ptr;
763
764 /* OK, this is kind of wacky. The WP says that we call
46e8c075
MM
765 terminate when the exception handling mechanism, after
766 completing evaluation of the expression to be thrown but
767 before the exception is caught (_except.throw_), calls a
768 user function that exits via an uncaught exception.
f4a23343
JM
769
770 So we have to protect the actual initialization of the
771 exception object with terminate(), but evaluate the expression
772 first. We also expand the call to __eh_alloc
773 first. Since there could be temps in the expression, we need
774 to handle that, too. */
a50f0918 775
59ccf49d 776 my_friendly_assert (stmts_are_full_exprs_p == 1, 19990926);
f4a23343 777
f4a23343
JM
778 /* Store the throw expression into a temp. This can be less
779 efficient than storing it into the allocated space directly, but
780 oh well. To do this efficiently we would need to insinuate
781 ourselves into expand_call. */
782 if (TREE_SIDE_EFFECTS (exp))
783 {
f1dedc31 784 tree temp = create_temporary_var (TREE_TYPE (exp));
c37dc68e 785 DECL_INITIAL (temp) = exp;
cd9f6678 786 cp_finish_decl (temp, exp, NULL_TREE, LOOKUP_ONLYCONVERTING);
f4a23343
JM
787 exp = temp;
788 }
f4a23343
JM
789
790 /* Allocate the space for the exception. */
791 ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
59ccf49d 792 finish_expr_stmt (ptr);
f4a23343 793
59ccf49d 794 try_block = begin_try_block ();
f4a23343
JM
795 object = build_indirect_ref (ptr, NULL_PTR);
796 exp = build_modify_expr (object, INIT_EXPR, exp);
faae18ab 797
f30432d7 798 if (exp == error_mark_node)
8251199e 799 error (" in thrown expression");
faae18ab 800
59ccf49d
MM
801 finish_expr_stmt (exp);
802 finish_cleanup_try_block (try_block);
803 finish_cleanup (build_terminate_handler (), try_block);
f4a23343 804
db48b831 805 throw_type = build_eh_type_type (TREE_TYPE (object));
72b7eeff 806
6874c264
JM
807 if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
808 {
809 cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
810 dtor_identifier, 0);
811 cleanup = TREE_VALUE (cleanup);
e872bb7a 812 mark_used (cleanup);
6874c264
JM
813 mark_addressable (cleanup);
814 /* Pretend it's a normal function. */
815 cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
816 }
f4a23343
JM
817
818 exp = ptr;
f30432d7 819 }
faae18ab 820
bbeeb2b0
MM
821 /* Cast EXP to `void *' so that it will match the prototype for
822 __cp_push_exception. */
c37dc68e 823 exp = convert (ptr_type_node, exp);
bbeeb2b0 824
6874c264
JM
825 if (cleanup == NULL_TREE)
826 {
827 cleanup = build_int_2 (0, 0);
828 TREE_TYPE (cleanup) = cleanup_type;
829 }
72b7eeff 830
6874c264
JM
831 fn = get_identifier ("__cp_push_exception");
832 if (IDENTIFIER_GLOBAL_VALUE (fn))
833 fn = IDENTIFIER_GLOBAL_VALUE (fn);
834 else
835 {
836 /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
837 as defined in exception.cc. */
838 tree tmp;
6874c264
JM
839 tmp = tree_cons
840 (NULL_TREE, ptr_type_node, tree_cons
841 (NULL_TREE, ptr_type_node, tree_cons
842 (NULL_TREE, cleanup_type, void_list_node)));
843 fn = build_lang_decl (FUNCTION_DECL, fn,
844 build_function_type (void_type_node, tmp));
845 DECL_EXTERNAL (fn) = 1;
846 TREE_PUBLIC (fn) = 1;
847 DECL_ARTIFICIAL (fn) = 1;
848 pushdecl_top_level (fn);
849 make_function_rtl (fn);
6874c264 850 }
72b7eeff 851
a6ecf8b6 852 mark_used (fn);
e1b3e07d
MM
853 e = tree_cons (NULL_TREE, exp, tree_cons
854 (NULL_TREE, throw_type, tree_cons
855 (NULL_TREE, cleanup, NULL_TREE)));
59ccf49d
MM
856 finish_expr_stmt (build_function_call (fn, e));
857
858 exp = finish_init_stmts (stmt_expr, compound_stmt);
8d2733ca
MS
859 }
860 else
a3b49ccd 861 {
6874c264
JM
862 /* rethrow current exception; note that it's no longer caught. */
863
864 tree fn = get_identifier ("__uncatch_exception");
865 if (IDENTIFIER_GLOBAL_VALUE (fn))
866 fn = IDENTIFIER_GLOBAL_VALUE (fn);
867 else
868 {
869 /* Declare void __uncatch_exception (void)
870 as defined in exception.cc. */
6874c264
JM
871 fn = build_lang_decl (FUNCTION_DECL, fn,
872 build_function_type (void_type_node,
873 void_list_node));
874 DECL_EXTERNAL (fn) = 1;
875 TREE_PUBLIC (fn) = 1;
876 DECL_ARTIFICIAL (fn) = 1;
877 pushdecl_top_level (fn);
878 make_function_rtl (fn);
6874c264
JM
879 }
880
a6ecf8b6 881 mark_used (fn);
6874c264 882 exp = build_function_call (fn, NULL_TREE);
a3b49ccd 883 }
8d2733ca 884
59ccf49d 885 return exp;
f376e137 886}
8d2733ca
MS
887
888/* Build a throw expression. */
6467930b 889
8d2733ca
MS
890tree
891build_throw (e)
892 tree e;
893{
02020185
JM
894 if (e == error_mark_node)
895 return e;
896
897 if (processing_template_decl)
898 return build_min (THROW_EXPR, void_type_node, e);
899
e0f9a8bc 900 if (e == null_node)
8251199e 901 cp_warning ("throwing NULL, which has integral, not pointer type");
980c394c
NS
902
903 if (e != NULL_TREE)
904 {
4cfbc546
NS
905 if (!complete_ptr_ref_or_void_ptr_p (TREE_TYPE (e), e))
906 return error_mark_node;
980c394c 907 }
02020185 908
59ccf49d 909 e = expand_throw (e);
02020185
JM
910 e = build1 (THROW_EXPR, void_type_node, e);
911 TREE_SIDE_EFFECTS (e) = 1;
912 TREE_USED (e) = 1;
913
8d2733ca 914 return e;
8d08fdba 915}
4cfbc546
NS
916
917/* Make sure TYPE is complete, pointer to complete, reference to
918 complete, or pointer to cv void. Issue diagnostic on failure.
919 Return the zero on failure and non-zero on success. FROM can be
920 the expr or decl from whence TYPE came, if available. */
921
922static int
923complete_ptr_ref_or_void_ptr_p (type, from)
924 tree type;
925 tree from;
926{
927 int is_ptr;
928
929 /* Check complete. */
930 type = complete_type_or_else (type, from);
931 if (!type)
932 return 0;
933
934 /* Or a pointer or ref to one, or cv void *. */
935 is_ptr = TREE_CODE (type) == POINTER_TYPE;
936 if (is_ptr || TREE_CODE (type) == REFERENCE_TYPE)
937 {
938 tree core = TREE_TYPE (type);
939
940 if (is_ptr && same_type_p (TYPE_MAIN_VARIANT (core), void_type_node))
941 /* OK */;
942 else if (!complete_type_or_else (core, from))
943 return 0;
944 }
945 return 1;
946}
947
This page took 0.743697 seconds and 5 git commands to generate.