compiler, runtime: better stack trace for `go f()` where f is nil
authorIan Lance Taylor <ian@gcc.gnu.org>
Thu, 22 Jun 2017 04:13:36 +0000 (04:13 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Thu, 22 Jun 2017 04:13:36 +0000 (04:13 +0000)
    The test for this is TestGoNil in the runtime package, which we don't
    run yet but will run with a subsequent gotools patch.

    Updates golang/go#8045

    Reviewed-on: https://go-review.googlesource.com/46392

From-SVN: r249494

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/statements.cc
libgo/runtime/go-runtime-error.c

index 96cf627eff34f74dbc6e08bbd24c51525a210389..9a23eb98b98ec140e34af414a7df7efb20922f72 100644 (file)
@@ -1,4 +1,4 @@
-dac4bb4f4ed8e7f2939d45439048dec2f6db14cf
+075e67bdbcb730669c1af1aa2d53bb77cbb2a3c5
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index c3e3f30131de73b8c8ad22488aedfb783147cbd9..a04a1a36ee31ef07b861cd3b887f7e0c2e180550 100644 (file)
@@ -3379,6 +3379,9 @@ static const int RUNTIME_ERROR_MAKE_CHAN_OUT_OF_BOUNDS = 9;
 // Division by zero.
 static const int RUNTIME_ERROR_DIVISION_BY_ZERO = 10;
 
+// Go statement with nil function.
+static const int RUNTIME_ERROR_GO_NIL = 11;
+
 // This is used by some of the langhooks.
 extern Gogo* go_get_gogo();
 
index 7a448d7a60601cbde8c35835cc4634fc546104d6..e59217672866ce70b9501c71d6a7debe158eeb40 100644 (file)
@@ -2201,6 +2201,15 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
 
   Location location = this->location();
 
+  bool is_constant_function = this->is_constant_function();
+  Temporary_statement* fn_temp = NULL;
+  if (!is_constant_function)
+    {
+      fn_temp = Statement::make_temporary(NULL, fn, location);
+      block->insert_statement_before(block->statements()->size() - 1, fn_temp);
+      fn = Expression::make_temporary_reference(fn_temp, location);
+    }
+
   std::string thunk_name = Gogo::thunk_name();
 
   // Build the thunk.
@@ -2212,7 +2221,7 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
   // argument to the thunk.
 
   Expression_list* vals = new Expression_list();
-  if (!this->is_constant_function())
+  if (!is_constant_function)
     vals->push_back(fn);
 
   if (interface_method != NULL)
@@ -2238,6 +2247,23 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
   // Allocate the initialized struct on the heap.
   constructor = Expression::make_heap_expression(constructor, location);
 
+  // Throw an error if the function is nil.  This is so that for `go
+  // nil` we get a backtrace from the go statement, rather than a
+  // useless backtrace from the brand new goroutine.
+  Expression* param = constructor;
+  if (!is_constant_function)
+    {
+      fn = Expression::make_temporary_reference(fn_temp, location);
+      Expression* nil = Expression::make_nil(location);
+      Expression* isnil = Expression::make_binary(OPERATOR_EQEQ, fn, nil,
+                                                 location);
+      Expression* crash = gogo->runtime_error(RUNTIME_ERROR_GO_NIL, location);
+      crash = Expression::make_conditional(isnil, crash,
+                                          Expression::make_nil(location),
+                                          location);
+      param = Expression::make_compound(crash, constructor, location);
+    }
+
   // Look up the thunk.
   Named_object* named_thunk = gogo->lookup(thunk_name, NULL);
   go_assert(named_thunk != NULL && named_thunk->is_function());
@@ -2246,7 +2272,7 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
   Expression* func = Expression::make_func_reference(named_thunk, NULL,
                                                     location);
   Expression_list* params = new Expression_list();
-  params->push_back(constructor);
+  params->push_back(param);
   Call_expression* call = Expression::make_call(func, params, false, location);
 
   // Build the simple go or defer statement.
index f5ab4f9196bbabc670bd7190423b49ceaee5fa89..4f563fc9ed5e37e8b1a059ac8d33dc7e63a54c4d 100644 (file)
@@ -49,7 +49,10 @@ enum
   MAKE_CHAN_OUT_OF_BOUNDS = 9,
 
   /* Integer division by zero.  */
-  DIVISION_BY_ZERO = 10
+  DIVISION_BY_ZERO = 10,
+
+  /* Go statement with nil function.  */
+  GO_NIL = 11
 };
 
 extern void __go_runtime_error () __attribute__ ((noreturn));
@@ -84,6 +87,12 @@ __go_runtime_error (int32 i)
     case DIVISION_BY_ZERO:
       runtime_panicstring ("integer divide by zero");
 
+    case GO_NIL:
+      /* This one is a throw, rather than a panic.  Set throwing to
+        not dump full stacks.  */
+      runtime_g()->m->throwing = -1;
+      runtime_throw ("go of nil func value");
+
     default:
       runtime_panicstring ("unknown runtime error");
     }