except.c revision 50643
1/* Handle exceptional things in C++. 2 Copyright (C) 1989, 92-97, 1998 Free Software Foundation, Inc. 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. 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 21the Free Software Foundation, 59 Temple Place - Suite 330, 22Boston, MA 02111-1307, USA. */ 23 24 25#include "config.h" 26#include "system.h" 27#include "tree.h" 28#include "rtl.h" 29#include "cp-tree.h" 30#include "flags.h" 31#include "obstack.h" 32#include "expr.h" 33#include "output.h" 34#include "except.h" 35#include "function.h" 36#include "defaults.h" 37#include "toplev.h" 38#include "eh-common.h" 39 40rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx)); 41 42/* Holds the fndecl for __builtin_return_address. */ 43tree builtin_return_address_fndecl; 44 45/* A couple of backend routines from m88k.c */ 46 47static void push_eh_cleanup PROTO((void)); 48static tree build_eh_type_type PROTO((tree)); 49static tree build_eh_type PROTO((tree)); 50static void expand_end_eh_spec PROTO((tree)); 51static tree call_eh_info PROTO((void)); 52static void push_eh_info PROTO((void)); 53static tree get_eh_info PROTO((void)); 54static tree get_eh_value PROTO((void)); 55static tree get_eh_type PROTO((void)); 56static tree get_eh_caught PROTO((void)); 57static tree get_eh_handlers PROTO((void)); 58static tree do_pop_exception PROTO((void)); 59static void process_start_catch_block PROTO((tree, tree)); 60static void process_start_catch_block_old PROTO((tree, tree)); 61static tree build_eh_type_type_ref PROTO((tree)); 62static tree build_terminate_handler PROTO((void)); 63static tree alloc_eh_object PROTO((tree)); 64 65#if 0 66/* This is the startup, and finish stuff per exception table. */ 67 68/* XXX - Tad: exception handling section */ 69#ifndef EXCEPT_SECTION_ASM_OP 70#define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits" 71#endif 72 73#ifdef EXCEPT_SECTION_ASM_OP 74 75 /* on machines which support it, the exception table lives in another section, 76 but it needs a label so we can reference it... This sets up that 77 label! */ 78asm (EXCEPT_SECTION_ASM_OP); 79exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 }; 80asm (TEXT_SECTION_ASM_OP); 81 82#endif /* EXCEPT_SECTION_ASM_OP */ 83 84#ifdef EXCEPT_SECTION_ASM_OP 85 86 /* we need to know where the end of the exception table is... so this 87 is how we do it! */ 88 89asm (EXCEPT_SECTION_ASM_OP); 90exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 }; 91asm (TEXT_SECTION_ASM_OP); 92 93#endif /* EXCEPT_SECTION_ASM_OP */ 94 95#endif 96 97#include "decl.h" 98#include "insn-flags.h" 99#include "obstack.h" 100 101/* ====================================================================== 102 Briefly the algorithm works like this: 103 104 When a constructor or start of a try block is encountered, 105 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a 106 new entry in the unwind protection stack and returns a label to 107 output to start the protection for that block. 108 109 When a destructor or end try block is encountered, pop_eh_entry 110 (&eh_stack) is called. Pop_eh_entry () returns the eh_entry it 111 created when push_eh_entry () was called. The eh_entry structure 112 contains three things at this point. The start protect label, 113 the end protect label, and the exception handler label. The end 114 protect label should be output before the call to the destructor 115 (if any). If it was a destructor, then its parse tree is stored 116 in the finalization variable in the eh_entry structure. Otherwise 117 the finalization variable is set to NULL to reflect the fact that 118 it is the end of a try block. Next, this modified eh_entry node 119 is enqueued in the finalizations queue by calling 120 enqueue_eh_entry (&queue,entry). 121 122 +---------------------------------------------------------------+ 123 |XXX: Will need modification to deal with partially | 124 | constructed arrays of objects | 125 | | 126 | Basically, this consists of keeping track of how many | 127 | of the objects have been constructed already (this | 128 | should be in a register though, so that shouldn't be a | 129 | problem. | 130 +---------------------------------------------------------------+ 131 132 When a catch block is encountered, there is a lot of work to be 133 done. 134 135 Since we don't want to generate the catch block inline with the 136 regular flow of the function, we need to have some way of doing 137 so. Luckily, we can use sequences to defer the catch sections. 138 When the start of a catch block is encountered, we start the 139 sequence. After the catch block is generated, we end the 140 sequence. 141 142 Next we must insure that when the catch block is executed, all 143 finalizations for the matching try block have been completed. If 144 any of those finalizations throw an exception, we must call 145 terminate according to the ARM (section r.15.6.1). What this 146 means is that we need to dequeue and emit finalizations for each 147 entry in the eh_queue until we get to an entry with a NULL 148 finalization field. For any of the finalization entries, if it 149 is not a call to terminate (), we must protect it by giving it 150 another start label, end label, and exception handler label, 151 setting its finalization tree to be a call to terminate (), and 152 enqueue'ing this new eh_entry to be output at an outer level. 153 Finally, after all that is done, we can get around to outputting 154 the catch block which basically wraps all the "catch (...) {...}" 155 statements in a big if/then/else construct that matches the 156 correct block to call. 157 158 ===================================================================== */ 159 160/* local globals for function calls 161 ====================================================================== */ 162 163/* Used to cache "terminate" and "__throw_type_match*". */ 164static tree Terminate, CatchMatch; 165 166/* Used to cache __find_first_exception_table_match for throw. */ 167static tree FirstExceptionMatch; 168 169/* Used to cache a call to __unwind_function. */ 170static tree Unwind; 171 172/* ====================================================================== */ 173 174 175/* ========================================================================= */ 176 177 178 179/* local globals - these local globals are for storing data necessary for 180 generating the exception table and code in the correct order. 181 182 ========================================================================= */ 183 184extern rtx catch_clauses; 185extern tree const_ptr_type_node; 186 187/* ========================================================================= */ 188 189/* sets up all the global eh stuff that needs to be initialized at the 190 start of compilation. 191 192 This includes: 193 - Setting up all the function call trees. */ 194 195void 196init_exception_processing () 197{ 198 /* void vtype () */ 199 tree vtype = build_function_type (void_type_node, void_list_node); 200 201 if (flag_honor_std) 202 push_namespace (get_identifier ("std")); 203 Terminate = auto_function (get_identifier ("terminate"), 204 vtype, NOT_BUILT_IN); 205 TREE_THIS_VOLATILE (Terminate) = 1; 206 if (flag_honor_std) 207 pop_namespace (); 208 209 push_lang_context (lang_name_c); 210 211 set_exception_lang_code (EH_LANG_C_plus_plus); 212 set_exception_version_code (1); 213 214 CatchMatch 215 = builtin_function (flag_rtti 216 ? "__throw_type_match_rtti" 217 : "__throw_type_match", 218 build_function_type (ptr_type_node, 219 tree_cons (NULL_TREE, const_ptr_type_node, 220 tree_cons (NULL_TREE, const_ptr_type_node, 221 tree_cons (NULL_TREE, ptr_type_node, 222 void_list_node)))), 223 NOT_BUILT_IN, NULL_PTR); 224 FirstExceptionMatch 225 = builtin_function ("__find_first_exception_table_match", 226 build_function_type (ptr_type_node, 227 tree_cons (NULL_TREE, ptr_type_node, 228 void_list_node)), 229 NOT_BUILT_IN, NULL_PTR); 230 Unwind 231 = builtin_function ("__unwind_function", 232 build_function_type (void_type_node, 233 tree_cons (NULL_TREE, ptr_type_node, 234 void_list_node)), 235 NOT_BUILT_IN, NULL_PTR); 236 237 pop_lang_context (); 238 239 /* If we use setjmp/longjmp EH, arrange for all cleanup actions to 240 be protected with __terminate. */ 241 protect_cleanup_actions_with_terminate = 1; 242} 243 244/* Retrieve a pointer to the cp_eh_info node for the current exception. */ 245 246static tree 247call_eh_info () 248{ 249 tree fn; 250 251 fn = get_identifier ("__cp_eh_info"); 252 if (IDENTIFIER_GLOBAL_VALUE (fn)) 253 fn = IDENTIFIER_GLOBAL_VALUE (fn); 254 else 255 { 256 tree t1, t, fields[7]; 257 258 /* Declare cp_eh_info * __cp_eh_info (void), 259 as defined in exception.cc. */ 260 push_obstacks_nochange (); 261 end_temporary_allocation (); 262 263 /* struct cp_eh_info. This must match exception.cc. Note that this 264 type is not pushed anywhere. */ 265 t1= make_lang_type (RECORD_TYPE); 266 fields[0] = build_lang_field_decl (FIELD_DECL, 267 get_identifier ("handler_label"), ptr_type_node); 268 fields[1] = build_lang_field_decl (FIELD_DECL, 269 get_identifier ("dynamic_handler_chain"), ptr_type_node); 270 fields[2] = build_lang_field_decl (FIELD_DECL, 271 get_identifier ("info"), ptr_type_node); 272 /* N.B.: The fourth field LEN is expected to be 273 the number of fields - 1, not the total number of fields. */ 274 finish_builtin_type (t1, "eh_context", fields, 2, ptr_type_node); 275 t1 = build_pointer_type (t1); 276 277 t1= make_lang_type (RECORD_TYPE); 278 fields[0] = build_lang_field_decl (FIELD_DECL, 279 get_identifier ("match_function"), ptr_type_node); 280 fields[1] = build_lang_field_decl (FIELD_DECL, 281 get_identifier ("language"), short_integer_type_node); 282 fields[2] = build_lang_field_decl (FIELD_DECL, 283 get_identifier ("version"), short_integer_type_node); 284 /* N.B.: The fourth field LEN is expected to be 285 the number of fields - 1, not the total number of fields. */ 286 finish_builtin_type (t1, "__eh_info", fields, 2, ptr_type_node); 287 t = make_lang_type (RECORD_TYPE); 288 fields[0] = build_lang_field_decl (FIELD_DECL, 289 get_identifier ("eh_info"), t1); 290 fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"), 291 ptr_type_node); 292 fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"), 293 ptr_type_node); 294 fields[3] = build_lang_field_decl 295 (FIELD_DECL, get_identifier ("cleanup"), 296 build_pointer_type (build_function_type 297 (ptr_type_node, tree_cons 298 (NULL_TREE, ptr_type_node, void_list_node)))); 299 fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"), 300 boolean_type_node); 301 fields[5] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"), 302 build_pointer_type (t)); 303 fields[6] = build_lang_field_decl 304 (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node); 305 /* N.B.: The fourth field LEN is expected to be 306 the number of fields - 1, not the total number of fields. */ 307 finish_builtin_type (t, "cp_eh_info", fields, 6, ptr_type_node); 308 t = build_pointer_type (t); 309 310 /* And now the function. */ 311 fn = build_lang_decl (FUNCTION_DECL, fn, 312 build_function_type (t, void_list_node)); 313 DECL_EXTERNAL (fn) = 1; 314 TREE_PUBLIC (fn) = 1; 315 DECL_ARTIFICIAL (fn) = 1; 316 pushdecl_top_level (fn); 317 make_function_rtl (fn); 318 assemble_external (fn); 319 pop_obstacks (); 320 } 321 return build_function_call (fn, NULL_TREE); 322} 323 324/* Retrieve a pointer to the cp_eh_info node for the current exception 325 and save it in the current binding level. */ 326 327static void 328push_eh_info () 329{ 330 tree decl, fn = call_eh_info (); 331 332 /* Remember the pointer to the current exception info; it won't change 333 during this catch block. */ 334 decl = build_decl (VAR_DECL, get_identifier ("__exception_info"), 335 TREE_TYPE (fn)); 336 DECL_ARTIFICIAL (decl) = 1; 337 DECL_INITIAL (decl) = fn; 338 decl = pushdecl (decl); 339 cp_finish_decl (decl, fn, NULL_TREE, 0, 0); 340} 341 342/* Returns a reference to the cp_eh_info node for the current exception. */ 343 344static tree 345get_eh_info () 346{ 347 /* Look for the pointer pushed in push_eh_info. */ 348 tree t = lookup_name (get_identifier ("__exception_info"), 0); 349 return build_indirect_ref (t, NULL_PTR); 350} 351 352/* Returns a reference to the current exception object. */ 353 354static tree 355get_eh_value () 356{ 357 return build_component_ref (get_eh_info (), get_identifier ("value"), 358 NULL_TREE, 0); 359} 360 361/* Returns a reference to the current exception type. */ 362 363static tree 364get_eh_type () 365{ 366 return build_component_ref (get_eh_info (), get_identifier ("type"), 367 NULL_TREE, 0); 368} 369 370/* Returns a reference to whether or not the current exception 371 has been caught. */ 372 373static tree 374get_eh_caught () 375{ 376 return build_component_ref (get_eh_info (), get_identifier ("caught"), 377 NULL_TREE, 0); 378} 379 380/* Returns a reference to whether or not the current exception 381 has been caught. */ 382 383static tree 384get_eh_handlers () 385{ 386 return build_component_ref (get_eh_info (), get_identifier ("handlers"), 387 NULL_TREE, 0); 388} 389 390/* Build a type value for use at runtime for a type that is matched 391 against by the exception handling system. */ 392 393static tree 394build_eh_type_type (type) 395 tree type; 396{ 397 char *typestring; 398 tree exp; 399 400 if (type == error_mark_node) 401 return error_mark_node; 402 403 /* peel back references, so they match. */ 404 if (TREE_CODE (type) == REFERENCE_TYPE) 405 type = TREE_TYPE (type); 406 407 /* Peel off cv qualifiers. */ 408 type = TYPE_MAIN_VARIANT (type); 409 410 if (flag_rtti) 411 { 412 return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type)); 413 } 414 415 typestring = build_overload_name (type, 1, 1); 416 exp = combine_strings (build_string (strlen (typestring)+1, typestring)); 417 return build1 (ADDR_EXPR, ptr_type_node, exp); 418} 419 420/* Build the address of a runtime type for use in the runtime matching 421 field of the new exception model */ 422 423static tree 424build_eh_type_type_ref (type) 425 tree type; 426{ 427 char *typestring; 428 tree exp; 429 430 if (type == error_mark_node) 431 return error_mark_node; 432 433 /* peel back references, so they match. */ 434 if (TREE_CODE (type) == REFERENCE_TYPE) 435 type = TREE_TYPE (type); 436 437 /* Peel off cv qualifiers. */ 438 type = TYPE_MAIN_VARIANT (type); 439 440 push_obstacks_nochange (); 441 end_temporary_allocation (); 442 443 if (flag_rtti) 444 { 445 exp = get_tinfo_fn (type); 446 TREE_USED (exp) = 1; 447 mark_inline_for_output (exp); 448 exp = build1 (ADDR_EXPR, ptr_type_node, exp); 449 } 450 else 451 { 452 typestring = build_overload_name (type, 1, 1); 453 exp = combine_strings (build_string (strlen (typestring)+1, typestring)); 454 exp = build1 (ADDR_EXPR, ptr_type_node, exp); 455 } 456 pop_obstacks (); 457 return (exp); 458} 459 460 461/* Build a type value for use at runtime for a exp that is thrown or 462 matched against by the exception handling system. */ 463 464static tree 465build_eh_type (exp) 466 tree exp; 467{ 468 if (flag_rtti) 469 { 470 exp = build_typeid (exp); 471 return build1 (ADDR_EXPR, ptr_type_node, exp); 472 } 473 return build_eh_type_type (TREE_TYPE (exp)); 474} 475 476/* This routine is called to mark all the symbols representing runtime 477 type functions in the exception table as haveing been referenced. 478 This will make sure code is emitted for them. Called from finish_file. */ 479void 480mark_all_runtime_matches () 481{ 482 int x,num; 483 void **ptr; 484 tree exp; 485 486 num = find_all_handler_type_matches (&ptr); 487 if (num == 0 || ptr == NULL) 488 return; 489 490 for (x=0; x <num; x++) 491 { 492 exp = (tree) ptr[x]; 493 if (TREE_CODE (exp) == ADDR_EXPR) 494 { 495 exp = TREE_OPERAND (exp, 0); 496 if (TREE_CODE (exp) == FUNCTION_DECL) 497 TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (exp)) = 1; 498 } 499 } 500 501 free (ptr); 502} 503 504/* Build up a call to __cp_pop_exception, to destroy the exception object 505 for the current catch block. HANDLER is either true or false, telling 506 the library whether or not it is being called from an exception handler; 507 if it is, it avoids destroying the object on rethrow. */ 508 509static tree 510do_pop_exception () 511{ 512 tree fn, cleanup; 513 fn = get_identifier ("__cp_pop_exception"); 514 if (IDENTIFIER_GLOBAL_VALUE (fn)) 515 fn = IDENTIFIER_GLOBAL_VALUE (fn); 516 else 517 { 518 /* Declare void __cp_pop_exception (void *), 519 as defined in exception.cc. */ 520 push_obstacks_nochange (); 521 end_temporary_allocation (); 522 fn = build_lang_decl 523 (FUNCTION_DECL, fn, 524 build_function_type (void_type_node, tree_cons 525 (NULL_TREE, ptr_type_node, void_list_node))); 526 DECL_EXTERNAL (fn) = 1; 527 TREE_PUBLIC (fn) = 1; 528 DECL_ARTIFICIAL (fn) = 1; 529 pushdecl_top_level (fn); 530 make_function_rtl (fn); 531 assemble_external (fn); 532 pop_obstacks (); 533 } 534 535 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */ 536 cleanup = lookup_name (get_identifier ("__exception_info"), 0); 537 cleanup = build_function_call (fn, expr_tree_cons 538 (NULL_TREE, cleanup, NULL_TREE)); 539 return cleanup; 540} 541 542/* This routine creates the cleanup for the current exception. */ 543 544static void 545push_eh_cleanup () 546{ 547 int yes; 548 549 expand_expr (build_unary_op (PREINCREMENT_EXPR, get_eh_handlers (), 1), 550 const0_rtx, VOIDmode, EXPAND_NORMAL); 551 552 yes = suspend_momentary (); 553 /* All cleanups must last longer than normal. */ 554 expand_decl_cleanup (NULL_TREE, do_pop_exception ()); 555 resume_momentary (yes); 556} 557 558/* Build up a call to terminate on the function obstack, for use as an 559 exception handler. */ 560 561static tree 562build_terminate_handler () 563{ 564 int yes = suspend_momentary (); 565 tree term = build_function_call (Terminate, NULL_TREE); 566 resume_momentary (yes); 567 return term; 568} 569 570/* Call this to start a catch block. Typename is the typename, and identifier 571 is the variable to place the object in or NULL if the variable doesn't 572 matter. If typename is NULL, that means its a "catch (...)" or catch 573 everything. In that case we don't need to do any type checking. 574 (ie: it ends up as the "else" clause rather than an "else if" clause) */ 575 576void 577expand_start_catch_block (declspecs, declarator) 578 tree declspecs, declarator; 579{ 580 tree decl; 581 582 if (processing_template_decl) 583 { 584 if (declspecs) 585 { 586 decl = grokdeclarator (declarator, declspecs, CATCHPARM, 587 1, NULL_TREE); 588 pushdecl (decl); 589 decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator), 590 copy_to_permanent (declspecs), 591 NULL_TREE); 592 add_tree (decl); 593 } 594 return; 595 } 596 597 if (! doing_eh (1)) 598 return; 599 600 if (flag_new_exceptions) 601 process_start_catch_block (declspecs, declarator); 602 else 603 process_start_catch_block_old (declspecs, declarator); 604} 605 606 607/* This function performs the expand_start_catch_block functionality for 608 exceptions implemented in the old style, where catch blocks were all 609 called, and had to check the runtime information themselves. */ 610 611static void 612process_start_catch_block_old (declspecs, declarator) 613 tree declspecs, declarator; 614{ 615 rtx false_label_rtx; 616 tree decl = NULL_TREE; 617 tree init; 618 619 /* Create a binding level for the eh_info and the exception object 620 cleanup. */ 621 pushlevel (0); 622 expand_start_bindings (0); 623 624 false_label_rtx = gen_label_rtx (); 625 push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE); 626 627 emit_line_note (input_filename, lineno); 628 629 push_eh_info (); 630 631 if (declspecs) 632 { 633 decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE); 634 635 if (decl == NULL_TREE) 636 error ("invalid catch parameter"); 637 } 638 639 if (decl) 640 { 641 tree exp; 642 rtx call_rtx, return_value_rtx; 643 tree init_type; 644 645 /* Make sure we mark the catch param as used, otherwise we'll get 646 a warning about an unused ((anonymous)). */ 647 TREE_USED (decl) = 1; 648 649 /* Figure out the type that the initializer is. */ 650 init_type = TREE_TYPE (decl); 651 if (TREE_CODE (init_type) != REFERENCE_TYPE 652 && TREE_CODE (init_type) != POINTER_TYPE) 653 init_type = build_reference_type (init_type); 654 655 exp = get_eh_value (); 656 657 /* Since pointers are passed by value, initialize a reference to 658 pointer catch parm with the address of the value slot. */ 659 if (TREE_CODE (init_type) == REFERENCE_TYPE 660 && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE) 661 exp = build_unary_op (ADDR_EXPR, exp, 1); 662 663 exp = expr_tree_cons (NULL_TREE, 664 build_eh_type_type (TREE_TYPE (decl)), 665 expr_tree_cons (NULL_TREE, 666 get_eh_type (), 667 expr_tree_cons (NULL_TREE, exp, NULL_TREE))); 668 exp = build_function_call (CatchMatch, exp); 669 call_rtx = expand_call (exp, NULL_RTX, 0); 670 671 return_value_rtx = hard_function_value (ptr_type_node, exp); 672 673 /* did the throw type match function return TRUE? */ 674 emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX, 675 GET_MODE (return_value_rtx), 0, 0); 676 677 /* if it returned FALSE, jump over the catch block, else fall into it */ 678 emit_jump_insn (gen_beq (false_label_rtx)); 679 680 push_eh_cleanup (); 681 682 /* Create a binding level for the parm. */ 683 pushlevel (0); 684 expand_start_bindings (0); 685 686 init = convert_from_reference (make_tree (init_type, call_rtx)); 687 688 /* If the constructor for the catch parm exits via an exception, we 689 must call terminate. See eh23.C. */ 690 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) 691 { 692 /* Generate the copy constructor call directly so we can wrap it. 693 See also expand_default_init. */ 694 init = ocp_convert (TREE_TYPE (decl), init, 695 CONV_IMPLICIT|CONV_FORCE_TEMP, 0); 696 init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init, 697 build_terminate_handler ()); 698 } 699 700 /* Let `cp_finish_decl' know that this initializer is ok. */ 701 DECL_INITIAL (decl) = init; 702 decl = pushdecl (decl); 703 704 start_decl_1 (decl); 705 cp_finish_decl (decl, DECL_INITIAL (decl), 706 NULL_TREE, 0, LOOKUP_ONLYCONVERTING); 707 } 708 else 709 { 710 push_eh_cleanup (); 711 712 /* Create a binding level for the parm. */ 713 pushlevel (0); 714 expand_start_bindings (0); 715 716 /* Fall into the catch all section. */ 717 } 718 719 init = build_modify_expr (get_eh_caught (), NOP_EXPR, integer_one_node); 720 expand_expr (init, const0_rtx, VOIDmode, EXPAND_NORMAL); 721 722 emit_line_note (input_filename, lineno); 723} 724 725/* This function performs the expand_start_catch_block functionality for 726 exceptions implemented in the new style. __throw determines whether 727 a handler needs to be called or not, so the handler itself has to do 728 nothing additionaal. */ 729 730static void 731process_start_catch_block (declspecs, declarator) 732 tree declspecs, declarator; 733{ 734 tree decl = NULL_TREE; 735 tree init; 736 737 /* Create a binding level for the eh_info and the exception object 738 cleanup. */ 739 pushlevel (0); 740 expand_start_bindings (0); 741 742 743 if (declspecs) 744 { 745 decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE); 746 747 if (decl == NULL_TREE) 748 error ("invalid catch parameter"); 749 } 750 751 if (decl) 752 start_catch_handler (build_eh_type_type_ref (TREE_TYPE (decl))); 753 else 754 start_catch_handler (CATCH_ALL_TYPE); 755 756 emit_line_note (input_filename, lineno); 757 758 push_eh_info (); 759 760 if (decl) 761 { 762 tree exp; 763 tree init_type; 764 765 /* Make sure we mark the catch param as used, otherwise we'll get 766 a warning about an unused ((anonymous)). */ 767 TREE_USED (decl) = 1; 768 769 /* Figure out the type that the initializer is. */ 770 init_type = TREE_TYPE (decl); 771 if (TREE_CODE (init_type) != REFERENCE_TYPE 772 && TREE_CODE (init_type) != POINTER_TYPE) 773 init_type = build_reference_type (init_type); 774 775 exp = get_eh_value (); 776 777 /* Since pointers are passed by value, initialize a reference to 778 pointer catch parm with the address of the value slot. */ 779 if (TREE_CODE (init_type) == REFERENCE_TYPE 780 && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE) 781 exp = build_unary_op (ADDR_EXPR, exp, 1); 782 783 exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0); 784 785 push_eh_cleanup (); 786 787 /* Create a binding level for the parm. */ 788 pushlevel (0); 789 expand_start_bindings (0); 790 791 init = convert_from_reference (exp); 792 793 /* If the constructor for the catch parm exits via an exception, we 794 must call terminate. See eh23.C. */ 795 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) 796 { 797 /* Generate the copy constructor call directly so we can wrap it. 798 See also expand_default_init. */ 799 init = ocp_convert (TREE_TYPE (decl), init, 800 CONV_IMPLICIT|CONV_FORCE_TEMP, 0); 801 init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init, 802 build_terminate_handler ()); 803 } 804 805 /* Let `cp_finish_decl' know that this initializer is ok. */ 806 DECL_INITIAL (decl) = init; 807 decl = pushdecl (decl); 808 809 cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING); 810 } 811 else 812 { 813 push_eh_cleanup (); 814 815 /* Create a binding level for the parm. */ 816 pushlevel (0); 817 expand_start_bindings (0); 818 819 /* Fall into the catch all section. */ 820 } 821 822 init = build_modify_expr (get_eh_caught (), NOP_EXPR, integer_one_node); 823 expand_expr (init, const0_rtx, VOIDmode, EXPAND_NORMAL); 824 825 emit_line_note (input_filename, lineno); 826} 827 828 829 830/* Call this to end a catch block. Its responsible for emitting the 831 code to handle jumping back to the correct place, and for emitting 832 the label to jump to if this catch block didn't match. */ 833 834void 835expand_end_catch_block () 836{ 837 if (! doing_eh (1)) 838 return; 839 840 /* Cleanup the EH parameter. */ 841 expand_end_bindings (getdecls (), kept_level_p (), 0); 842 poplevel (kept_level_p (), 1, 0); 843 844 /* Cleanup the EH object. */ 845 expand_end_bindings (getdecls (), kept_level_p (), 0); 846 poplevel (kept_level_p (), 1, 0); 847 848 /* Fall to outside the try statement when done executing handler and 849 we fall off end of handler. This is jump Lresume in the 850 documentation. */ 851 expand_goto (top_label_entry (&caught_return_label_stack)); 852 853 /* label we emit to jump to if this catch block didn't match. */ 854 /* This the closing } in the `if (eq) {' of the documentation. */ 855 if (! flag_new_exceptions) 856 emit_label (pop_label_entry (&false_label_stack)); 857} 858 859/* An exception spec is implemented more or less like: 860 861 try { 862 function body; 863 } catch (...) { 864 void *p[] = { typeid(raises) }; 865 __check_eh_spec (p, count); 866 } 867 868 __check_eh_spec in exception.cc handles all the details. */ 869 870void 871expand_start_eh_spec () 872{ 873 expand_start_try_stmts (); 874} 875 876static void 877expand_end_eh_spec (raises) 878 tree raises; 879{ 880 tree tmp, fn, decl, types = NULL_TREE; 881 int count = 0; 882 883 expand_start_all_catch (); 884 expand_start_catch_block (NULL_TREE, NULL_TREE); 885 886 /* Build up an array of type_infos. */ 887 for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises)) 888 { 889 types = expr_tree_cons 890 (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types); 891 ++count; 892 } 893 894 types = build_nt (CONSTRUCTOR, NULL_TREE, types); 895 TREE_HAS_CONSTRUCTOR (types) = 1; 896 897 /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */ 898 tmp = build_array_type (const_ptr_type_node, NULL_TREE); 899 decl = build_decl (VAR_DECL, NULL_TREE, tmp); 900 DECL_ARTIFICIAL (decl) = 1; 901 DECL_INITIAL (decl) = types; 902 cp_finish_decl (decl, types, NULL_TREE, 0, 0); 903 904 decl = decay_conversion (decl); 905 906 fn = get_identifier ("__check_eh_spec"); 907 if (IDENTIFIER_GLOBAL_VALUE (fn)) 908 fn = IDENTIFIER_GLOBAL_VALUE (fn); 909 else 910 { 911 push_obstacks_nochange (); 912 end_temporary_allocation (); 913 914 tmp = tree_cons 915 (NULL_TREE, integer_type_node, tree_cons 916 (NULL_TREE, TREE_TYPE (decl), void_list_node)); 917 tmp = build_function_type (void_type_node, tmp); 918 919 fn = build_lang_decl (FUNCTION_DECL, fn, tmp); 920 DECL_EXTERNAL (fn) = 1; 921 TREE_PUBLIC (fn) = 1; 922 DECL_ARTIFICIAL (fn) = 1; 923 TREE_THIS_VOLATILE (fn) = 1; 924 pushdecl_top_level (fn); 925 make_function_rtl (fn); 926 assemble_external (fn); 927 pop_obstacks (); 928 } 929 930 tmp = expr_tree_cons (NULL_TREE, build_int_2 (count, 0), expr_tree_cons 931 (NULL_TREE, decl, NULL_TREE)); 932 tmp = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), tmp); 933 expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL); 934 935 expand_end_catch_block (); 936 expand_end_all_catch (); 937} 938 939/* This is called to expand all the toplevel exception handling 940 finalization for a function. It should only be called once per 941 function. */ 942 943void 944expand_exception_blocks () 945{ 946 do_pending_stack_adjust (); 947 push_to_sequence (catch_clauses); 948 expand_leftover_cleanups (); 949 do_pending_stack_adjust (); 950 catch_clauses = get_insns (); 951 end_sequence (); 952 953 /* Do this after we expand leftover cleanups, so that the 954 expand_eh_region_end that expand_end_eh_spec does will match the 955 right expand_eh_region_start, and make sure it comes out before 956 the terminate protected region. */ 957 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl))) 958 { 959 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl))); 960 do_pending_stack_adjust (); 961 push_to_sequence (catch_clauses); 962 expand_leftover_cleanups (); 963 do_pending_stack_adjust (); 964 catch_clauses = get_insns (); 965 end_sequence (); 966 } 967 968 if (catch_clauses) 969 { 970 rtx funcend = gen_label_rtx (); 971 emit_jump (funcend); 972 973 /* We cannot protect n regions this way if we must flow into the 974 EH region through the top of the region, as we have to with 975 the setjmp/longjmp approach. */ 976 if (exceptions_via_longjmp == 0) 977 expand_eh_region_start (); 978 979 emit_insns (catch_clauses); 980 catch_clauses = NULL_RTX; 981 982 if (exceptions_via_longjmp == 0) 983 expand_eh_region_end (build_terminate_handler ()); 984 985 expand_leftover_cleanups (); 986 987 emit_label (funcend); 988 } 989} 990 991tree 992start_anon_func () 993{ 994 static int counter = 0; 995 int old_interface_unknown = interface_unknown; 996 char name[32]; 997 tree params; 998 tree t; 999 1000 push_cp_function_context (NULL_TREE); 1001 push_to_top_level (); 1002 1003 /* No need to mangle this. */ 1004 push_lang_context (lang_name_c); 1005 1006 interface_unknown = 1; 1007 1008 params = void_list_node; 1009 /* tcf stands for throw clean function. */ 1010 sprintf (name, "__tcf_%d", counter++); 1011 t = make_call_declarator (get_identifier (name), params, NULL_TREE, 1012 NULL_TREE); 1013 start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"), 1014 void_list_node), 1015 t, NULL_TREE, 0); 1016 store_parm_decls (); 1017 pushlevel (0); 1018 clear_last_expr (); 1019 push_momentary (); 1020 expand_start_bindings (0); 1021 emit_line_note (input_filename, lineno); 1022 1023 interface_unknown = old_interface_unknown; 1024 1025 pop_lang_context (); 1026 1027 return current_function_decl; 1028} 1029 1030void 1031end_anon_func () 1032{ 1033 expand_end_bindings (getdecls (), 1, 0); 1034 poplevel (1, 0, 0); 1035 pop_momentary (); 1036 1037 finish_function (lineno, 0, 0); 1038 1039 pop_from_top_level (); 1040 pop_cp_function_context (NULL_TREE); 1041} 1042 1043/* Return a pointer to a buffer for an exception object of type TYPE. */ 1044 1045static tree 1046alloc_eh_object (type) 1047 tree type; 1048{ 1049 tree fn, exp; 1050 1051 fn = get_identifier ("__eh_alloc"); 1052 if (IDENTIFIER_GLOBAL_VALUE (fn)) 1053 fn = IDENTIFIER_GLOBAL_VALUE (fn); 1054 else 1055 { 1056 /* Declare __eh_alloc (size_t), as defined in exception.cc. */ 1057 tree tmp; 1058 push_obstacks_nochange (); 1059 end_temporary_allocation (); 1060 tmp = tree_cons (NULL_TREE, sizetype, void_list_node); 1061 fn = build_lang_decl (FUNCTION_DECL, fn, 1062 build_function_type (ptr_type_node, tmp)); 1063 DECL_EXTERNAL (fn) = 1; 1064 TREE_PUBLIC (fn) = 1; 1065 DECL_ARTIFICIAL (fn) = 1; 1066 pushdecl_top_level (fn); 1067 make_function_rtl (fn); 1068 assemble_external (fn); 1069 pop_obstacks (); 1070 } 1071 1072 exp = build_function_call (fn, expr_tree_cons 1073 (NULL_TREE, size_in_bytes (type), NULL_TREE)); 1074 exp = build1 (NOP_EXPR, build_pointer_type (type), exp); 1075 return exp; 1076} 1077 1078/* Expand a throw statement. This follows the following 1079 algorithm: 1080 1081 1. Allocate space to save the current PC onto the stack. 1082 2. Generate and emit a label and save its address into the 1083 newly allocated stack space since we can't save the pc directly. 1084 3. If this is the first call to throw in this function: 1085 generate a label for the throw block 1086 4. jump to the throw block label. */ 1087 1088void 1089expand_throw (exp) 1090 tree exp; 1091{ 1092 tree fn; 1093 static tree cleanup_type; 1094 1095 if (! doing_eh (1)) 1096 return; 1097 1098 if (exp) 1099 { 1100 tree throw_type; 1101 tree cleanup = NULL_TREE, e; 1102 1103 /* throw expression */ 1104 /* First, decay it. */ 1105 exp = decay_conversion (exp); 1106 1107 /* cleanup_type is void (*)(void *, int), 1108 the internal type of a destructor. */ 1109 if (cleanup_type == NULL_TREE) 1110 { 1111 push_obstacks_nochange (); 1112 end_temporary_allocation (); 1113 cleanup_type = build_pointer_type 1114 (build_function_type 1115 (void_type_node, tree_cons 1116 (NULL_TREE, ptr_type_node, tree_cons 1117 (NULL_TREE, integer_type_node, void_list_node)))); 1118 pop_obstacks (); 1119 } 1120 1121 if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE) 1122 { 1123 throw_type = build_eh_type (exp); 1124 exp = build_reinterpret_cast (ptr_type_node, exp); 1125 } 1126 else 1127 { 1128 tree object, ptr; 1129 1130 /* OK, this is kind of wacky. The WP says that we call 1131 terminate 1132 1133 when the exception handling mechanism, after completing 1134 evaluation of the expression to be thrown but before the 1135 exception is caught (_except.throw_), calls a user function 1136 that exits via an uncaught exception. 1137 1138 So we have to protect the actual initialization of the 1139 exception object with terminate(), but evaluate the expression 1140 first. We also expand the call to __eh_alloc 1141 first. Since there could be temps in the expression, we need 1142 to handle that, too. */ 1143 1144 expand_start_target_temps (); 1145 1146#if 0 1147 /* Unfortunately, this doesn't work. */ 1148 preexpand_calls (exp); 1149#else 1150 /* Store the throw expression into a temp. This can be less 1151 efficient than storing it into the allocated space directly, but 1152 oh well. To do this efficiently we would need to insinuate 1153 ourselves into expand_call. */ 1154 if (TREE_SIDE_EFFECTS (exp)) 1155 { 1156 tree temp = build (VAR_DECL, TREE_TYPE (exp)); 1157 DECL_ARTIFICIAL (temp) = 1; 1158 layout_decl (temp, 0); 1159 DECL_RTL (temp) = assign_temp (TREE_TYPE (exp), 2, 0, 1); 1160 expand_expr (build (INIT_EXPR, TREE_TYPE (exp), temp, exp), 1161 NULL_RTX, VOIDmode, 0); 1162 expand_decl_cleanup (NULL_TREE, maybe_build_cleanup (temp)); 1163 exp = temp; 1164 } 1165#endif 1166 1167 /* Allocate the space for the exception. */ 1168 ptr = save_expr (alloc_eh_object (TREE_TYPE (exp))); 1169 expand_expr (ptr, const0_rtx, VOIDmode, 0); 1170 1171 expand_eh_region_start (); 1172 1173 object = build_indirect_ref (ptr, NULL_PTR); 1174 exp = build_modify_expr (object, INIT_EXPR, exp); 1175 1176 if (exp == error_mark_node) 1177 error (" in thrown expression"); 1178 1179 expand_expr (exp, const0_rtx, VOIDmode, 0); 1180 expand_eh_region_end (build_terminate_handler ()); 1181 expand_end_target_temps (); 1182 1183 throw_type = build_eh_type (object); 1184 1185 if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object))) 1186 { 1187 cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)), 1188 dtor_identifier, 0); 1189 cleanup = TREE_VALUE (cleanup); 1190 mark_used (cleanup); 1191 mark_addressable (cleanup); 1192 /* Pretend it's a normal function. */ 1193 cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup); 1194 } 1195 1196 exp = ptr; 1197 } 1198 1199 if (cleanup == NULL_TREE) 1200 { 1201 cleanup = build_int_2 (0, 0); 1202 TREE_TYPE (cleanup) = cleanup_type; 1203 } 1204 1205 fn = get_identifier ("__cp_push_exception"); 1206 if (IDENTIFIER_GLOBAL_VALUE (fn)) 1207 fn = IDENTIFIER_GLOBAL_VALUE (fn); 1208 else 1209 { 1210 /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)), 1211 as defined in exception.cc. */ 1212 tree tmp; 1213 push_obstacks_nochange (); 1214 end_temporary_allocation (); 1215 tmp = tree_cons 1216 (NULL_TREE, ptr_type_node, tree_cons 1217 (NULL_TREE, ptr_type_node, tree_cons 1218 (NULL_TREE, cleanup_type, void_list_node))); 1219 fn = build_lang_decl (FUNCTION_DECL, fn, 1220 build_function_type (void_type_node, tmp)); 1221 DECL_EXTERNAL (fn) = 1; 1222 TREE_PUBLIC (fn) = 1; 1223 DECL_ARTIFICIAL (fn) = 1; 1224 pushdecl_top_level (fn); 1225 make_function_rtl (fn); 1226 assemble_external (fn); 1227 pop_obstacks (); 1228 } 1229 1230 e = expr_tree_cons (NULL_TREE, exp, expr_tree_cons 1231 (NULL_TREE, throw_type, expr_tree_cons 1232 (NULL_TREE, cleanup, NULL_TREE))); 1233 e = build_function_call (fn, e); 1234 expand_expr (e, const0_rtx, VOIDmode, 0); 1235 } 1236 else 1237 { 1238 /* rethrow current exception; note that it's no longer caught. */ 1239 1240 tree fn = get_identifier ("__uncatch_exception"); 1241 if (IDENTIFIER_GLOBAL_VALUE (fn)) 1242 fn = IDENTIFIER_GLOBAL_VALUE (fn); 1243 else 1244 { 1245 /* Declare void __uncatch_exception (void) 1246 as defined in exception.cc. */ 1247 push_obstacks_nochange (); 1248 end_temporary_allocation (); 1249 fn = build_lang_decl (FUNCTION_DECL, fn, 1250 build_function_type (void_type_node, 1251 void_list_node)); 1252 DECL_EXTERNAL (fn) = 1; 1253 TREE_PUBLIC (fn) = 1; 1254 DECL_ARTIFICIAL (fn) = 1; 1255 pushdecl_top_level (fn); 1256 make_function_rtl (fn); 1257 assemble_external (fn); 1258 pop_obstacks (); 1259 } 1260 1261 exp = build_function_call (fn, NULL_TREE); 1262 expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL); 1263 } 1264 1265 expand_internal_throw (); 1266} 1267 1268/* Build a throw expression. */ 1269 1270tree 1271build_throw (e) 1272 tree e; 1273{ 1274 if (e == error_mark_node) 1275 return e; 1276 1277 if (processing_template_decl) 1278 return build_min (THROW_EXPR, void_type_node, e); 1279 1280 if (! flag_ansi && e == null_node) 1281 { 1282 cp_warning ("throwing NULL"); 1283 e = integer_zero_node; 1284 } 1285 1286 e = build1 (THROW_EXPR, void_type_node, e); 1287 TREE_SIDE_EFFECTS (e) = 1; 1288 TREE_USED (e) = 1; 1289 1290 return e; 1291} 1292