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