re PR c++/5636 (gcc-3.0.3, memory leakage: function that take a string as parameter will not call local variable destructors if exception is thrown.)

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.
        * cp/semantics.c (nullify_returns_r): Just set CLEANUP_EH_ONLY on
        cleanup for nrv.

        * 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.

cp/:
        * 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.

From-SVN: r51827
This commit is contained in:
Jason Merrill 2002-04-03 19:11:00 -05:00
parent 053d3344d4
commit 659e5a7aa9
18 changed files with 121 additions and 183 deletions

View File

@ -1,3 +1,22 @@
2002-04-03 Jason Merrill <jason@redhat.com>
* 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 <hp@axis.com>
* config/cris/cris.c (cris_target_asm_function_prologue): Cast
@ -1497,7 +1516,7 @@ Fri Mar 22 12:08:36 CET 2002 Jan Hubicka <jh@suse.cz>
* 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.

View File

@ -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));

View File

@ -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:

View File

@ -1,5 +1,24 @@
2002-04-04 Jason Merrill <jason@redhat.com>
* 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.

View File

@ -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)

View File

@ -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 *));

View File

@ -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

View File

@ -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));

View File

@ -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);

View File

@ -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 ();
}

View File

@ -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;

View File

@ -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:

View File

@ -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. */

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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));