This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH to destructor cleanups
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 14 Dec 2001 03:08:45 +0000
- Subject: C++ PATCH to destructor cleanups
We weren't properly destroying the bases and members of an object before
transferring control to a catch clause of a destructor function-try-block.
It seemed to me that the best way to deal with this would be to change the
member destruction to use cleanups; that way we get the exception semantics
for free.
In order to use the cleanups, I needed to add an additional binding level
around the main compound-statement of the function for destructors, as we
already did for constructors with explicit member-initializers. It seemed
simplest just to add it unconditionally. I also moved the destructor
deletion and constructor end-of-partial-cleanups stuff to the end of this
"body" block rather than end of function, since they are not relevant to
the function-catch clauses, and this allowed me to remove a redundant
end_protect_partials from the function-try-block handling.
I'm not entirely comfortable with the name "body block"; alternate
suggestions are welcome.
Tested i686-pc-linux-gnu. Test in g++.dg/eh/dtor1.C.
2001-12-13 Jason Merrill <jason@redhat.com>
* c-common.h (COMPOUND_STMT_BODY_BLOCK): New macro.
2001-12-13 Jason Merrill <jason@redhat.com>
* Make-lang.in (parse.h): Separate rule, just depend on parse.c.
Use cleanups to run base and member destructors.
* init.c (push_base_cleanups): New function, split out from...
(build_delete): ...here. Lose !TYPE_HAS_DESTRUCTOR code.
* decl.c (finish_destructor_body): Move vbase destruction code to
push_base_cleanups.
(begin_function_body, finish_function_body): New fns.
(finish_function): Move [cd]tor handling and call_poplevel to
finish_function_body.
(pushdecl): Skip the new level.
* semantics.c (genrtl_try_block): Don't call end_protect_partials.
(setup_vtbl_ptr): Call push_base_cleanups.
* method.c (synthesize_method): Call {begin,end}_function_body.
* pt.c (tsubst_expr): Handle COMPOUND_STMT_BODY_BLOCK.
* cp-tree.h: Declare new fns.
* parse.y (function_body, .begin_function_body): New nonterminals.
(fndef, pending_inline, function_try_block): Use function_body.
(ctor_initializer_opt, function_try_block): No longer has a value.
(base_init): Remove .set_base_init token.
(.set_base_init, compstmt_or_error): Remove.
* Make-lang.in (parse.c): Expect two fewer s/r conflicts.
Index: c-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.106
diff -c -p -r1.106 c-common.h
*** c-common.h 2001/12/11 19:42:32 1.106
--- c-common.h 2001/12/14 02:47:33
*************** Software Foundation, 59 Temple Place - S
*** 37,42 ****
--- 37,43 ----
STMT_IS_FULL_EXPR_P (in _STMT)
2: STMT_LINENO_FOR_FN_P (in _STMT)
3: SCOPE_NO_CLEANUPS_P (in SCOPE_STMT)
+ COMPOUND_STMT_BODY_BLOCK (in COMPOUND_STMT)
4: SCOPE_PARTIAL_P (in SCOPE_STMT)
*/
*************** extern tree build_break_stmt
*** 761,766 ****
--- 762,771 ----
extern tree build_return_stmt PARAMS ((tree));
#define COMPOUND_STMT_NO_SCOPE(NODE) TREE_LANG_FLAG_0 (NODE)
+
+ /* Used by the C++ frontend to mark the block around the member
+ initializers and cleanups. */
+ #define COMPOUND_STMT_BODY_BLOCK(NODE) TREE_LANG_FLAG_3 (NODE)
extern void c_expand_asm_operands PARAMS ((tree, tree, tree, tree, int, const char *, int));
Index: cp/Make-lang.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/Make-lang.in,v
retrieving revision 1.102
diff -c -p -r1.102 Make-lang.in
*** cp/Make-lang.in 2001/12/03 12:39:46 1.102
--- cp/Make-lang.in 2001/12/14 02:47:58
*************** $(srcdir)/cp/cfns.h: $(srcdir)/cp/cfns.g
*** 118,125 ****
gperf -o -C -E -k '1-6,$$' -j1 -D -N 'libc_name_p' \
$(srcdir)/cp/cfns.gperf > $(srcdir)/cp/cfns.h
! $(srcdir)/cp/parse.h $(srcdir)/cp/parse.c: $(srcdir)/cp/parse.y
! @echo "Expect 36 shift/reduce conflicts and 58 reduce/reduce conflicts."
cd $(srcdir)/cp; $(BISON) $(BISONFLAGS) -d -o p$$$$.c parse.y ; \
grep '^#define[ ]*YYEMPTY' p$$$$.c >> p$$$$.h ; \
mv -f p$$$$.c parse.c ; mv -f p$$$$.h parse.h
--- 118,126 ----
gperf -o -C -E -k '1-6,$$' -j1 -D -N 'libc_name_p' \
$(srcdir)/cp/cfns.gperf > $(srcdir)/cp/cfns.h
! $(srcdir)/cp/parse.h: $(srcdir)/cp/parse.c
! $(srcdir)/cp/parse.c: $(srcdir)/cp/parse.y
! @echo "Expect 34 shift/reduce conflicts and 58 reduce/reduce conflicts."
cd $(srcdir)/cp; $(BISON) $(BISONFLAGS) -d -o p$$$$.c parse.y ; \
grep '^#define[ ]*YYEMPTY' p$$$$.c >> p$$$$.h ; \
mv -f p$$$$.c parse.c ; mv -f p$$$$.h parse.h
Index: cp/cp-tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.def,v
retrieving revision 1.60
diff -c -p -r1.60 cp-tree.def
*** cp/cp-tree.def 2001/10/23 09:14:11 1.60
--- cp/cp-tree.def 2001/12/14 02:47:59
*************** DEFTREECODE (CTOR_STMT, "ctor_stmt", 'e'
*** 234,239 ****
--- 234,241 ----
constructed. If, after this point, the CLEANUP_DECL goes out of
scope, the CLEANUP_EXPR must be run. */
DEFTREECODE (CLEANUP_STMT, "cleanup_stmt", 'e', 2)
+ /* 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)
DEFTREECODE (RETURN_INIT, "return_init", 'e', 2)
DEFTREECODE (TRY_BLOCK, "try_block", 'e', 2)
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.664
diff -c -p -r1.664 cp-tree.h
*** cp/cp-tree.h 2001/12/13 01:37:48 1.664
--- cp/cp-tree.h 2001/12/14 02:48:13
*************** extern tree start_enum PARAMS ((tree)
*** 3677,3682 ****
--- 3677,3684 ----
extern void finish_enum PARAMS ((tree));
extern void build_enumerator PARAMS ((tree, tree, tree));
extern int start_function PARAMS ((tree, tree, tree, int));
+ extern tree begin_function_body PARAMS ((void));
+ extern void finish_function_body PARAMS ((tree));
extern tree finish_function PARAMS ((int));
extern tree start_method PARAMS ((tree, tree, tree));
extern tree finish_method PARAMS ((tree));
*************** extern tree build_new PARAMS ((tree,
*** 3849,3854 ****
--- 3851,3857 ----
extern tree build_vec_init PARAMS ((tree, tree, int));
extern tree build_x_delete PARAMS ((tree, int, tree));
extern tree build_delete PARAMS ((tree, tree, special_function_kind, int, int));
+ extern void push_base_cleanups PARAMS ((void));
extern tree build_vbase_delete PARAMS ((tree, tree));
extern tree build_vec_delete PARAMS ((tree, tree, special_function_kind, int));
extern tree create_temporary_var PARAMS ((tree));
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.840
diff -c -p -r1.840 decl.c
*** cp/decl.c 2001/12/13 01:37:49 1.840
--- cp/decl.c 2001/12/14 02:48:36
*************** pushdecl (x)
*** 4188,4195 ****
them there. */
struct binding_level *b = current_binding_level->level_chain;
! if (cleanup_label)
! b = b->level_chain;
/* ARM $8.3 */
if (b->parm_flag == 1)
--- 4188,4195 ----
them there. */
struct binding_level *b = current_binding_level->level_chain;
! /* Skip the ctor/dtor cleanup level. */
! b = b->level_chain;
/* ARM $8.3 */
if (b->parm_flag == 1)
*************** save_function_data (decl)
*** 13920,14025 ****
}
}
! /* At the end of every constructor we generate to code to return
! `this'. Do that now. */
static void
finish_constructor_body ()
{
! /* Mark the end of the constructor. */
add_stmt (build_stmt (CTOR_STMT));
}
! /* At the end of every destructor we generate code to restore virtual
! function tables to the values desired by base classes and to call
! to base class destructors. Do that now. */
static void
finish_destructor_body ()
{
- tree compound_stmt;
tree exprstmt;
- /* Create a block to contain all the extra code. */
- compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
-
- /* Any return from a destructor will end up here. */
- add_stmt (build_stmt (LABEL_STMT, dtor_label));
-
- /* Generate the code to call destructor on base class. If this
- destructor belongs to a class with virtual functions, then set
- the virtual function table pointer to represent the type of our
- base class. */
-
- /* This side-effect makes call to `build_delete' generate the code
- we have to have at the end of this destructor. `build_delete'
- will set the flag again. */
- TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
-
- exprstmt = build_delete (current_class_type,
- current_class_ref,
- sfk_base_destructor,
- LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
- 0);
-
- if (exprstmt != error_mark_node
- && (TREE_CODE (exprstmt) != NOP_EXPR
- || TREE_OPERAND (exprstmt, 0) != integer_zero_node
- || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)))
- {
- if (exprstmt != void_zero_node)
- /* Don't call `expand_expr_stmt' if we're not going to do
- anything, since -Wall will give a diagnostic. */
- finish_expr_stmt (exprstmt);
-
- /* Run destructors for all virtual baseclasses. */
- if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
- {
- tree vbases;
- tree if_stmt;
-
- if_stmt = begin_if_stmt ();
- finish_if_stmt_cond (build (BIT_AND_EXPR, integer_type_node,
- current_in_charge_parm,
- integer_two_node),
- if_stmt);
-
- vbases = CLASSTYPE_VBASECLASSES (current_class_type);
- /* The CLASSTYPE_VBASECLASSES list is in initialization
- order, so we have to march through it in reverse order. */
- for (vbases = nreverse (copy_list (vbases));
- vbases;
- vbases = TREE_CHAIN (vbases))
- {
- tree vbase = TREE_VALUE (vbases);
- tree base_type = BINFO_TYPE (vbase);
-
- if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (base_type))
- {
- tree base_ptr_type = build_pointer_type (base_type);
- tree expr = current_class_ptr;
-
- /* Convert to the basetype here, as we know the layout is
- fixed. What is more, if we let build_method_call do it,
- it will use the vtable, which may have been clobbered
- by the deletion of our primary base. */
-
- expr = build1 (NOP_EXPR, base_ptr_type, expr);
- expr = build (PLUS_EXPR, base_ptr_type, expr,
- BINFO_OFFSET (vbase));
- expr = build_indirect_ref (expr, NULL);
- expr = build_method_call (expr, base_dtor_identifier,
- NULL_TREE, vbase,
- LOOKUP_NORMAL);
- finish_expr_stmt (expr);
- }
- }
-
- finish_then_clause (if_stmt);
- finish_if_stmt ();
- }
- }
-
/* In a virtual destructor, we must call delete. */
if (DECL_VIRTUAL_P (current_function_decl))
{
--- 13920,13948 ----
}
}
! /* Add a note to mark the end of the main body of the constructor. This is
! used to end the cleanup regions for fully-constructed bases and
! members. */
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));
}
! /* At the end of every destructor we generate code to delete the object if
! necessary. Do that now. */
static void
finish_destructor_body ()
{
tree exprstmt;
/* In a virtual destructor, we must call delete. */
if (DECL_VIRTUAL_P (current_function_decl))
{
*************** finish_destructor_body ()
*** 14045,14064 ****
finish_then_clause (if_stmt);
finish_if_stmt ();
}
-
- /* Close the block we started above. */
- finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
}
/* Finish up a function declaration and compile that function
all the way to assembler language output. The free the storage
for the function definition.
FLAGS is a bitwise or of the following values:
- 1 - CALL_POPLEVEL
- An extra call to poplevel (and expand_end_bindings) must be
- made to take care of the binding contour for the base
- initializers. This is only relevant for constructors.
2 - INCLASS_INLINE
We just finished processing the body of an in-class inline
function definition. (This processing will have taken place
--- 13968,14025 ----
finish_then_clause (if_stmt);
finish_if_stmt ();
}
}
+ /* Do the necessary processing for the beginning of a function body, which
+ in this case includes member-initializers, but not the catch clauses of
+ a function-try-block. Currently, this means opening a binding level
+ for the member-initializers (in a ctor) and member cleanups (in a dtor).
+ In other functions, this isn't necessary, but it doesn't hurt. */
+
+ tree
+ begin_function_body ()
+ {
+ tree stmt = begin_compound_stmt (0);
+ COMPOUND_STMT_BODY_BLOCK (stmt) = 1;
+ return stmt;
+ }
+
+ /* Do the processing for the end of a function body. Currently, this means
+ closing out the cleanups for fully-constructed bases and members, and in
+ the case of the destructor, deleting the object if desired. Again, this
+ is only meaningful for [cd]tors, since they are the only functions where
+ there is a significant distinction between the main body and any
+ function catch clauses. Handling, say, main() return semantics here
+ would be wrong, as flowing off the end of a function catch clause for
+ main() would also need to return 0. */
+
+ void
+ finish_function_body (compstmt)
+ tree compstmt;
+ {
+ if (processing_template_decl)
+ /* Do nothing now. */;
+ else if (DECL_DESTRUCTOR_P (current_function_decl))
+ /* Any return from a destructor will end up here. Put it before the
+ cleanups so that an explicit return doesn't duplicate them. */
+ add_stmt (build_stmt (LABEL_STMT, dtor_label));
+
+ /* Close the block; in a destructor, run the member cleanups. */
+ finish_compound_stmt (0, compstmt);
+
+ if (processing_template_decl)
+ /* Do nothing now. */;
+ else if (DECL_CONSTRUCTOR_P (current_function_decl))
+ finish_constructor_body ();
+ else if (DECL_DESTRUCTOR_P (current_function_decl))
+ finish_destructor_body ();
+ }
+
/* Finish up a function declaration and compile that function
all the way to assembler language output. The free the storage
for the function definition.
FLAGS is a bitwise or of the following values:
2 - INCLASS_INLINE
We just finished processing the body of an in-class inline
function definition. (This processing will have taken place
*************** finish_function (flags)
*** 14070,14076 ****
{
register tree fndecl = current_function_decl;
tree fntype, ctype = NULL_TREE;
- int call_poplevel = (flags & 1) != 0;
int inclass_inline = (flags & 2) != 0;
int nested;
--- 14031,14036 ----
*************** finish_function (flags)
*** 14094,14108 ****
there's no need to add any extra bits. */
if (!DECL_CLONED_FUNCTION_P (fndecl))
{
! if (DECL_CONSTRUCTOR_P (fndecl))
! {
! finish_constructor_body ();
! if (call_poplevel)
! do_poplevel ();
! }
! else if (DECL_DESTRUCTOR_P (fndecl) && !processing_template_decl)
! finish_destructor_body ();
! else if (DECL_MAIN_P (fndecl))
{
/* Make it so that `main' always returns 0 by default. */
#ifdef VMS_TARGET
--- 14054,14060 ----
there's no need to add any extra bits. */
if (!DECL_CLONED_FUNCTION_P (fndecl))
{
! if (DECL_MAIN_P (current_function_decl))
{
/* Make it so that `main' always returns 0 by default. */
#ifdef VMS_TARGET
Index: cp/init.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/init.c,v
retrieving revision 1.256
diff -c -p -r1.256 init.c
*** cp/init.c 2001/12/05 23:48:17 1.256
--- cp/init.c 2001/12/14 02:48:42
*************** build_dtor_call (exp, dtor_kind, flags)
*** 3078,3087 ****
sfk_deleting_destructor.
FLAGS is the logical disjunction of zero or more LOOKUP_
! flags. See cp-tree.h for more info.
- This function does not delete an object's virtual base classes. */
-
tree
build_delete (type, addr, auto_delete, flags, use_global_delete)
tree type, addr;
--- 3078,3085 ----
sfk_deleting_destructor.
FLAGS is the logical disjunction of zero or more LOOKUP_
! flags. See cp-tree.h for more info. */
tree
build_delete (type, addr, auto_delete, flags, use_global_delete)
tree type, addr;
*************** build_delete (type, addr, auto_delete, f
*** 3089,3095 ****
int flags;
int use_global_delete;
{
- tree member;
tree expr;
if (addr == error_mark_node)
--- 3087,3092 ----
*************** build_delete (type, addr, auto_delete, f
*** 3157,3171 ****
LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL),
NULL_TREE);
}
!
! /* Below, we will reverse the order in which these calls are made.
! If we have a destructor, then that destructor will take care
! of the base classes; otherwise, we must do that here. */
! if (TYPE_HAS_DESTRUCTOR (type))
{
tree do_delete = NULL_TREE;
tree ifexp;
/* For `::delete x', we must not use the deleting destructor
since then we would not be sure to get the global `operator
delete'. */
--- 3154,3166 ----
LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL),
NULL_TREE);
}
! else
{
tree do_delete = NULL_TREE;
tree ifexp;
+ my_friendly_assert (TYPE_HAS_DESTRUCTOR (type), 20011213);
+
/* For `::delete x', we must not use the deleting destructor
since then we would not be sure to get the global `operator
delete'. */
*************** build_delete (type, addr, auto_delete, f
*** 3215,3270 ****
return expr;
}
! else
! {
! /* We only get here from finish_function for a destructor. */
! tree binfos = BINFO_BASETYPES (TYPE_BINFO (type));
! int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (type);
! tree base_binfo = n_baseclasses > 0 ? TREE_VEC_ELT (binfos, 0) : NULL_TREE;
! tree exprstmt = NULL_TREE;
! tree ref = build_indirect_ref (addr, NULL);
!
! /* Set this again before we call anything, as we might get called
! recursively. */
! TYPE_HAS_DESTRUCTOR (type) = 1;
!
! /* If we have member delete or vbases, we call delete in
! finish_function. */
! my_friendly_assert (auto_delete == sfk_base_destructor, 20000411);
! /* Take care of the remaining baseclasses. */
! for (i = 0; i < n_baseclasses; i++)
! {
! base_binfo = TREE_VEC_ELT (binfos, i);
! if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo))
! || TREE_VIA_VIRTUAL (base_binfo))
! continue;
! expr = build_scoped_method_call (ref, base_binfo,
! base_dtor_identifier,
! NULL_TREE);
! exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
! }
! for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member))
{
! if (TREE_CODE (member) != FIELD_DECL)
! continue;
! if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (member)))
{
! tree this_member = build_component_ref (ref, DECL_NAME (member), NULL_TREE, 0);
! tree this_type = TREE_TYPE (member);
! expr = build_delete (this_type, this_member,
! sfk_complete_destructor, flags, 0);
! exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
}
}
! if (exprstmt)
! return build_compound_expr (exprstmt);
! /* Virtual base classes make this function do nothing. */
! return void_zero_node;
}
}
--- 3210,3307 ----
return expr;
}
! }
! /* At the beginning of a destructor, push cleanups that will call the
! destructors for our base classes and members.
! Called from setup_vtbl_ptr. */
! void
! push_base_cleanups ()
! {
! tree binfos;
! int i, n_baseclasses;
! tree member;
! tree expr;
! /* Run destructors for all virtual baseclasses. */
! if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
! {
! tree vbases;
! tree cond = (condition_conversion
! (build (BIT_AND_EXPR, integer_type_node,
! current_in_charge_parm,
! integer_two_node)));
!
! vbases = CLASSTYPE_VBASECLASSES (current_class_type);
! /* The CLASSTYPE_VBASECLASSES list is in initialization
! order, which is also the right order for pushing cleanups. */
! for (; vbases;
! vbases = TREE_CHAIN (vbases))
{
! tree vbase = TREE_VALUE (vbases);
! tree base_type = BINFO_TYPE (vbase);
!
! if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (base_type))
{
! tree base_ptr_type = build_pointer_type (base_type);
! expr = current_class_ptr;
!
! /* Convert to the basetype here, as we know the layout is
! fixed. What is more, if we let build_method_call do it,
! it will use the vtable, which may have been clobbered
! by the deletion of our primary base. */
!
! expr = build1 (NOP_EXPR, base_ptr_type, expr);
! expr = build (PLUS_EXPR, base_ptr_type, expr,
! BINFO_OFFSET (vbase));
! expr = build_indirect_ref (expr, NULL);
! expr = build_method_call (expr, base_dtor_identifier,
! NULL_TREE, vbase,
! LOOKUP_NORMAL);
! expr = build (COND_EXPR, void_type_node, cond,
! expr, void_zero_node);
! finish_decl_cleanup (NULL_TREE, expr);
}
}
+ }
+
+ binfos = BINFO_BASETYPES (TYPE_BINFO (current_class_type));
+ n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type);
! /* Take care of the remaining baseclasses. */
! for (i = 0; i < n_baseclasses; i++)
! {
! tree base_binfo = TREE_VEC_ELT (binfos, i);
! if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo))
! || TREE_VIA_VIRTUAL (base_binfo))
! continue;
!
! expr = build_scoped_method_call (current_class_ref, base_binfo,
! base_dtor_identifier,
! NULL_TREE);
!
! finish_decl_cleanup (NULL_TREE, expr);
! }
!
! for (member = TYPE_FIELDS (current_class_type); member;
! member = TREE_CHAIN (member))
! {
! if (TREE_CODE (member) != FIELD_DECL)
! continue;
! if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (member)))
! {
! tree this_member = (build_component_ref
! (current_class_ref, DECL_NAME (member),
! NULL_TREE, 0));
! tree this_type = TREE_TYPE (member);
! expr = build_delete (this_type, this_member,
! sfk_complete_destructor,
! LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
! 0);
! finish_decl_cleanup (NULL_TREE, expr);
! }
}
}
Index: cp/method.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/method.c,v
retrieving revision 1.212
diff -c -p -r1.212 method.c
*** cp/method.c 2001/12/13 01:37:51 1.212
--- cp/method.c 2001/12/14 02:48:44
*************** synthesize_method (fndecl)
*** 727,732 ****
--- 727,733 ----
int nested = (current_function_decl != NULL_TREE);
tree context = decl_function_context (fndecl);
int need_body = 1;
+ tree stmt;
if (at_eof)
import_export_decl (fndecl);
*************** synthesize_method (fndecl)
*** 757,762 ****
--- 758,764 ----
interface_unknown = 1;
start_function (NULL_TREE, fndecl, NULL_TREE, SF_DEFAULT | SF_PRE_PARSED);
clear_last_expr ();
+ stmt = begin_function_body ();
if (DECL_OVERLOADED_OPERATOR_P (fndecl) == NOP_EXPR)
{
*************** synthesize_method (fndecl)
*** 783,788 ****
--- 785,791 ----
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
}
+ finish_function_body (stmt);
expand_body (finish_function (0));
extract_interface_info ();
Index: cp/parse.y
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parse.y,v
retrieving revision 1.236
diff -c -p -r1.236 parse.y
*** cp/parse.y 2001/12/11 20:11:34 1.236
--- cp/parse.y 2001/12/14 02:48:50
*************** cp_parse_init ()
*** 385,391 ****
%token <pi> PRE_PARSED_FUNCTION_DECL
%type <ttype> component_constructor_declarator
%type <ttype> fn.def2 return_id constructor_declarator
! %type <itype> ctor_initializer_opt function_try_block
%type <ttype> named_class_head_sans_basetype
%type <ftype> class_head named_class_head
%type <ftype> named_complex_class_head_sans_basetype
--- 385,391 ----
%token <pi> PRE_PARSED_FUNCTION_DECL
%type <ttype> component_constructor_declarator
%type <ttype> fn.def2 return_id constructor_declarator
! %type <ttype> .begin_function_body
%type <ttype> named_class_head_sans_basetype
%type <ftype> class_head named_class_head
%type <ftype> named_complex_class_head_sans_basetype
*************** datadef:
*** 747,755 ****
ctor_initializer_opt:
nodecls
- { $$ = 0; }
| base_init
- { $$ = 1; }
;
maybe_return_init:
--- 747,753 ----
*************** eat_saved_input:
*** 763,773 ****
| END_OF_SAVED_INPUT
;
fndef:
! fn.def1 maybe_return_init ctor_initializer_opt compstmt_or_error
! { expand_body (finish_function ((int)$3)); }
| fn.def1 maybe_return_init function_try_block
! { expand_body (finish_function ((int)$3)); }
| fn.def1 maybe_return_init error
{ }
;
--- 761,778 ----
| END_OF_SAVED_INPUT
;
+ function_body:
+ .begin_function_body ctor_initializer_opt compstmt
+ {
+ finish_function_body ($1);
+ }
+ ;
+
fndef:
! fn.def1 maybe_return_init function_body
! { expand_body (finish_function (0)); }
| fn.def1 maybe_return_init function_try_block
! { expand_body (finish_function (0)); }
| fn.def1 maybe_return_init error
{ }
;
*************** return_init:
*** 890,914 ****
;
base_init:
! ':' .set_base_init member_init_list
{
! if ($3.new_type_flag == 0)
error ("no base or member initializers given following ':'");
! finish_mem_initializers ($3.t);
}
;
! .set_base_init:
/* empty */
{
! if (DECL_CONSTRUCTOR_P (current_function_decl))
! /* Make a contour for the initializer list. */
! do_pushlevel ();
! else if (current_class_type == NULL_TREE)
! error ("base initializers not allowed for non-member functions");
! else if (! DECL_CONSTRUCTOR_P (current_function_decl))
! error ("only constructors take base initializers");
}
;
--- 895,915 ----
;
base_init:
! ':' member_init_list
{
! if (! DECL_CONSTRUCTOR_P (current_function_decl))
! error ("only constructors take base initializers");
! else if ($2.new_type_flag == 0)
error ("no base or member initializers given following ':'");
! finish_mem_initializers ($2.t);
}
;
! .begin_function_body:
/* empty */
{
! $$ = begin_function_body ();
}
;
*************** initlist:
*** 2208,2221 ****
;
pending_inline:
! PRE_PARSED_FUNCTION_DECL maybe_return_init ctor_initializer_opt compstmt_or_error
{
! expand_body (finish_function ((int)$3 | 2));
process_next_inline ($1);
}
| PRE_PARSED_FUNCTION_DECL maybe_return_init function_try_block
{
! expand_body (finish_function ((int)$3 | 2));
process_next_inline ($1);
}
| PRE_PARSED_FUNCTION_DECL maybe_return_init error
--- 2209,2222 ----
;
pending_inline:
! PRE_PARSED_FUNCTION_DECL maybe_return_init function_body
{
! expand_body (finish_function (2));
process_next_inline ($1);
}
| PRE_PARSED_FUNCTION_DECL maybe_return_init function_try_block
{
! expand_body (finish_function (2));
process_next_inline ($1);
}
| PRE_PARSED_FUNCTION_DECL maybe_return_init error
*************** label_decl:
*** 3328,3340 ****
}
;
- /* This is the body of a function definition.
- It causes syntax errors to ignore to the next openbrace. */
- compstmt_or_error:
- compstmt
- | error compstmt
- ;
-
compstmt:
save_lineno '{'
{ $<ttype>$ = begin_compound_stmt (0); }
--- 3329,3334 ----
*************** simple_stmt:
*** 3499,3511 ****
function_try_block:
TRY
{ $<ttype>$ = begin_function_try_block (); }
! ctor_initializer_opt compstmt
{ finish_function_try_block ($<ttype>2); }
handler_seq
! {
! finish_function_handler_sequence ($<ttype>2);
! $$ = $3;
! }
;
try_block:
--- 3493,3502 ----
function_try_block:
TRY
{ $<ttype>$ = begin_function_try_block (); }
! function_body
{ finish_function_try_block ($<ttype>2); }
handler_seq
! { finish_function_handler_sequence ($<ttype>2); }
;
try_block:
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.562
diff -c -p -r1.562 pt.c
*** cp/pt.c 2001/12/09 16:33:42 1.562
--- cp/pt.c 2001/12/14 02:49:27
*************** tsubst_expr (t, args, complain, in_decl)
*** 7389,7397 ****
case COMPOUND_STMT:
{
prep_stmt (t);
! stmt = begin_compound_stmt (COMPOUND_STMT_NO_SCOPE (t));
tsubst_expr (COMPOUND_BODY (t), args, complain, in_decl);
! finish_compound_stmt (COMPOUND_STMT_NO_SCOPE (t), stmt);
}
break;
--- 7389,7405 ----
case COMPOUND_STMT:
{
prep_stmt (t);
! if (COMPOUND_STMT_BODY_BLOCK (t))
! stmt = begin_function_body ();
! else
! stmt = begin_compound_stmt (COMPOUND_STMT_NO_SCOPE (t));
!
tsubst_expr (COMPOUND_BODY (t), args, complain, in_decl);
!
! if (COMPOUND_STMT_BODY_BLOCK (t))
! finish_function_body (stmt);
! else
! finish_compound_stmt (COMPOUND_STMT_NO_SCOPE (t), stmt);
}
break;
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.236
diff -c -p -r1.236 semantics.c
*** cp/semantics.c 2001/12/13 01:37:52 1.236
--- cp/semantics.c 2001/12/14 02:49:32
*************** genrtl_try_block (t)
*** 580,586 ****
if (FN_TRY_BLOCK_P (t))
{
- end_protect_partials ();
expand_start_all_catch ();
in_function_try_handler = 1;
expand_stmt (TRY_HANDLERS (t));
--- 580,585 ----
*************** setup_vtbl_ptr (member_init_list, base_i
*** 1216,1221 ****
--- 1215,1224 ----
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
finish_then_clause (if_stmt);
finish_if_stmt ();
+
+ /* And insert cleanups for our bases and members so that they
+ will be properly destroyed if we throw. */
+ push_base_cleanups ();
}
/* Always keep the BLOCK node associated with the outermost pair of
*************** static void
*** 2559,2566 ****
genrtl_start_function (fn)
tree fn;
{
- tree parm;
-
/* Tell everybody what function we're processing. */
current_function_decl = fn;
/* Get the RTL machinery going for this function. */
--- 2562,2567 ----