summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2017-06-22 04:13:36 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2017-06-22 04:13:36 +0000
commit789c8746707c870f6d3aa4e33f81e362914a398c (patch)
treeb318ec0d3a71e91a29241ff9dbe39c796b084a0a
parent0a54e2a6031f4ada89dfc7c9696afcabace2d2f4 (diff)
downloadgcc-789c8746707c870f6d3aa4e33f81e362914a398c.tar.gz
compiler, runtime: better stack trace for `go f()` where f is nil
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 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@249494 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/gogo.h3
-rw-r--r--gcc/go/gofrontend/statements.cc30
-rw-r--r--libgo/runtime/go-runtime-error.c11
4 files changed, 42 insertions, 4 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 96cf627eff3..9a23eb98b98 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -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.
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index c3e3f30131d..a04a1a36ee3 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -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();
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index 7a448d7a606..e5921767286 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -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.
diff --git a/libgo/runtime/go-runtime-error.c b/libgo/runtime/go-runtime-error.c
index f5ab4f9196b..4f563fc9ed5 100644
--- a/libgo/runtime/go-runtime-error.c
+++ b/libgo/runtime/go-runtime-error.c
@@ -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");
}