OSDN Git Service

Fix defer when not calling recover in function with named results.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 16 Sep 2011 05:47:20 +0000 (05:47 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 16 Sep 2011 05:47:20 +0000 (05:47 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@178905 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/go/gofrontend/gogo-tree.cc
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/runtime.def
gcc/go/gofrontend/statements.cc
libgo/runtime/go-defer.c
libgo/runtime/go-defer.h
libgo/runtime/go-panic.c
libgo/runtime/go-unwind.c

index fbddc04..49a0ba4 100644 (file)
@@ -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);
index c544eba..4a89ca8 100644 (file)
@@ -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.
index 219ccb8..a7828ed 100644 (file)
@@ -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.
index bb43dcd..82be112 100644 (file)
@@ -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,
index 6425f05..1f116eb 100644 (file)
@@ -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;
     }
 }
 
index f8924f3..0b20e8f 100644 (file)
@@ -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.
index b684779..c39ea9f 100644 (file)
@@ -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;
index 0bc3f1b..e64cf90 100644 (file)
@@ -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;
     }