diff options
author | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2017-06-22 04:13:36 +0000 |
---|---|---|
committer | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2017-06-22 04:13:36 +0000 |
commit | 789c8746707c870f6d3aa4e33f81e362914a398c (patch) | |
tree | b318ec0d3a71e91a29241ff9dbe39c796b084a0a | |
parent | 0a54e2a6031f4ada89dfc7c9696afcabace2d2f4 (diff) | |
download | gcc-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/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 3 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 30 | ||||
-rw-r--r-- | libgo/runtime/go-runtime-error.c | 11 |
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"); } |