diff options
-rw-r--r-- | gcc/go/gofrontend/gogo-tree.cc | 18 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 18 | ||||
-rw-r--r-- | gcc/go/gofrontend/runtime.def | 6 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 9 | ||||
-rw-r--r-- | libgo/runtime/go-defer.c | 10 | ||||
-rw-r--r-- | libgo/runtime/go-defer.h | 7 | ||||
-rw-r--r-- | libgo/runtime/go-panic.c | 6 | ||||
-rw-r--r-- | libgo/runtime/go-unwind.c | 10 |
8 files changed, 57 insertions, 27 deletions
diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc index fbddc0492f6..49a0ba40bbd 100644 --- a/gcc/go/gofrontend/gogo-tree.cc +++ b/gcc/go/gofrontend/gogo-tree.cc @@ -1592,15 +1592,25 @@ Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function, && !this->type_->results()->empty() && !this->type_->results()->front().name().empty()) { - // If the result variables are named, we need to return them - // again, because they might have been changed by a defer - // function. + // If the result variables are named, and we are returning from + // this function rather than panicing through it, we need to + // 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, &stmt_list); set = fold_build2_loc(end_loc, MODIFY_EXPR, void_type_node, DECL_RESULT(this->fndecl_), retval); 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); diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index c544eba8d2f..4a89ca80ba5 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -2976,27 +2976,27 @@ Function::determine_types() this->block_->determine_types(); } -// Get a pointer to the variable holding the defer stack for this -// function, making it if necessary. At least at present, the value -// of this variable is not used. However, a pointer to this variable -// is used as a marker for the functions on the defer stack associated -// with this function. Doing things this way permits inlining a +// Get a pointer to the variable representing the defer stack for this +// function, making it if necessary. The value of the variable is set +// by the runtime routines to true if the function is returning, +// rather than panicing through. A pointer to this variable is used +// 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. Expression* Function::defer_stack(source_location location) { - Type* t = Type::make_pointer_type(Type::make_void_type()); 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_->set_is_address_taken(); } Expression* ref = Expression::make_temporary_reference(this->defer_stack_, location); - Expression* addr = Expression::make_unary(OPERATOR_AND, ref, location); - return Expression::make_unsafe_cast(t, addr, location); + return Expression::make_unary(OPERATOR_AND, ref, location); } // Export the function. diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index 219ccb8bd90..a7828edeb2e 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -165,10 +165,10 @@ DEF_GO_RUNTIME(SET_DEFER_RETADDR, "__go_set_defer_retaddr", P1(POINTER), R1(BOOL)) // 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. -DEF_GO_RUNTIME(UNDEFER, "__go_undefer", P1(POINTER), R0()) +DEF_GO_RUNTIME(UNDEFER, "__go_undefer", P1(BOOLPTR), R0()) // Panic with a runtime error. 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. -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. diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index bb43dcdee43..82be1129028 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -2539,11 +2539,10 @@ Return_statement::do_traverse_assignments(Traverse_assignments* tassign) // Lower a return statement. If we are returning a function call // which returns multiple values which match the current function, -// split up the call's results. If the function has named result -// variables, and the return statement lists explicit values, then -// implement it by assigning the values to the result variables and -// changing the statement to not list any values. This lets -// panic/recover work correctly. +// split up the call's results. If the return statement lists +// explicit values, implement this statement by assigning the values +// to the result variables and change this statement to a naked +// return. This lets panic/recover work correctly. Statement* Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing, diff --git a/libgo/runtime/go-defer.c b/libgo/runtime/go-defer.c index 6425f0586a7..1f116eb38c9 100644 --- a/libgo/runtime/go-defer.c +++ b/libgo/runtime/go-defer.c @@ -13,7 +13,7 @@ /* This function is called each time we need to defer a call. */ void -__go_defer (void *frame, void (*pfn) (void *), void *arg) +__go_defer (_Bool *frame, void (*pfn) (void *), void *arg) { 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. */ void -__go_undefer (void *frame) +__go_undefer (_Bool *frame) { if (__go_panic_defer == NULL) return; @@ -53,6 +53,12 @@ __go_undefer (void *frame) __go_panic_defer->__defer = d->__next; __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; } } diff --git a/libgo/runtime/go-defer.h b/libgo/runtime/go-defer.h index f8924f3b63a..0b20e8f6e78 100644 --- a/libgo/runtime/go-defer.h +++ b/libgo/runtime/go-defer.h @@ -13,9 +13,10 @@ struct __go_defer_stack /* The next entry in the stack. */ struct __go_defer_stack *__next; - /* The frame pointer for the function which called this defer - statement. */ - void *__frame; + /* The stack variable for the function which called this defer + statement. This is set to 1 if we are returning from that + function, 0 if we are panicing through it. */ + _Bool *__frame; /* The value of the panic stack when this function is deferred. This function can not recover this value from the panic stack. diff --git a/libgo/runtime/go-panic.c b/libgo/runtime/go-panic.c index b684779cda8..c39ea9f9303 100644 --- a/libgo/runtime/go-panic.c +++ b/libgo/runtime/go-panic.c @@ -87,6 +87,12 @@ __go_panic (struct __go_empty_interface arg) /* __go_unwind_stack should not return. */ 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; diff --git a/libgo/runtime/go-unwind.c b/libgo/runtime/go-unwind.c index 0bc3f1b4e65..e64cf903d9f 100644 --- a/libgo/runtime/go-unwind.c +++ b/libgo/runtime/go-unwind.c @@ -44,7 +44,7 @@ static const _Unwind_Exception_Class __go_exception_class = continue unwinding. */ void -__go_check_defer (void *frame) +__go_check_defer (_Bool *frame) { struct _Unwind_Exception *hdr; @@ -103,8 +103,12 @@ __go_check_defer (void *frame) if (was_recovered) { /* Just return and continue executing Go code. */ + *frame = 1; return; } + + /* We are panicing through this function. */ + *frame = 0; } else if (__go_panic_defer->__defer != NULL && __go_panic_defer->__defer->__pfn == NULL @@ -118,6 +122,10 @@ __go_check_defer (void *frame) d = __go_panic_defer->__defer; __go_panic_defer->__defer = d->__next; __go_free (d); + + /* We are returning from this function. */ + *frame = 1; + return; } |