diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ce125acd123..57e66e4c992 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2002-04-03 Jason Merrill + + * except.c (struct eh_status): Remove protect_list. + (begin_protect_partials, end_protect_partials): Remove. + (add_partial_entry): Remove. + * except.h: Remove prototypes. + + * expr.c (expand_expr) [WITH_CLEANUP_EXPR, TARGET_EXPR]: Use + expand_decl_cleanup_eh. + + PR c++/5636 + * tree.h (CLEANUP_EH_ONLY): New macro. + * stmt.c (expand_decl_cleanup_eh): New fn. + (expand_cleanups): Check CLEANUP_EH_ONLY. + * c-semantics.c (genrtl_decl_cleanup): Just take the CLEANUP_STMT. + Use expand_decl_cleanup_eh. + (expand_stmt): Adjust. + * c-common.h: Adjust prototype. + 2002-04-04 Hans-Peter Nilsson * config/cris/cris.c (cris_target_asm_function_prologue): Cast @@ -1497,7 +1516,7 @@ Fri Mar 22 12:08:36 CET 2002 Jan Hubicka * flags.h (flag_really_no_inline): New. - * c-common.c (c_common_post_options): Initialzie + * c-common.c (c_common_post_options): Initialize flag_really_no_inline. * toplev.c (flag_really_no_inline): New. diff --git a/gcc/c-common.h b/gcc/c-common.h index 5dde85a8ee3..cb49b529e80 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -765,7 +765,7 @@ extern void genrtl_compound_stmt PARAMS ((tree)); extern void genrtl_asm_stmt PARAMS ((tree, tree, tree, tree, tree, int)); -extern void genrtl_decl_cleanup PARAMS ((tree, tree)); +extern void genrtl_decl_cleanup PARAMS ((tree)); extern int stmts_are_full_exprs_p PARAMS ((void)); extern int anon_aggr_type_p PARAMS ((tree)); diff --git a/gcc/c-semantics.c b/gcc/c-semantics.c index 3d8759d8584..030a04cb009 100644 --- a/gcc/c-semantics.c +++ b/gcc/c-semantics.c @@ -737,12 +737,12 @@ genrtl_asm_stmt (cv_qualifier, string, output_operands, /* Generate the RTL for a DECL_CLEANUP. */ void -genrtl_decl_cleanup (decl, cleanup) - tree decl; - tree cleanup; +genrtl_decl_cleanup (t) + tree t; { + tree decl = CLEANUP_DECL (t); if (!decl || (DECL_SIZE (decl) && TREE_TYPE (decl) != error_mark_node)) - expand_decl_cleanup (decl, cleanup); + expand_decl_cleanup_eh (decl, CLEANUP_EXPR (t), CLEANUP_EH_ONLY (t)); } /* We're about to expand T, a statement. Set up appropriate context @@ -848,7 +848,7 @@ expand_stmt (t) break; case CLEANUP_STMT: - genrtl_decl_cleanup (CLEANUP_DECL (t), CLEANUP_EXPR (t)); + genrtl_decl_cleanup (t); break; default: diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 15e12d6858c..756d2b30c63 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,24 @@ 2002-04-04 Jason Merrill + * semantics.c (finish_eh_cleanup): New fn. + * cp-tree.h: Add prototype. + * init.c (perform_member_init, expand_cleanup_for_base): Use + finish_eh_cleanup. + * cp-tree.def (SUBOBJECT, CTOR_STMT): Remove. + * cp-tree.h: Remove references. + * decl.c (begin_constructor_body, end_constructor_body): Likewise. + * dump.c (cp_dump_tree): Likewise. + * pt.c (tsubst_expr): Likewise. + * semantics.c (genrtl_ctor_stmt, genrtl_subobject): Remove. + (cp_expand_stmt): Remove handling of CTOR_STMT and SUBOBJECT. + * tree.c (cp_statement_code_p): Likewise. + + * init.c (build_new_1): Set CLEANUP_EH_ONLY on deleting cleanup. + + PR c++/5636 + * semantics.c (nullify_returns_r): Just set CLEANUP_EH_ONLY on + cleanup for nrv. + PR c++/5104 * typeck.c (comptypes) [FUNCTION_TYPE]: Don't compare exception specifiers. diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 38545256114..1bf4c0d2ec6 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -220,16 +220,6 @@ DEFTREECODE (DOTSTAR_EXPR, "dotstar_expr", 'e', 2) DEFTREECODE (TYPEID_EXPR, "typeid_expr", 'e', 1) DEFTREECODE (PSEUDO_DTOR_EXPR, "pseudo_dtor_expr", 'e', 3) -/* A SUBOBJECT statement marks the point at which a sub-object is - fully constructed. After this point, the SUBOBJECT_CLEANUP must be - run if an exception is thrown before the end of the enclosing - function. */ -DEFTREECODE (SUBOBJECT, "subobject", 'e', 1) -/* An CTOR_STMT marks the beginning (if CTOR_BEGIN_P holds) or end of - a constructor (if CTOR_END_P) holds. At the end of a constructor, - the cleanups associated with any SUBOBJECT_CLEANUPS need no longer - be run. */ -DEFTREECODE (CTOR_STMT, "ctor_stmt", 'e', 0) /* CTOR_INITIALIZER is a placeholder in template code for a call to setup_vtbl_pointer (and appears in all functions, not just ctors). */ DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 2) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index dbd95550242..b65467bae1d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -47,7 +47,6 @@ struct diagnostic_context; ICS_USER_FLAG (in _CONV) CLEANUP_P (in TRY_BLOCK) AGGR_INIT_VIA_CTOR_P (in AGGR_INIT_EXPR) - CTOR_BEGIN_P (in CTOR_STMT) BV_USE_VCALL_INDEX_P (in the BINFO_VIRTUALS TREE_LIST) PTRMEM_OK_P (in ADDR_EXPR, OFFSET_REF) PARMLIST_ELLIPSIS_P (in PARMLIST) @@ -2969,15 +2968,6 @@ enum ptrmemfunc_vbit_where_t #define HANDLER_PARMS(NODE) TREE_OPERAND (HANDLER_CHECK (NODE), 0) #define HANDLER_BODY(NODE) TREE_OPERAND (HANDLER_CHECK (NODE), 1) #define HANDLER_TYPE(NODE) TREE_TYPE (HANDLER_CHECK (NODE)) -#define SUBOBJECT_CLEANUP(NODE) TREE_OPERAND (SUBOBJECT_CHECK (NODE), 0) - -/* Nonzero if this CTOR_STMT is for the beginning of a constructor. */ -#define CTOR_BEGIN_P(NODE) \ - (TREE_LANG_FLAG_0 (CTOR_STMT_CHECK (NODE))) - -/* Nonzero if this CTOR_STMT is for the end of a constructor. */ -#define CTOR_END_P(NODE) \ - (!CTOR_BEGIN_P (NODE)) /* The parameters for a call-declarator. */ #define CALL_DECLARATOR_PARMS(NODE) \ @@ -4217,6 +4207,7 @@ extern tree finish_typeof PARAMS ((tree)); extern tree finish_sizeof PARAMS ((tree)); extern tree finish_alignof PARAMS ((tree)); extern void finish_decl_cleanup PARAMS ((tree, tree)); +extern void finish_eh_cleanup PARAMS ((tree)); extern void finish_named_return_value PARAMS ((tree, tree)); extern void expand_body PARAMS ((tree)); extern tree nullify_returns_r PARAMS ((tree *, int *, void *)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 840dcff2d50..78f1b14a7f3 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -13948,9 +13948,6 @@ save_function_data (decl) static void begin_constructor_body () { - tree ctor_stmt = build_stmt (CTOR_STMT); - CTOR_BEGIN_P (ctor_stmt) = 1; - add_stmt (ctor_stmt); } /* Add a note to mark the end of the main body of the constructor. This is @@ -13960,12 +13957,6 @@ begin_constructor_body () static void finish_constructor_body () { - /* Mark the end of the cleanups for a partially constructed object. - - ??? These should really be handled automatically by closing the block, - as with the destructor cleanups; the only difference is that these are - only run if an exception is thrown. */ - add_stmt (build_stmt (CTOR_STMT)); } /* Do all the processing for the beginning of a destructor; set up the diff --git a/gcc/cp/dump.c b/gcc/cp/dump.c index 6dd60baf73b..e0bc410bcae 100644 --- a/gcc/cp/dump.c +++ b/gcc/cp/dump.c @@ -390,15 +390,6 @@ cp_dump_tree (dump_info, t) dump_child ("decl", TREE_OPERAND (t, 2)); break; - case CTOR_STMT: - dump_stmt (di, t); - if (CTOR_BEGIN_P (t)) - dump_string (di, "begn"); - else - dump_string (di, "end"); - dump_next_stmt (di, t); - break; - case HANDLER: dump_stmt (di, t); dump_child ("parm", HANDLER_PARMS (t)); @@ -412,12 +403,6 @@ cp_dump_tree (dump_info, t) dump_next_stmt (di, t); break; - case SUBOBJECT: - dump_stmt (di, t); - dump_child ("clnp", TREE_OPERAND (t, 0)); - dump_next_stmt (di, t); - break; - case USING_STMT: dump_stmt (di, t); dump_child ("nmsp", USING_STMT_NAMESPACE (t)); diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 10098e72cfa..8b7e1f239a4 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -296,7 +296,7 @@ perform_member_init (member, init, explicit) LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0); if (expr != error_mark_node) - finish_subobject (expr); + finish_eh_cleanup (expr); } } @@ -844,7 +844,7 @@ expand_cleanup_for_base (binfo, flag) truthvalue_conversion (flag), expr, integer_zero_node)); - finish_subobject (expr); + finish_eh_cleanup (expr); } /* Subroutine of `expand_aggr_vbase_init'. @@ -2498,9 +2498,11 @@ build_new_1 (exp) tree end, sentry, begin; begin = get_target_expr (boolean_true_node); - sentry = TREE_OPERAND (begin, 0); + CLEANUP_EH_ONLY (begin) = 1; - TREE_OPERAND (begin, 2) + sentry = TARGET_EXPR_SLOT (begin); + + TARGET_EXPR_CLEANUP (begin) = build (COND_EXPR, void_type_node, sentry, cleanup, void_zero_node); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d28298a56a3..b7057830686 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -7584,10 +7584,6 @@ tsubst_expr (t, args, complain, in_decl) tsubst (TREE_TYPE (t), args, complain, NULL_TREE); break; - case CTOR_STMT: - add_stmt (copy_node (t)); - break; - default: abort (); } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 8666d7f02c4..ee609f45363 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -56,8 +56,6 @@ static void emit_associated_thunks PARAMS ((tree)); static void genrtl_try_block PARAMS ((tree)); static void genrtl_eh_spec_block PARAMS ((tree)); static void genrtl_handler PARAMS ((tree)); -static void genrtl_ctor_stmt PARAMS ((tree)); -static void genrtl_subobject PARAMS ((tree)); static void genrtl_named_return_value PARAMS ((void)); static void cp_expand_stmt PARAMS ((tree)); static void genrtl_start_function PARAMS ((tree)); @@ -777,21 +775,6 @@ finish_handler (handler) RECHAIN_STMTS (handler, HANDLER_BODY (handler)); } -/* Generate the RTL for T, which is a CTOR_STMT. */ - -static void -genrtl_ctor_stmt (t) - tree t; -{ - if (CTOR_BEGIN_P (t)) - begin_protect_partials (); - else - /* After this point, any exceptions will cause the - destructor to be executed, so we no longer need to worry - about destroying the various subobjects ourselves. */ - end_protect_partials (); -} - /* Begin a compound-statement. If HAS_NO_SCOPE is non-zero, the compound-statement does not define a scope. Returns a new COMPOUND_STMT if appropriate. */ @@ -976,27 +959,6 @@ finish_label_decl (name) add_decl_stmt (decl); } -/* Generate the RTL for a SUBOBJECT. */ - -static void -genrtl_subobject (cleanup) - tree cleanup; -{ - add_partial_entry (cleanup); -} - -/* We're in a constructor, and have just constructed a a subobject of - *THIS. CLEANUP is code to run if an exception is thrown before the - end of the current function is reached. */ - -void -finish_subobject (cleanup) - tree cleanup; -{ - tree r = build_stmt (SUBOBJECT, cleanup); - add_stmt (r); -} - /* When DECL goes out of scope, make sure that CLEANUP is executed. */ void @@ -1007,6 +969,17 @@ finish_decl_cleanup (decl, cleanup) add_stmt (build_stmt (CLEANUP_STMT, decl, cleanup)); } +/* If the current scope exits with an exception, run CLEANUP. */ + +void +finish_eh_cleanup (cleanup) + tree cleanup; +{ + tree r = build_stmt (CLEANUP_STMT, NULL_TREE, cleanup); + CLEANUP_EH_ONLY (r) = 1; + add_stmt (r); +} + /* Generate the RTL for a RETURN_INIT. */ static void @@ -2130,10 +2103,6 @@ cp_expand_stmt (t) { switch (TREE_CODE (t)) { - case CTOR_STMT: - genrtl_ctor_stmt (t); - break; - case TRY_BLOCK: genrtl_try_block (t); break; @@ -2146,10 +2115,6 @@ cp_expand_stmt (t) genrtl_handler (t); break; - case SUBOBJECT: - genrtl_subobject (SUBOBJECT_CLEANUP (t)); - break; - case RETURN_INIT: genrtl_named_return_value (); break; @@ -2458,7 +2423,7 @@ nullify_returns_r (tp, walk_subtrees, data) RETURN_EXPR (*tp) = NULL_TREE; else if (TREE_CODE (*tp) == CLEANUP_STMT && CLEANUP_DECL (*tp) == nrv) - CLEANUP_EXPR (*tp) = NULL_TREE; + CLEANUP_EH_ONLY (*tp) = 1; /* Keep iterating. */ return NULL_TREE; diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index c96f0e24d77..e0f73617449 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1030,8 +1030,6 @@ cp_statement_code_p (code) { switch (code) { - case SUBOBJECT: - case CTOR_STMT: case CTOR_INITIALIZER: case RETURN_INIT: case TRY_BLOCK: diff --git a/gcc/except.c b/gcc/except.c index 3eb31bd0237..e5079f99e0d 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -214,12 +214,6 @@ struct eh_status /* This is the region for which we are processing catch blocks. */ struct eh_region *try_region; - /* A stack (TREE_LIST) of lists of handlers. The TREE_VALUE of each - node is itself a TREE_CHAINed list of handlers for regions that - are not yet closed. The TREE_VALUE of each entry contains the - handler for the corresponding entry on the ehstack. */ - tree protect_list; - rtx filter; rtx exc_ptr; @@ -560,7 +554,6 @@ mark_eh_status (eh) tree_done:; } - ggc_mark_tree (eh->protect_list); ggc_mark_rtx (eh->filter); ggc_mark_rtx (eh->exc_ptr); ggc_mark_tree_varray (eh->ttype_data); @@ -1011,55 +1004,6 @@ get_exception_filter (fun) } return filter; } - -/* Begin a region that will contain entries created with - add_partial_entry. */ - -void -begin_protect_partials () -{ - /* Push room for a new list. */ - cfun->eh->protect_list - = tree_cons (NULL_TREE, NULL_TREE, cfun->eh->protect_list); -} - -/* Start a new exception region for a region of code that has a - cleanup action and push the HANDLER for the region onto - protect_list. All of the regions created with add_partial_entry - will be ended when end_protect_partials is invoked. - - ??? The only difference between this purpose and that of - expand_decl_cleanup is that in this case, we only want the cleanup to - run if an exception is thrown. This should also be handled using - binding levels. */ - -void -add_partial_entry (handler) - tree handler; -{ - expand_eh_region_start (); - - /* Add this entry to the front of the list. */ - TREE_VALUE (cfun->eh->protect_list) - = tree_cons (NULL_TREE, handler, TREE_VALUE (cfun->eh->protect_list)); -} - -/* End all the pending exception regions on protect_list. */ - -void -end_protect_partials () -{ - tree t; - - /* Pop the topmost entry. */ - t = TREE_VALUE (cfun->eh->protect_list); - cfun->eh->protect_list = TREE_CHAIN (cfun->eh->protect_list); - - /* End all the exception regions. */ - for (; t; t = TREE_CHAIN (t)) - expand_eh_region_end_cleanup (TREE_VALUE (t)); -} - /* This section is for the exception handling specific optimization pass. */ diff --git a/gcc/except.h b/gcc/except.h index 27dc7143f6c..200210f31bc 100644 --- a/gcc/except.h +++ b/gcc/except.h @@ -83,20 +83,6 @@ extern void expand_eh_region_end_throw PARAMS ((tree)); destroying an object twice. */ extern void expand_eh_region_end_fixup PARAMS ((tree)); -/* Begin a region that will contain entries created with - add_partial_entry. */ -extern void begin_protect_partials PARAMS ((void)); - -/* Create a new exception region and add the handler for the region - onto a list. These regions will be ended (and their handlers emitted) - when end_protect_partials is invoked. */ -extern void add_partial_entry PARAMS ((tree)); - -/* End all of the pending exception regions that have handlers added with - add_partial_entry. */ -extern void end_protect_partials PARAMS ((void)); - - /* A list of labels used for exception handlers. */ extern rtx exception_handler_labels; diff --git a/gcc/expr.c b/gcc/expr.c index 6f1a0d62eef..066b454a735 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -7209,7 +7209,8 @@ expand_expr (exp, target, tmode, modifier) { WITH_CLEANUP_EXPR_RTL (exp) = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier); - expand_decl_cleanup (NULL_TREE, TREE_OPERAND (exp, 1)); + expand_decl_cleanup_eh (NULL_TREE, TREE_OPERAND (exp, 1), + CLEANUP_EH_ONLY (exp)); /* That's it for this cleanup. */ TREE_OPERAND (exp, 1) = 0; @@ -8422,7 +8423,7 @@ expand_expr (exp, target, tmode, modifier) store_expr (exp1, target, 0); - expand_decl_cleanup (NULL_TREE, cleanups); + expand_decl_cleanup_eh (NULL_TREE, cleanups, CLEANUP_EH_ONLY (exp)); return target; } diff --git a/gcc/stmt.c b/gcc/stmt.c index 9a72b8784f4..2e8aeb628c6 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -4169,6 +4169,23 @@ expand_decl_cleanup (decl, cleanup) } return 1; } + +/* Like expand_decl_cleanup, but maybe only run the cleanup if an exception + is thrown. */ + +int +expand_decl_cleanup_eh (decl, cleanup, eh_only) + tree decl, cleanup; + int eh_only; +{ + int ret = expand_decl_cleanup (decl, cleanup); + if (cleanup && ret) + { + tree node = block_stack->data.block.cleanups; + CLEANUP_EH_ONLY (node) = eh_only; + } + return ret; +} /* DECL is an anonymous union. CLEANUP is a cleanup for DECL. DECL_ELTS is the list of elements that belong to DECL's type. @@ -4277,7 +4294,7 @@ expand_cleanups (list, dont_do, in_fixup, reachable) if (! in_fixup && using_eh_for_cleanups_p) expand_eh_region_end_cleanup (TREE_VALUE (tail)); - if (reachable) + if (reachable && !CLEANUP_EH_ONLY (tail)) { /* Cleanups may be run multiple times. For example, when exiting a binding contour, we expand the diff --git a/gcc/testsuite/g++.dg/eh/nrv1.C b/gcc/testsuite/g++.dg/eh/nrv1.C new file mode 100644 index 00000000000..e2457e87e65 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/nrv1.C @@ -0,0 +1,25 @@ +// PR c++/5636 +// Bug: the named return value optimization interfered with EH cleanups. + +int c, d; + +struct A +{ + A() { ++c; } + ~A() { ++d; } +}; + +A f() +{ + A nrv; + throw 42; + return nrv; +} + +int main() +{ + try + { A a = f(); } + catch (...) { } + return (d < c); +} diff --git a/gcc/tree.h b/gcc/tree.h index ad24904f1d6..950463f6372 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -177,6 +177,9 @@ struct tree_common INTEGER_CST, REAL_CST, COMPLEX_CST, VECTOR_CST TREE_SYMBOL_REFERENCED in IDENTIFIER_NODE + CLEANUP_EH_ONLY in + TARGET_EXPR, WITH_CLEANUP_EXPR, CLEANUP_STMT, + TREE_LIST elements of a block's cleanup list. public_flag: @@ -194,7 +197,7 @@ struct tree_common TREE_VIA_PRIVATE in TREE_LIST or TREE_VEC TREE_PRIVATE in - ??? unspecified nodes + ..._DECL protected_flag: @@ -203,7 +206,7 @@ struct tree_common TREE_VEC TREE_PROTECTED in BLOCK - ??? unspecified nodes + ..._DECL side_effects_flag: @@ -503,6 +506,11 @@ extern void tree_class_check_failed PARAMS ((const tree, int, In a CONSTRUCTOR, nonzero means allocate static storage. */ #define TREE_STATIC(NODE) ((NODE)->common.static_flag) +/* In a TARGET_EXPR, WITH_CLEANUP_EXPR, CLEANUP_STMT, or element of a + block's cleanup list, means that the pertinent cleanup should only be + executed if an exception is thrown, not on normal exit of its scope. */ +#define CLEANUP_EH_ONLY(NODE) ((NODE)->common.static_flag) + /* In a CONVERT_EXPR, NOP_EXPR or COMPOUND_EXPR, this means the node was made implicitly and should not lead to an "unused value" warning. */ #define TREE_NO_UNUSED_WARNING(NODE) ((NODE)->common.static_flag) @@ -2985,6 +2993,7 @@ extern void expand_elseif PARAMS ((tree)); extern void save_stack_pointer PARAMS ((void)); extern void expand_decl PARAMS ((tree)); extern int expand_decl_cleanup PARAMS ((tree, tree)); +extern int expand_decl_cleanup_eh PARAMS ((tree, tree, int)); extern void expand_anon_union_decl PARAMS ((tree, tree, tree)); extern void move_cleanups_up PARAMS ((void)); extern void expand_start_case_dummy PARAMS ((void));