Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 249487) +++ gcc/go/gofrontend/MERGE (working copy) @@ -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: gcc/go/gofrontend/gogo.h =================================================================== --- gcc/go/gofrontend/gogo.h (revision 249205) +++ gcc/go/gofrontend/gogo.h (working copy) @@ -3379,6 +3379,9 @@ static const int RUNTIME_ERROR_MAKE_CHAN // 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: gcc/go/gofrontend/statements.cc =================================================================== --- gcc/go/gofrontend/statements.cc (revision 249205) +++ gcc/go/gofrontend/statements.cc (working copy) @@ -2201,6 +2201,15 @@ Thunk_statement::simplify_statement(Gogo 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 // 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 // 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 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: libgo/runtime/go-runtime-error.c =================================================================== --- libgo/runtime/go-runtime-error.c (revision 249205) +++ libgo/runtime/go-runtime-error.c (working copy) @@ -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"); }