From: Ian Lance Taylor Date: Thu, 22 Jun 2017 04:13:36 +0000 (+0000) Subject: compiler, runtime: better stack trace for `go f()` where f is nil X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=55ea0ea07dc837e596f81ce972361ec46d2cb1fe;p=gcc.git 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 From-SVN: r249494 --- 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"); }