summaryrefslogtreecommitdiff
path: root/gcc/go/gofrontend/gogo-tree.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/go/gofrontend/gogo-tree.cc')
-rw-r--r--gcc/go/gofrontend/gogo-tree.cc18
1 files changed, 14 insertions, 4 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);