mirror of git://gcc.gnu.org/git/gcc.git
Fix defer when not calling recover in function with named results.
From-SVN: r178905
This commit is contained in:
parent
fae3f4598a
commit
b9f04a8461
|
|
@ -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()
|
||||||
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),
|
||||||
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())
|
||||||
|
|
||||||
|
|
||||||
// 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)
|
||||||
|
|
||||||
// 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 @@
|
||||||
/* 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)
|
||||||
/* 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)
|
||||||
|
|
||||||
__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
|
||||||
/* 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)
|
||||||
/* __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 =
|
||||||
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)
|
||||||
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)
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue