except.c revision 259660
118334Speter/* Handle exceptional things in C++. 290289Sobrien Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 3169699Skan 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. 418334Speter Contributed by Michael Tiemann <tiemann@cygnus.com> 518334Speter Rewritten by Mike Stump <mrs@cygnus.com>, based upon an 618334Speter initial re-implementation courtesy Tad Hunt. 718334Speter 8132727SkanThis file is part of GCC. 918334Speter 10132727SkanGCC is free software; you can redistribute it and/or modify 1118334Speterit under the terms of the GNU General Public License as published by 1218334Speterthe Free Software Foundation; either version 2, or (at your option) 1318334Speterany later version. 1418334Speter 15132727SkanGCC is distributed in the hope that it will be useful, 1618334Speterbut WITHOUT ANY WARRANTY; without even the implied warranty of 1718334SpeterMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1818334SpeterGNU General Public License for more details. 1918334Speter 2018334SpeterYou should have received a copy of the GNU General Public License 21132727Skanalong with GCC; see the file COPYING. If not, write to 22169699Skanthe Free Software Foundation, 51 Franklin Street, Fifth Floor, 23169699SkanBoston, MA 02110-1301, USA. */ 2418334Speter 2518334Speter 2618334Speter#include "config.h" 2750643Sobrien#include "system.h" 28132727Skan#include "coretypes.h" 29132727Skan#include "tm.h" 3018334Speter#include "tree.h" 3118334Speter#include "rtl.h" 3290289Sobrien#include "expr.h" 3390289Sobrien#include "libfuncs.h" 3418334Speter#include "cp-tree.h" 3518334Speter#include "flags.h" 3650643Sobrien#include "output.h" 3750643Sobrien#include "except.h" 3850643Sobrien#include "toplev.h" 39117404Skan#include "tree-inline.h" 40169699Skan#include "tree-iterator.h" 41169699Skan#include "target.h" 4218334Speter 43132727Skanstatic void push_eh_cleanup (tree); 44132727Skanstatic tree prepare_eh_type (tree); 45132727Skanstatic tree build_eh_type_type (tree); 46132727Skanstatic tree do_begin_catch (void); 47132727Skanstatic int dtor_nothrow (tree); 48132727Skanstatic tree do_end_catch (tree); 49132727Skanstatic bool decl_is_java_type (tree decl, int err); 50132727Skanstatic void initialize_handler_parm (tree, tree); 51132727Skanstatic tree do_allocate_exception (tree); 52132727Skanstatic tree wrap_cleanups_r (tree *, int *, void *); 53132727Skanstatic int complete_ptr_ref_or_void_ptr_p (tree, tree); 54132727Skanstatic bool is_admissible_throw_operand (tree); 55132727Skanstatic int can_convert_eh (tree, tree); 56132727Skanstatic tree cp_protect_cleanup_actions (void); 5718334Speter 5890289Sobrien/* Sets up all the global eh stuff that needs to be initialized at the 5990289Sobrien start of compilation. */ 6018334Speter 6118334Spetervoid 62132727Skaninit_exception_processing (void) 6318334Speter{ 6490289Sobrien tree tmp; 6518334Speter 6690289Sobrien /* void std::terminate (); */ 6790289Sobrien push_namespace (std_identifier); 6890289Sobrien tmp = build_function_type (void_type_node, void_list_node); 6990289Sobrien terminate_node = build_cp_library_fn_ptr ("terminate", tmp); 7090289Sobrien TREE_THIS_VOLATILE (terminate_node) = 1; 7190289Sobrien TREE_NOTHROW (terminate_node) = 1; 7290289Sobrien pop_namespace (); 7318334Speter 7490289Sobrien /* void __cxa_call_unexpected(void *); */ 7590289Sobrien tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node); 7690289Sobrien tmp = build_function_type (void_type_node, tmp); 7790289Sobrien call_unexpected_node 7890289Sobrien = push_throw_library_fn (get_identifier ("__cxa_call_unexpected"), tmp); 7918334Speter 8090289Sobrien eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS 8190289Sobrien ? "__gxx_personality_sj0" 8290289Sobrien : "__gxx_personality_v0"); 83169699Skan if (targetm.arm_eabi_unwinder) 84169699Skan unwind_resume_libfunc = init_one_libfunc ("__cxa_end_cleanup"); 85169699Skan else 86169699Skan default_init_unwind_resume_libfunc (); 8718334Speter 8890289Sobrien lang_eh_runtime_type = build_eh_type_type; 8990289Sobrien lang_protect_cleanup_actions = &cp_protect_cleanup_actions; 9018334Speter} 9118334Speter 9290289Sobrien/* Returns an expression to be executed if an unhandled exception is 9390289Sobrien propagated out of a cleanup region. */ 9418334Speter 9550643Sobrienstatic tree 96132727Skancp_protect_cleanup_actions (void) 9718334Speter{ 9890289Sobrien /* [except.terminate] 9918334Speter 10090289Sobrien When the destruction of an object during stack unwinding exits 10190289Sobrien using an exception ... void terminate(); is called. */ 10290289Sobrien return build_call (terminate_node, NULL_TREE); 103169699Skan} 10418334Speter 10550643Sobrienstatic tree 106132727Skanprepare_eh_type (tree type) 10718334Speter{ 10890289Sobrien if (type == NULL_TREE) 10990289Sobrien return type; 11050643Sobrien if (type == error_mark_node) 11150643Sobrien return error_mark_node; 11218334Speter 11350643Sobrien /* peel back references, so they match. */ 114132727Skan type = non_reference (type); 11518334Speter 11650643Sobrien /* Peel off cv qualifiers. */ 11750643Sobrien type = TYPE_MAIN_VARIANT (type); 11818334Speter 11990289Sobrien return type; 12018334Speter} 12118334Speter 122132727Skan/* Return the type info for TYPE as used by EH machinery. */ 123132727Skantree 124132727Skaneh_type_info (tree type) 12518334Speter{ 12618334Speter tree exp; 12718334Speter 12890289Sobrien if (type == NULL_TREE || type == error_mark_node) 12990289Sobrien return type; 13018334Speter 13190289Sobrien if (decl_is_java_type (type, 0)) 13290289Sobrien exp = build_java_class_ref (TREE_TYPE (type)); 13390289Sobrien else 13490289Sobrien exp = get_tinfo_decl (type); 13518334Speter 136132727Skan return exp; 137132727Skan} 138132727Skan 139132727Skan/* Build the address of a typeinfo decl for use in the runtime 140132727Skan matching field of the exception model. */ 141132727Skan 142132727Skanstatic tree 143132727Skanbuild_eh_type_type (tree type) 144132727Skan{ 145132727Skan tree exp = eh_type_info (type); 146132727Skan 147132727Skan if (!exp) 148132727Skan return NULL; 149132727Skan 15090289Sobrien mark_used (exp); 15118334Speter 152169699Skan return convert (ptr_type_node, build_address (exp)); 15390289Sobrien} 15450643Sobrien 15590289Sobrientree 156132727Skanbuild_exc_ptr (void) 15790289Sobrien{ 158169699Skan return build0 (EXC_PTR_EXPR, ptr_type_node); 15918334Speter} 16018334Speter 161169699Skan/* Build up a call to __cxa_get_exception_ptr so that we can build a 162169699Skan copy constructor for the thrown object. */ 163169699Skan 164169699Skanstatic tree 165169699Skando_get_exception_ptr (void) 166169699Skan{ 167169699Skan tree fn; 168169699Skan 169169699Skan fn = get_identifier ("__cxa_get_exception_ptr"); 170169699Skan if (!get_global_value_if_present (fn, &fn)) 171169699Skan { 172169699Skan /* Declare void* __cxa_get_exception_ptr (void *). */ 173169699Skan tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node); 174169699Skan fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp)); 175169699Skan } 176169699Skan 177169699Skan return build_function_call (fn, tree_cons (NULL_TREE, build_exc_ptr (), 178169699Skan NULL_TREE)); 179169699Skan} 180169699Skan 18190289Sobrien/* Build up a call to __cxa_begin_catch, to tell the runtime that the 18290289Sobrien exception has been handled. */ 18350643Sobrien 18418334Speterstatic tree 185132727Skando_begin_catch (void) 18618334Speter{ 18790289Sobrien tree fn; 18890289Sobrien 18990289Sobrien fn = get_identifier ("__cxa_begin_catch"); 190132727Skan if (!get_global_value_if_present (fn, &fn)) 19118334Speter { 19290289Sobrien /* Declare void* __cxa_begin_catch (void *). */ 19390289Sobrien tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node); 19490289Sobrien fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp)); 19518334Speter } 19690289Sobrien 19790289Sobrien return build_function_call (fn, tree_cons (NULL_TREE, build_exc_ptr (), 19890289Sobrien NULL_TREE)); 19918334Speter} 20018334Speter 20190289Sobrien/* Returns nonzero if cleaning up an exception of type TYPE (which can be 20290289Sobrien NULL_TREE for a ... handler) will not throw an exception. */ 20390289Sobrien 20490289Sobrienstatic int 205132727Skandtor_nothrow (tree type) 20650643Sobrien{ 20790289Sobrien if (type == NULL_TREE) 20890289Sobrien return 0; 20990289Sobrien 210169699Skan if (!CLASS_TYPE_P (type)) 21190289Sobrien return 1; 21290289Sobrien 213169699Skan if (CLASSTYPE_LAZY_DESTRUCTOR (type)) 214169699Skan lazily_declare_fn (sfk_destructor, type); 215169699Skan 216117404Skan return TREE_NOTHROW (CLASSTYPE_DESTRUCTORS (type)); 21750643Sobrien} 21850643Sobrien 21990289Sobrien/* Build up a call to __cxa_end_catch, to destroy the exception object 22090289Sobrien for the current catch block if no others are currently using it. */ 22150643Sobrien 22250643Sobrienstatic tree 223132727Skando_end_catch (tree type) 22450643Sobrien{ 22550643Sobrien tree fn, cleanup; 22690289Sobrien 22790289Sobrien fn = get_identifier ("__cxa_end_catch"); 228132727Skan if (!get_global_value_if_present (fn, &fn)) 22950643Sobrien { 23090289Sobrien /* Declare void __cxa_end_catch (). */ 23190289Sobrien fn = push_void_library_fn (fn, void_list_node); 23290289Sobrien /* This can throw if the destructor for the exception throws. */ 23390289Sobrien TREE_NOTHROW (fn) = 0; 23450643Sobrien } 23550643Sobrien 23690289Sobrien cleanup = build_function_call (fn, NULL_TREE); 23790289Sobrien TREE_NOTHROW (cleanup) = dtor_nothrow (type); 23890289Sobrien 23950643Sobrien return cleanup; 24050643Sobrien} 24150643Sobrien 24250643Sobrien/* This routine creates the cleanup for the current exception. */ 24350643Sobrien 24450643Sobrienstatic void 245132727Skanpush_eh_cleanup (tree type) 24650643Sobrien{ 24790289Sobrien finish_decl_cleanup (NULL_TREE, do_end_catch (type)); 24850643Sobrien} 24950643Sobrien 25090289Sobrien/* Return nonzero value if DECL is a Java type suitable for catch or 25190289Sobrien throw. */ 25250643Sobrien 25390289Sobrienstatic bool 254132727Skandecl_is_java_type (tree decl, int err) 25550643Sobrien{ 25690289Sobrien bool r = (TREE_CODE (decl) == POINTER_TYPE 25790289Sobrien && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE 25890289Sobrien && TYPE_FOR_JAVA (TREE_TYPE (decl))); 25990289Sobrien 26090289Sobrien if (err) 26190289Sobrien { 26290289Sobrien if (TREE_CODE (decl) == REFERENCE_TYPE 26390289Sobrien && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE 26490289Sobrien && TYPE_FOR_JAVA (TREE_TYPE (decl))) 26590289Sobrien { 26690289Sobrien /* Can't throw a reference. */ 267169699Skan error ("type %qT is disallowed in Java %<throw%> or %<catch%>", 268169699Skan decl); 26990289Sobrien } 27090289Sobrien 27190289Sobrien if (r) 27290289Sobrien { 27390289Sobrien tree jthrow_node 27490289Sobrien = IDENTIFIER_GLOBAL_VALUE (get_identifier ("jthrowable")); 27590289Sobrien 27690289Sobrien if (jthrow_node == NULL_TREE) 27790289Sobrien fatal_error 278169699Skan ("call to Java %<catch%> or %<throw%> with %<jthrowable%> undefined"); 27990289Sobrien 28090289Sobrien jthrow_node = TREE_TYPE (TREE_TYPE (jthrow_node)); 28190289Sobrien 28290289Sobrien if (! DERIVED_FROM_P (jthrow_node, TREE_TYPE (decl))) 28390289Sobrien { 28490289Sobrien /* Thrown object must be a Throwable. */ 285169699Skan error ("type %qT is not derived from %<java::lang::Throwable%>", 286169699Skan TREE_TYPE (decl)); 28790289Sobrien } 28890289Sobrien } 28990289Sobrien } 29090289Sobrien 29190289Sobrien return r; 29250643Sobrien} 29350643Sobrien 29490289Sobrien/* Select the personality routine to be used for exception handling, 29590289Sobrien or issue an error if we need two different ones in the same 29690289Sobrien translation unit. 29790289Sobrien ??? At present eh_personality_libfunc is set to 29890289Sobrien __gxx_personality_(sj|v)0 in init_exception_processing - should it 29990289Sobrien be done here instead? */ 30018334Spetervoid 301132727Skanchoose_personality_routine (enum languages lang) 30218334Speter{ 30390289Sobrien static enum { 30490289Sobrien chose_none, 30590289Sobrien chose_cpp, 30690289Sobrien chose_java, 30790289Sobrien gave_error 30890289Sobrien } state; 30950643Sobrien 31090289Sobrien switch (state) 31150643Sobrien { 31290289Sobrien case gave_error: 31350643Sobrien return; 31490289Sobrien 31590289Sobrien case chose_cpp: 31690289Sobrien if (lang != lang_cplusplus) 31790289Sobrien goto give_error; 31890289Sobrien return; 31990289Sobrien 32090289Sobrien case chose_java: 32190289Sobrien if (lang != lang_java) 32290289Sobrien goto give_error; 32390289Sobrien return; 32490289Sobrien 32590289Sobrien case chose_none: 326132727Skan ; /* Proceed to language selection. */ 32750643Sobrien } 32850643Sobrien 32990289Sobrien switch (lang) 33090289Sobrien { 33190289Sobrien case lang_cplusplus: 33290289Sobrien state = chose_cpp; 33390289Sobrien break; 33450643Sobrien 33590289Sobrien case lang_java: 33690289Sobrien state = chose_java; 33790289Sobrien eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS 33890289Sobrien ? "__gcj_personality_sj0" 33990289Sobrien : "__gcj_personality_v0"); 34090289Sobrien break; 34190289Sobrien 34290289Sobrien default: 343169699Skan gcc_unreachable (); 34490289Sobrien } 34590289Sobrien return; 34690289Sobrien 34790289Sobrien give_error: 34890289Sobrien error ("mixing C++ and Java catches in a single translation unit"); 34990289Sobrien state = gave_error; 35050643Sobrien} 35150643Sobrien 35290289Sobrien/* Initialize the catch parameter DECL. */ 35350643Sobrien 354169699Skanstatic void 355132727Skaninitialize_handler_parm (tree decl, tree exp) 35618334Speter{ 35750643Sobrien tree init; 35890289Sobrien tree init_type; 35918334Speter 36090289Sobrien /* Make sure we mark the catch param as used, otherwise we'll get a 36190289Sobrien warning about an unused ((anonymous)). */ 36290289Sobrien TREE_USED (decl) = 1; 36318334Speter 36490289Sobrien /* Figure out the type that the initializer is. Pointers are returned 365169699Skan adjusted by value from __cxa_begin_catch. Others are returned by 36690289Sobrien reference. */ 36790289Sobrien init_type = TREE_TYPE (decl); 368169699Skan if (!POINTER_TYPE_P (init_type)) 36990289Sobrien init_type = build_reference_type (init_type); 37018334Speter 37190289Sobrien choose_personality_routine (decl_is_java_type (init_type, 0) 37290289Sobrien ? lang_java : lang_cplusplus); 37318334Speter 37490289Sobrien /* Since pointers are passed by value, initialize a reference to 37590289Sobrien pointer catch parm with the address of the temporary. */ 37690289Sobrien if (TREE_CODE (init_type) == REFERENCE_TYPE 37790289Sobrien && TYPE_PTR_P (TREE_TYPE (init_type))) 37890289Sobrien exp = build_unary_op (ADDR_EXPR, exp, 1); 37918334Speter 38090289Sobrien exp = ocp_convert (init_type, exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0); 38118334Speter 38290289Sobrien init = convert_from_reference (exp); 38318334Speter 38490289Sobrien /* If the constructor for the catch parm exits via an exception, we 38590289Sobrien must call terminate. See eh23.C. */ 38690289Sobrien if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) 38750643Sobrien { 38890289Sobrien /* Generate the copy constructor call directly so we can wrap it. 38990289Sobrien See also expand_default_init. */ 39090289Sobrien init = ocp_convert (TREE_TYPE (decl), init, 39190289Sobrien CONV_IMPLICIT|CONV_FORCE_TEMP, 0); 39290289Sobrien init = build1 (MUST_NOT_THROW_EXPR, TREE_TYPE (init), init); 39390289Sobrien } 39418334Speter 39590289Sobrien decl = pushdecl (decl); 39618334Speter 397169699Skan start_decl_1 (decl, true); 398169699Skan cp_finish_decl (decl, init, /*init_const_expr_p=*/false, NULL_TREE, 39990289Sobrien LOOKUP_ONLYCONVERTING|DIRECT_BIND); 40090289Sobrien} 40118334Speter 40290289Sobrien/* Call this to start a catch block. DECL is the catch parameter. */ 40318334Speter 40490289Sobrientree 405132727Skanexpand_start_catch_block (tree decl) 40690289Sobrien{ 407169699Skan tree exp; 40890289Sobrien tree type; 40918334Speter 41090289Sobrien if (! doing_eh (1)) 41190289Sobrien return NULL_TREE; 41218334Speter 41390289Sobrien /* Make sure this declaration is reasonable. */ 41490289Sobrien if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE)) 415169699Skan decl = error_mark_node; 41618334Speter 41790289Sobrien if (decl) 41890289Sobrien type = prepare_eh_type (TREE_TYPE (decl)); 41990289Sobrien else 42090289Sobrien type = NULL_TREE; 42118334Speter 422169699Skan if (decl && decl_is_java_type (type, 1)) 42390289Sobrien { 424169699Skan /* Java only passes object via pointer and doesn't require 425169699Skan adjusting. The java object is immediately before the 426169699Skan generic exception header. */ 427169699Skan exp = build_exc_ptr (); 428169699Skan exp = build1 (NOP_EXPR, build_pointer_type (type), exp); 429169699Skan exp = build2 (MINUS_EXPR, TREE_TYPE (exp), exp, 430169699Skan TYPE_SIZE_UNIT (TREE_TYPE (exp))); 431169699Skan exp = build_indirect_ref (exp, NULL); 432169699Skan initialize_handler_parm (decl, exp); 433169699Skan return type; 434169699Skan } 43518334Speter 436169699Skan /* Call __cxa_end_catch at the end of processing the exception. */ 437169699Skan push_eh_cleanup (type); 438169699Skan 439169699Skan /* If there's no decl at all, then all we need to do is make sure 440169699Skan to tell the runtime that we've begun handling the exception. */ 441169699Skan if (decl == NULL || decl == error_mark_node) 442169699Skan finish_expr_stmt (do_begin_catch ()); 443169699Skan 444169699Skan /* If the C++ object needs constructing, we need to do that before 445169699Skan calling __cxa_begin_catch, so that std::uncaught_exception gets 446169699Skan the right value during the copy constructor. */ 447169699Skan else if (flag_use_cxa_get_exception_ptr 448169699Skan && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) 449169699Skan { 450169699Skan exp = do_get_exception_ptr (); 451169699Skan initialize_handler_parm (decl, exp); 452169699Skan finish_expr_stmt (do_begin_catch ()); 45350643Sobrien } 454169699Skan 455169699Skan /* Otherwise the type uses a bitwise copy, and we don't have to worry 456169699Skan about the value of std::uncaught_exception and therefore can do the 457169699Skan copy with the return value of __cxa_end_catch instead. */ 45850643Sobrien else 459169699Skan { 460169699Skan tree init = do_begin_catch (); 461169699Skan tree init_type = type; 46218334Speter 463169699Skan /* Pointers are passed by values, everything else by reference. */ 464169699Skan if (!TYPE_PTR_P (type)) 465169699Skan init_type = build_pointer_type (type); 466169699Skan if (init_type != TREE_TYPE (init)) 467169699Skan init = build1 (NOP_EXPR, init_type, init); 468169699Skan exp = create_temporary_var (init_type); 469169699Skan DECL_REGISTER (exp) = 1; 470169699Skan cp_finish_decl (exp, init, /*init_const_expr=*/false, 471169699Skan NULL_TREE, LOOKUP_ONLYCONVERTING); 472169699Skan initialize_handler_parm (decl, exp); 473169699Skan } 47418334Speter 47590289Sobrien return type; 47618334Speter} 47718334Speter 47818334Speter 47950643Sobrien/* Call this to end a catch block. Its responsible for emitting the 48050643Sobrien code to handle jumping back to the correct place, and for emitting 48150643Sobrien the label to jump to if this catch block didn't match. */ 48218334Speter 48318334Spetervoid 484132727Skanexpand_end_catch_block (void) 48518334Speter{ 48650643Sobrien if (! doing_eh (1)) 48718334Speter return; 48818334Speter 48990289Sobrien /* The exception being handled is rethrown if control reaches the end of 49090289Sobrien a handler of the function-try-block of a constructor or destructor. */ 49190289Sobrien if (in_function_try_handler 49290289Sobrien && (DECL_CONSTRUCTOR_P (current_function_decl) 49390289Sobrien || DECL_DESTRUCTOR_P (current_function_decl))) 49490289Sobrien finish_expr_stmt (build_throw (NULL_TREE)); 49590289Sobrien} 49618334Speter 49790289Sobrientree 498132727Skanbegin_eh_spec_block (void) 49990289Sobrien{ 50090289Sobrien tree r = build_stmt (EH_SPEC_BLOCK, NULL_TREE, NULL_TREE); 50190289Sobrien add_stmt (r); 502169699Skan EH_SPEC_STMTS (r) = push_stmt_list (); 50390289Sobrien return r; 50450643Sobrien} 50518334Speter 50690289Sobrienvoid 507132727Skanfinish_eh_spec_block (tree raw_raises, tree eh_spec_block) 50890289Sobrien{ 50990289Sobrien tree raises; 51018334Speter 511169699Skan EH_SPEC_STMTS (eh_spec_block) = pop_stmt_list (EH_SPEC_STMTS (eh_spec_block)); 51218334Speter 51390289Sobrien /* Strip cv quals, etc, from the specification types. */ 51490289Sobrien for (raises = NULL_TREE; 51590289Sobrien raw_raises && TREE_VALUE (raw_raises); 51690289Sobrien raw_raises = TREE_CHAIN (raw_raises)) 517132727Skan { 518132727Skan tree type = prepare_eh_type (TREE_VALUE (raw_raises)); 519132727Skan tree tinfo = eh_type_info (type); 52018334Speter 521132727Skan mark_used (tinfo); 522132727Skan raises = tree_cons (NULL_TREE, type, raises); 523132727Skan } 524132727Skan 52590289Sobrien EH_SPEC_RAISES (eh_spec_block) = raises; 52618334Speter} 52718334Speter 52890289Sobrien/* Return a pointer to a buffer for an exception object of type TYPE. */ 52990289Sobrien 53090289Sobrienstatic tree 531132727Skando_allocate_exception (tree type) 53218334Speter{ 53390289Sobrien tree fn; 53418334Speter 53590289Sobrien fn = get_identifier ("__cxa_allocate_exception"); 536132727Skan if (!get_global_value_if_present (fn, &fn)) 53750643Sobrien { 53890289Sobrien /* Declare void *__cxa_allocate_exception(size_t). */ 539110621Skan tree tmp = tree_cons (NULL_TREE, size_type_node, void_list_node); 54090289Sobrien fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp)); 54150643Sobrien } 542169699Skan 54390289Sobrien return build_function_call (fn, tree_cons (NULL_TREE, size_in_bytes (type), 54490289Sobrien NULL_TREE)); 54590289Sobrien} 54618334Speter 54790289Sobrien/* Call __cxa_free_exception from a cleanup. This is never invoked 548117404Skan directly, but see the comment for stabilize_throw_expr. */ 54950643Sobrien 55090289Sobrienstatic tree 551132727Skando_free_exception (tree ptr) 55290289Sobrien{ 55390289Sobrien tree fn; 55450643Sobrien 55590289Sobrien fn = get_identifier ("__cxa_free_exception"); 556132727Skan if (!get_global_value_if_present (fn, &fn)) 55718334Speter { 55890289Sobrien /* Declare void __cxa_free_exception (void *). */ 55990289Sobrien fn = push_void_library_fn (fn, tree_cons (NULL_TREE, ptr_type_node, 56090289Sobrien void_list_node)); 56150643Sobrien } 56218334Speter 56390289Sobrien return build_function_call (fn, tree_cons (NULL_TREE, ptr, NULL_TREE)); 56418334Speter} 56518334Speter 566117404Skan/* Wrap all cleanups for TARGET_EXPRs in MUST_NOT_THROW_EXPR. 567117404Skan Called from build_throw via walk_tree_without_duplicates. */ 568117404Skan 569117404Skanstatic tree 570132727Skanwrap_cleanups_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, 571169699Skan void *data ATTRIBUTE_UNUSED) 572117404Skan{ 573117404Skan tree exp = *tp; 574117404Skan tree cleanup; 575117404Skan 576117404Skan /* Don't walk into types. */ 577117404Skan if (TYPE_P (exp)) 578117404Skan { 579117404Skan *walk_subtrees = 0; 580117404Skan return NULL_TREE; 581117404Skan } 582117404Skan if (TREE_CODE (exp) != TARGET_EXPR) 583117404Skan return NULL_TREE; 584117404Skan 585117404Skan cleanup = TARGET_EXPR_CLEANUP (exp); 586117404Skan if (cleanup) 587117404Skan { 588132727Skan cleanup = build1 (MUST_NOT_THROW_EXPR, void_type_node, cleanup); 589117404Skan TARGET_EXPR_CLEANUP (exp) = cleanup; 590117404Skan } 591117404Skan 592117404Skan /* Keep iterating. */ 593117404Skan return NULL_TREE; 594117404Skan} 595117404Skan 59690289Sobrien/* Build a throw expression. */ 59750643Sobrien 59890289Sobrientree 599132727Skanbuild_throw (tree exp) 60018334Speter{ 60190289Sobrien tree fn; 60218334Speter 60390289Sobrien if (exp == error_mark_node) 60490289Sobrien return exp; 60590289Sobrien 60690289Sobrien if (processing_template_decl) 607132727Skan { 608169699Skan if (cfun) 609169699Skan current_function_returns_abnormally = 1; 610132727Skan return build_min (THROW_EXPR, void_type_node, exp); 611132727Skan } 61290289Sobrien 61390289Sobrien if (exp == null_node) 614169699Skan warning (0, "throwing NULL, which has integral, not pointer type"); 615169699Skan 61690289Sobrien if (exp != NULL_TREE) 61750643Sobrien { 61890289Sobrien if (!is_admissible_throw_operand (exp)) 619169699Skan return error_mark_node; 62050643Sobrien } 62118334Speter 62290289Sobrien if (! doing_eh (1)) 62390289Sobrien return error_mark_node; 62490289Sobrien 62590289Sobrien if (exp && decl_is_java_type (TREE_TYPE (exp), 1)) 62650643Sobrien { 62790289Sobrien tree fn = get_identifier ("_Jv_Throw"); 628132727Skan if (!get_global_value_if_present (fn, &fn)) 62990289Sobrien { 63090289Sobrien /* Declare void _Jv_Throw (void *). */ 63190289Sobrien tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node); 63290289Sobrien tmp = build_function_type (ptr_type_node, tmp); 63390289Sobrien fn = push_throw_library_fn (fn, tmp); 63490289Sobrien } 635132727Skan else if (really_overloaded_fn (fn)) 636146906Skan { 637169699Skan error ("%qD should never be overloaded", fn); 638146906Skan return error_mark_node; 639132727Skan } 640132727Skan fn = OVL_CURRENT (fn); 64190289Sobrien exp = build_function_call (fn, tree_cons (NULL_TREE, exp, NULL_TREE)); 64290289Sobrien } 64390289Sobrien else if (exp) 64490289Sobrien { 64590289Sobrien tree throw_type; 646169699Skan tree temp_type; 64790289Sobrien tree cleanup; 64890289Sobrien tree object, ptr; 64990289Sobrien tree tmp; 650117404Skan tree temp_expr, allocate_expr; 651132727Skan bool elided; 65218334Speter 653146906Skan /* The CLEANUP_TYPE is the internal type of a destructor. */ 654146906Skan if (!cleanup_type) 655146906Skan { 656146906Skan tmp = void_list_node; 657146906Skan tmp = tree_cons (NULL_TREE, ptr_type_node, tmp); 658146906Skan tmp = build_function_type (void_type_node, tmp); 659146906Skan cleanup_type = build_pointer_type (tmp); 660146906Skan } 661169699Skan 66290289Sobrien fn = get_identifier ("__cxa_throw"); 663132727Skan if (!get_global_value_if_present (fn, &fn)) 66490289Sobrien { 66590289Sobrien /* Declare void __cxa_throw (void*, void*, void (*)(void*)). */ 66690289Sobrien /* ??? Second argument is supposed to be "std::type_info*". */ 66790289Sobrien tmp = void_list_node; 66890289Sobrien tmp = tree_cons (NULL_TREE, cleanup_type, tmp); 66990289Sobrien tmp = tree_cons (NULL_TREE, ptr_type_node, tmp); 67090289Sobrien tmp = tree_cons (NULL_TREE, ptr_type_node, tmp); 67190289Sobrien tmp = build_function_type (void_type_node, tmp); 67290289Sobrien fn = push_throw_library_fn (fn, tmp); 67390289Sobrien } 67418334Speter 675169699Skan /* [except.throw] 676169699Skan 677169699Skan A throw-expression initializes a temporary object, the type 678169699Skan of which is determined by removing any top-level 679169699Skan cv-qualifiers from the static type of the operand of throw 680169699Skan and adjusting the type from "array of T" or "function return 681169699Skan T" to "pointer to T" or "pointer to function returning T" 682169699Skan respectively. */ 683169699Skan temp_type = is_bitfield_expr_with_lowered_type (exp); 684169699Skan if (!temp_type) 685169699Skan temp_type = type_decays_to (TYPE_MAIN_VARIANT (TREE_TYPE (exp))); 686169699Skan 68790289Sobrien /* OK, this is kind of wacky. The standard says that we call 68890289Sobrien terminate when the exception handling mechanism, after 68990289Sobrien completing evaluation of the expression to be thrown but 69090289Sobrien before the exception is caught (_except.throw_), calls a 69190289Sobrien user function that exits via an uncaught exception. 69218334Speter 69390289Sobrien So we have to protect the actual initialization of the 69490289Sobrien exception object with terminate(), but evaluate the 69590289Sobrien expression first. Since there could be temps in the 69690289Sobrien expression, we need to handle that, too. We also expand 69790289Sobrien the call to __cxa_allocate_exception first (which doesn't 69890289Sobrien matter, since it can't throw). */ 69918334Speter 70090289Sobrien /* Allocate the space for the exception. */ 701169699Skan allocate_expr = do_allocate_exception (temp_type); 702117404Skan allocate_expr = get_target_expr (allocate_expr); 703117404Skan ptr = TARGET_EXPR_SLOT (allocate_expr); 704169699Skan object = build_nop (build_pointer_type (temp_type), ptr); 70590289Sobrien object = build_indirect_ref (object, NULL); 70618334Speter 707132727Skan elided = (TREE_CODE (exp) == TARGET_EXPR); 708132727Skan 709117404Skan /* And initialize the exception object. */ 710169699Skan if (CLASS_TYPE_P (temp_type)) 711117404Skan { 712169699Skan /* Call the copy constructor. */ 713169699Skan exp = (build_special_member_call 714169699Skan (object, complete_ctor_identifier, 715169699Skan build_tree_list (NULL_TREE, exp), 716169699Skan TREE_TYPE (object), 717259660Spfg LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING)); 718169699Skan if (exp == error_mark_node) 719169699Skan { 720169699Skan error (" in thrown expression"); 721169699Skan return error_mark_node; 722169699Skan } 723117404Skan } 724169699Skan else 725169699Skan exp = build2 (INIT_EXPR, temp_type, object, 726169699Skan decay_conversion (exp)); 72718334Speter 728132727Skan /* Pre-evaluate the thrown expression first, since if we allocated 729132727Skan the space first we would have to deal with cleaning it up if 730132727Skan evaluating this expression throws. 731132727Skan 732169699Skan The case where EXP the initializer is a cast or a function 733169699Skan returning a class is a bit of a grey area in the standard; it's 734169699Skan unclear whether or not it should be allowed to throw. We used to 735169699Skan say no, as that allowed us to optimize this case without worrying 736169699Skan about deallocating the exception object if it does. But that 737169699Skan conflicted with expectations (PR 13944) and the EDG compiler; now 738169699Skan we wrap the initialization in a TRY_CATCH_EXPR to call 739169699Skan do_free_exception rather than in a MUST_NOT_THROW_EXPR, for this 740169699Skan case only. 741132727Skan 742169699Skan BUT: Issue 475 may do away with this inconsistency by removing the 743169699Skan terminate() in this situation. 744169699Skan 745169699Skan Note that we don't check the return value from stabilize_init 746169699Skan because it will only return false in cases where elided is true, 747169699Skan and therefore we don't need to work around the failure to 748169699Skan preevaluate. */ 749132727Skan temp_expr = NULL_TREE; 750132727Skan stabilize_init (exp, &temp_expr); 751132727Skan 752169699Skan /* Wrap the initialization in a CLEANUP_POINT_EXPR so that cleanups 753169699Skan for temporaries within the initialization are run before the one 754169699Skan for the exception object, preserving LIFO order. */ 755169699Skan exp = build1 (CLEANUP_POINT_EXPR, void_type_node, exp); 756169699Skan 757132727Skan if (elided) 758169699Skan exp = build2 (TRY_CATCH_EXPR, void_type_node, exp, 759169699Skan do_free_exception (ptr)); 760132727Skan else 761132727Skan exp = build1 (MUST_NOT_THROW_EXPR, void_type_node, exp); 762132727Skan 763117404Skan /* Prepend the allocation. */ 764169699Skan exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp); 765132727Skan if (temp_expr) 766117404Skan { 767117404Skan /* Prepend the calculation of the throw expression. Also, force 768117404Skan any cleanups from the expression to be evaluated here so that 769117404Skan we don't have to do them during unwinding. But first wrap 770117404Skan them in MUST_NOT_THROW_EXPR, since they are run after the 771117404Skan exception object is initialized. */ 772117404Skan walk_tree_without_duplicates (&temp_expr, wrap_cleanups_r, 0); 773169699Skan exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), temp_expr, exp); 774117404Skan exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp); 775117404Skan } 77618334Speter 77790289Sobrien throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object))); 77818334Speter 779169699Skan if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (object))) 78090289Sobrien { 78190289Sobrien cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)), 78290289Sobrien complete_dtor_identifier, 0); 783117404Skan cleanup = BASELINK_FUNCTIONS (cleanup); 78490289Sobrien mark_used (cleanup); 785117404Skan cxx_mark_addressable (cleanup); 78690289Sobrien /* Pretend it's a normal function. */ 78790289Sobrien cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup); 78890289Sobrien } 78990289Sobrien else 790169699Skan cleanup = build_int_cst (cleanup_type, 0); 79150643Sobrien 79290289Sobrien tmp = tree_cons (NULL_TREE, cleanup, NULL_TREE); 79390289Sobrien tmp = tree_cons (NULL_TREE, throw_type, tmp); 79490289Sobrien tmp = tree_cons (NULL_TREE, ptr, tmp); 795117404Skan /* ??? Indicate that this function call throws throw_type. */ 79690289Sobrien tmp = build_function_call (fn, tmp); 79718334Speter 798117404Skan /* Tack on the initialization stuff. */ 799169699Skan exp = build2 (COMPOUND_EXPR, TREE_TYPE (tmp), exp, tmp); 80090289Sobrien } 80150643Sobrien else 80250643Sobrien { 80390289Sobrien /* Rethrow current exception. */ 80490289Sobrien 80590289Sobrien tree fn = get_identifier ("__cxa_rethrow"); 806132727Skan if (!get_global_value_if_present (fn, &fn)) 80790289Sobrien { 80890289Sobrien /* Declare void __cxa_rethrow (void). */ 80990289Sobrien fn = push_throw_library_fn 81090289Sobrien (fn, build_function_type (void_type_node, void_list_node)); 81190289Sobrien } 81290289Sobrien 813117404Skan /* ??? Indicate that this function call allows exceptions of the type 814169699Skan of the enclosing catch block (if known). */ 81590289Sobrien exp = build_function_call (fn, NULL_TREE); 81650643Sobrien } 81750643Sobrien 81890289Sobrien exp = build1 (THROW_EXPR, void_type_node, exp); 81990289Sobrien 82050643Sobrien return exp; 82150643Sobrien} 82250643Sobrien 82390289Sobrien/* Make sure TYPE is complete, pointer to complete, reference to 82490289Sobrien complete, or pointer to cv void. Issue diagnostic on failure. 825117404Skan Return the zero on failure and nonzero on success. FROM can be 82690289Sobrien the expr or decl from whence TYPE came, if available. */ 82718334Speter 82890289Sobrienstatic int 829132727Skancomplete_ptr_ref_or_void_ptr_p (tree type, tree from) 83090289Sobrien{ 83190289Sobrien int is_ptr; 832169699Skan 83390289Sobrien /* Check complete. */ 83490289Sobrien type = complete_type_or_else (type, from); 83590289Sobrien if (!type) 83690289Sobrien return 0; 837169699Skan 83890289Sobrien /* Or a pointer or ref to one, or cv void *. */ 83990289Sobrien is_ptr = TREE_CODE (type) == POINTER_TYPE; 84090289Sobrien if (is_ptr || TREE_CODE (type) == REFERENCE_TYPE) 84190289Sobrien { 84290289Sobrien tree core = TREE_TYPE (type); 843169699Skan 84490289Sobrien if (is_ptr && VOID_TYPE_P (core)) 845169699Skan /* OK */; 84690289Sobrien else if (!complete_type_or_else (core, from)) 847169699Skan return 0; 84890289Sobrien } 84990289Sobrien return 1; 85090289Sobrien} 85150643Sobrien 85290289Sobrien/* Return truth-value if EXPRESSION is admissible in throw-expression, 85390289Sobrien i.e. if it is not of incomplete type or a pointer/reference to such 85490289Sobrien a type or of an abstract class type. */ 85590289Sobrien 85690289Sobrienstatic bool 857132727Skanis_admissible_throw_operand (tree expr) 85818334Speter{ 85990289Sobrien tree type = TREE_TYPE (expr); 86018334Speter 86190289Sobrien /* 15.1/4 [...] The type of the throw-expression shall not be an 862169699Skan incomplete type, or a pointer or a reference to an incomplete 863169699Skan type, other than void*, const void*, volatile void*, or 864169699Skan const volatile void*. Except for these restriction and the 865169699Skan restrictions on type matching mentioned in 15.3, the operand 866169699Skan of throw is treated exactly as a function argument in a call 867169699Skan (5.2.2) or the operand of a return statement. */ 86890289Sobrien if (!complete_ptr_ref_or_void_ptr_p (type, expr)) 86990289Sobrien return false; 87018334Speter 87190289Sobrien /* 10.4/3 An abstract class shall not be used as a parameter type, 872169699Skan as a function return type or as type of an explicit 873169699Skan conversion. */ 87490289Sobrien else if (CLASS_TYPE_P (type) && CLASSTYPE_PURE_VIRTUALS (type)) 87518334Speter { 876169699Skan error ("expression %qE of abstract class type %qT cannot " 877169699Skan "be used in throw-expression", expr, type); 87890289Sobrien return false; 87990289Sobrien } 88018334Speter 88190289Sobrien return true; 88290289Sobrien} 88318334Speter 88490289Sobrien/* Returns nonzero if FN is a declaration of a standard C library 88590289Sobrien function which is known not to throw. 88650643Sobrien 88790289Sobrien [lib.res.on.exception.handling]: None of the functions from the 88890289Sobrien Standard C library shall report an error by throwing an 88990289Sobrien exception, unless it calls a program-supplied function that 89090289Sobrien throws an exception. */ 89118334Speter 89290289Sobrien#include "cfns.h" 89318334Speter 89490289Sobrienint 895132727Skannothrow_libfn_p (tree fn) 89690289Sobrien{ 89790289Sobrien tree id; 89818334Speter 89990289Sobrien if (TREE_PUBLIC (fn) 90090289Sobrien && DECL_EXTERNAL (fn) 90190289Sobrien && DECL_NAMESPACE_SCOPE_P (fn) 90290289Sobrien && DECL_EXTERN_C_P (fn)) 90390289Sobrien /* OK */; 90490289Sobrien else 90590289Sobrien /* Can't be a C library function. */ 90690289Sobrien return 0; 90718334Speter 908169699Skan /* Being a C library function, DECL_ASSEMBLER_NAME == DECL_NAME 909169699Skan unless the system headers are playing rename tricks, and if 910169699Skan they are, we don't want to be confused by them. */ 911169699Skan id = DECL_NAME (fn); 91290289Sobrien return !!libc_name_p (IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id)); 91390289Sobrien} 91418334Speter 91590289Sobrien/* Returns nonzero if an exception of type FROM will be caught by a 91690289Sobrien handler for type TO, as per [except.handle]. */ 91718334Speter 91890289Sobrienstatic int 919132727Skancan_convert_eh (tree to, tree from) 92090289Sobrien{ 921132727Skan to = non_reference (to); 922132727Skan from = non_reference (from); 92318334Speter 92490289Sobrien if (TREE_CODE (to) == POINTER_TYPE && TREE_CODE (from) == POINTER_TYPE) 92590289Sobrien { 92690289Sobrien to = TREE_TYPE (to); 92790289Sobrien from = TREE_TYPE (from); 92818334Speter 92990289Sobrien if (! at_least_as_qualified_p (to, from)) 93090289Sobrien return 0; 93118334Speter 93290289Sobrien if (TREE_CODE (to) == VOID_TYPE) 93390289Sobrien return 1; 93418334Speter 935132727Skan /* Else fall through. */ 93690289Sobrien } 93718334Speter 93890289Sobrien if (CLASS_TYPE_P (to) && CLASS_TYPE_P (from) 93990289Sobrien && PUBLICLY_UNIQUELY_DERIVED_P (to, from)) 94090289Sobrien return 1; 94118334Speter 94290289Sobrien return 0; 94390289Sobrien} 94418334Speter 945169699Skan/* Check whether any of the handlers in I are shadowed by another handler 946169699Skan accepting TYPE. Note that the shadowing may not be complete; even if 947169699Skan an exception of type B would be caught by a handler for A, there could 948169699Skan be a derived class C for which A is an ambiguous base but B is not, so 949169699Skan the handler for B would catch an exception of type C. */ 95018334Speter 95190289Sobrienstatic void 952169699Skancheck_handlers_1 (tree master, tree_stmt_iterator i) 95390289Sobrien{ 95490289Sobrien tree type = TREE_TYPE (master); 95552291Sobrien 956169699Skan for (; !tsi_end_p (i); tsi_next (&i)) 957169699Skan { 958169699Skan tree handler = tsi_stmt (i); 959169699Skan if (TREE_TYPE (handler) && can_convert_eh (type, TREE_TYPE (handler))) 960169699Skan { 961169699Skan warning (0, "%Hexception of type %qT will be caught", 962169699Skan EXPR_LOCUS (handler), TREE_TYPE (handler)); 963169699Skan warning (0, "%H by earlier handler for %qT", 964169699Skan EXPR_LOCUS (master), type); 965169699Skan break; 966169699Skan } 967169699Skan } 96890289Sobrien} 96918334Speter 970169699Skan/* Given a STATEMENT_LIST of HANDLERs, make sure that they're OK. */ 97118659Sjdp 97290289Sobrienvoid 973132727Skancheck_handlers (tree handlers) 97490289Sobrien{ 975169699Skan tree_stmt_iterator i; 976169699Skan 977169699Skan /* If we don't have a STATEMENT_LIST, then we've just got one 978169699Skan handler, and thus nothing to warn about. */ 979169699Skan if (TREE_CODE (handlers) != STATEMENT_LIST) 980169699Skan return; 981169699Skan 982169699Skan i = tsi_start (handlers); 983169699Skan if (!tsi_end_p (i)) 984169699Skan while (1) 985169699Skan { 986169699Skan tree handler = tsi_stmt (i); 987169699Skan tsi_next (&i); 988169699Skan 989169699Skan /* No more handlers; nothing to shadow. */ 990169699Skan if (tsi_end_p (i)) 991169699Skan break; 992169699Skan if (TREE_TYPE (handler) == NULL_TREE) 993169699Skan pedwarn ("%H%<...%> handler must be the last handler for" 994169699Skan " its try block", EXPR_LOCUS (handler)); 995169699Skan else 996169699Skan check_handlers_1 (handler, i); 997169699Skan } 99818334Speter} 999