Commit b9f04a84 by Ian Lance Taylor

Fix defer when not calling recover in function with named results.

From-SVN: r178905
parent fae3f459
...@@ -1592,15 +1592,25 @@ Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function, ...@@ -1592,15 +1592,25 @@ Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function,
&& !this->type_->results()->empty() && !this->type_->results()->empty()
&& !this->type_->results()->front().name().empty()) && !this->type_->results()->front().name().empty())
{ {
// If the result variables are named, we need to return them // If the result variables are named, and we are returning from
// again, because they might have been changed by a defer // this function rather than panicing through it, we need to
// function. // return them again, because they might have been changed by a
// defer function. The runtime routines set the defer_stack
// variable to true if we are returning from this function.
retval = this->return_value(gogo, named_function, end_loc, retval = this->return_value(gogo, named_function, end_loc,
&stmt_list); &stmt_list);
set = fold_build2_loc(end_loc, MODIFY_EXPR, void_type_node, set = fold_build2_loc(end_loc, MODIFY_EXPR, void_type_node,
DECL_RESULT(this->fndecl_), retval); DECL_RESULT(this->fndecl_), retval);
ret_stmt = fold_build1_loc(end_loc, RETURN_EXPR, void_type_node, set); ret_stmt = fold_build1_loc(end_loc, RETURN_EXPR, void_type_node, set);
append_to_statement_list(ret_stmt, &stmt_list);
Expression* ref =
Expression::make_temporary_reference(this->defer_stack_, end_loc);
tree tref = ref->get_tree(&context);
tree s = build3_loc(end_loc, COND_EXPR, void_type_node, tref,
ret_stmt, NULL_TREE);
append_to_statement_list(s, &stmt_list);
} }
go_assert(*fini == NULL_TREE); go_assert(*fini == NULL_TREE);
......
...@@ -2976,27 +2976,27 @@ Function::determine_types() ...@@ -2976,27 +2976,27 @@ Function::determine_types()
this->block_->determine_types(); this->block_->determine_types();
} }
// Get a pointer to the variable holding the defer stack for this // Get a pointer to the variable representing the defer stack for this
// function, making it if necessary. At least at present, the value // function, making it if necessary. The value of the variable is set
// of this variable is not used. However, a pointer to this variable // by the runtime routines to true if the function is returning,
// is used as a marker for the functions on the defer stack associated // rather than panicing through. A pointer to this variable is used
// with this function. Doing things this way permits inlining a // as a marker for the functions on the defer stack associated with
// this function. A function-specific variable permits inlining a
// function which uses defer. // function which uses defer.
Expression* Expression*
Function::defer_stack(source_location location) Function::defer_stack(source_location location)
{ {
Type* t = Type::make_pointer_type(Type::make_void_type());
if (this->defer_stack_ == NULL) if (this->defer_stack_ == NULL)
{ {
Expression* n = Expression::make_nil(location); Type* t = Type::lookup_bool_type();
Expression* n = Expression::make_boolean(false, location);
this->defer_stack_ = Statement::make_temporary(t, n, location); this->defer_stack_ = Statement::make_temporary(t, n, location);
this->defer_stack_->set_is_address_taken(); this->defer_stack_->set_is_address_taken();
} }
Expression* ref = Expression::make_temporary_reference(this->defer_stack_, Expression* ref = Expression::make_temporary_reference(this->defer_stack_,
location); location);
Expression* addr = Expression::make_unary(OPERATOR_AND, ref, location); return Expression::make_unary(OPERATOR_AND, ref, location);
return Expression::make_unsafe_cast(t, addr, location);
} }
// Export the function. // Export the function.
......
...@@ -165,10 +165,10 @@ DEF_GO_RUNTIME(SET_DEFER_RETADDR, "__go_set_defer_retaddr", P1(POINTER), ...@@ -165,10 +165,10 @@ DEF_GO_RUNTIME(SET_DEFER_RETADDR, "__go_set_defer_retaddr", P1(POINTER),
R1(BOOL)) R1(BOOL))
// Check for a deferred function in an exception handler. // Check for a deferred function in an exception handler.
DEF_GO_RUNTIME(CHECK_DEFER, "__go_check_defer", P1(POINTER), R0()) DEF_GO_RUNTIME(CHECK_DEFER, "__go_check_defer", P1(BOOLPTR), R0())
// Run deferred functions. // Run deferred functions.
DEF_GO_RUNTIME(UNDEFER, "__go_undefer", P1(POINTER), R0()) DEF_GO_RUNTIME(UNDEFER, "__go_undefer", P1(BOOLPTR), R0())
// Panic with a runtime error. // Panic with a runtime error.
DEF_GO_RUNTIME(RUNTIME_ERROR, "__go_runtime_error", P1(INT), R0()) DEF_GO_RUNTIME(RUNTIME_ERROR, "__go_runtime_error", P1(INT), R0())
...@@ -207,7 +207,7 @@ DEF_GO_RUNTIME(GO, "__go_go", P2(FUNC_PTR, POINTER), R0()) ...@@ -207,7 +207,7 @@ DEF_GO_RUNTIME(GO, "__go_go", P2(FUNC_PTR, POINTER), R0())
// Defer a function. // Defer a function.
DEF_GO_RUNTIME(DEFER, "__go_defer", P3(POINTER, FUNC_PTR, POINTER), R0()) DEF_GO_RUNTIME(DEFER, "__go_defer", P3(BOOLPTR, FUNC_PTR, POINTER), R0())
// Run a select statement. // Run a select statement.
......
...@@ -2539,11 +2539,10 @@ Return_statement::do_traverse_assignments(Traverse_assignments* tassign) ...@@ -2539,11 +2539,10 @@ Return_statement::do_traverse_assignments(Traverse_assignments* tassign)
// Lower a return statement. If we are returning a function call // Lower a return statement. If we are returning a function call
// which returns multiple values which match the current function, // which returns multiple values which match the current function,
// split up the call's results. If the function has named result // split up the call's results. If the return statement lists
// variables, and the return statement lists explicit values, then // explicit values, implement this statement by assigning the values
// implement it by assigning the values to the result variables and // to the result variables and change this statement to a naked
// changing the statement to not list any values. This lets // return. This lets panic/recover work correctly.
// panic/recover work correctly.
Statement* Statement*
Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing, Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing,
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
/* This function is called each time we need to defer a call. */ /* This function is called each time we need to defer a call. */
void void
__go_defer (void *frame, void (*pfn) (void *), void *arg) __go_defer (_Bool *frame, void (*pfn) (void *), void *arg)
{ {
struct __go_defer_stack *n; struct __go_defer_stack *n;
...@@ -34,7 +34,7 @@ __go_defer (void *frame, void (*pfn) (void *), void *arg) ...@@ -34,7 +34,7 @@ __go_defer (void *frame, void (*pfn) (void *), void *arg)
/* This function is called when we want to undefer the stack. */ /* This function is called when we want to undefer the stack. */
void void
__go_undefer (void *frame) __go_undefer (_Bool *frame)
{ {
if (__go_panic_defer == NULL) if (__go_panic_defer == NULL)
return; return;
...@@ -53,6 +53,12 @@ __go_undefer (void *frame) ...@@ -53,6 +53,12 @@ __go_undefer (void *frame)
__go_panic_defer->__defer = d->__next; __go_panic_defer->__defer = d->__next;
__go_free (d); __go_free (d);
/* Since we are executing a defer function here, we know we are
returning from the calling function. If the calling
function, or one of its callees, paniced, then the defer
functions would be executed by __go_panic. */
*frame = 1;
} }
} }
......
...@@ -13,9 +13,10 @@ struct __go_defer_stack ...@@ -13,9 +13,10 @@ struct __go_defer_stack
/* The next entry in the stack. */ /* The next entry in the stack. */
struct __go_defer_stack *__next; struct __go_defer_stack *__next;
/* The frame pointer for the function which called this defer /* The stack variable for the function which called this defer
statement. */ statement. This is set to 1 if we are returning from that
void *__frame; function, 0 if we are panicing through it. */
_Bool *__frame;
/* The value of the panic stack when this function is deferred. /* The value of the panic stack when this function is deferred.
This function can not recover this value from the panic stack. This function can not recover this value from the panic stack.
......
...@@ -87,6 +87,12 @@ __go_panic (struct __go_empty_interface arg) ...@@ -87,6 +87,12 @@ __go_panic (struct __go_empty_interface arg)
/* __go_unwind_stack should not return. */ /* __go_unwind_stack should not return. */
abort (); abort ();
} }
/* Because we executed that defer function by a panic, and
it did not call recover, we know that we are not
returning from the calling function--we are panicing
through it. */
*d->__frame = 0;
} }
__go_panic_defer->__defer = d->__next; __go_panic_defer->__defer = d->__next;
......
...@@ -44,7 +44,7 @@ static const _Unwind_Exception_Class __go_exception_class = ...@@ -44,7 +44,7 @@ static const _Unwind_Exception_Class __go_exception_class =
continue unwinding. */ continue unwinding. */
void void
__go_check_defer (void *frame) __go_check_defer (_Bool *frame)
{ {
struct _Unwind_Exception *hdr; struct _Unwind_Exception *hdr;
...@@ -103,8 +103,12 @@ __go_check_defer (void *frame) ...@@ -103,8 +103,12 @@ __go_check_defer (void *frame)
if (was_recovered) if (was_recovered)
{ {
/* Just return and continue executing Go code. */ /* Just return and continue executing Go code. */
*frame = 1;
return; return;
} }
/* We are panicing through this function. */
*frame = 0;
} }
else if (__go_panic_defer->__defer != NULL else if (__go_panic_defer->__defer != NULL
&& __go_panic_defer->__defer->__pfn == NULL && __go_panic_defer->__defer->__pfn == NULL
...@@ -118,6 +122,10 @@ __go_check_defer (void *frame) ...@@ -118,6 +122,10 @@ __go_check_defer (void *frame)
d = __go_panic_defer->__defer; d = __go_panic_defer->__defer;
__go_panic_defer->__defer = d->__next; __go_panic_defer->__defer = d->__next;
__go_free (d); __go_free (d);
/* We are returning from this function. */
*frame = 1;
return; return;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment