compiler: traverse func subexprs when creating func descriptors
Fix the Create_func_descriptors pass to traverse the subexpressions of the function in a Call_expression. There are no subexpressions in the normal case of calling a function a method directly, but there are subexpressions when in code like F().M() when F returns an interface type. Forgetting to traverse the function subexpressions was almost entirely hidden by the fact that we also created the necessary thunks in Bound_method_expression::do_flatten and Interface_field_reference_expression::do_get_backend. However, when the thunks were created there, they did not go through the order_evaluations pass. This almost always worked, but failed in the case in which the function being thunked returned multiple results, as order_evaluations takes the necessary step of moving the Call_expression into its own statement, and that would not happen when order_evaluations was not called. Avoid hiding errors like this by changing those methods to only lookup the previously created thunk, rather than creating it if it was not already created. The test case for this is https://golang.org/cl/363156. Fixes https://golang.org/issue/49512 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/363274
This commit is contained in:
parent
083fd73202
commit
7846156274
|
@ -1,4 +1,4 @@
|
||||||
128ea3dce9b8753167f33d0a96bd093a6cbd58b8
|
3e9f4ee16683883ccfb8661d99318c74bb7a4bef
|
||||||
|
|
||||||
The first line of this file holds the git revision number of the last
|
The first line of this file holds the git revision number of the last
|
||||||
merge done from the gofrontend repository.
|
merge done from the gofrontend repository.
|
||||||
|
|
|
@ -7981,7 +7981,7 @@ Bound_method_expression::do_check_types(Gogo*)
|
||||||
Bound_method_expression::Method_value_thunks
|
Bound_method_expression::Method_value_thunks
|
||||||
Bound_method_expression::method_value_thunks;
|
Bound_method_expression::method_value_thunks;
|
||||||
|
|
||||||
// Find or create the thunk for METHOD.
|
// Find or create the thunk for FN.
|
||||||
|
|
||||||
Named_object*
|
Named_object*
|
||||||
Bound_method_expression::create_thunk(Gogo* gogo, const Method* method,
|
Bound_method_expression::create_thunk(Gogo* gogo, const Method* method,
|
||||||
|
@ -8078,14 +8078,28 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method,
|
||||||
gogo->add_statement(s);
|
gogo->add_statement(s);
|
||||||
Block* b = gogo->finish_block(loc);
|
Block* b = gogo->finish_block(loc);
|
||||||
gogo->add_block(b, loc);
|
gogo->add_block(b, loc);
|
||||||
|
|
||||||
|
// This is called after lowering but before determine_types.
|
||||||
gogo->lower_block(new_no, b);
|
gogo->lower_block(new_no, b);
|
||||||
gogo->flatten_block(new_no, b);
|
|
||||||
gogo->finish_function(loc);
|
gogo->finish_function(loc);
|
||||||
|
|
||||||
ins.first->second = new_no;
|
ins.first->second = new_no;
|
||||||
return new_no;
|
return new_no;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Look up a thunk for FN.
|
||||||
|
|
||||||
|
Named_object*
|
||||||
|
Bound_method_expression::lookup_thunk(Named_object* fn)
|
||||||
|
{
|
||||||
|
Method_value_thunks::const_iterator p =
|
||||||
|
Bound_method_expression::method_value_thunks.find(fn);
|
||||||
|
if (p == Bound_method_expression::method_value_thunks.end())
|
||||||
|
return NULL;
|
||||||
|
return p->second;
|
||||||
|
}
|
||||||
|
|
||||||
// Return an expression to check *REF for nil while dereferencing
|
// Return an expression to check *REF for nil while dereferencing
|
||||||
// according to FIELD_INDEXES. Update *REF to build up the field
|
// according to FIELD_INDEXES. Update *REF to build up the field
|
||||||
// reference. This is a static function so that we don't have to
|
// reference. This is a static function so that we don't have to
|
||||||
|
@ -8129,10 +8143,11 @@ Bound_method_expression::do_flatten(Gogo* gogo, Named_object*,
|
||||||
{
|
{
|
||||||
Location loc = this->location();
|
Location loc = this->location();
|
||||||
|
|
||||||
Named_object* thunk = Bound_method_expression::create_thunk(gogo,
|
Named_object* thunk = Bound_method_expression::lookup_thunk(this->function_);
|
||||||
this->method_,
|
|
||||||
this->function_);
|
// The thunk should have been created during the
|
||||||
if (thunk->is_erroneous())
|
// create_function_descriptors pass.
|
||||||
|
if (thunk == NULL || thunk->is_erroneous())
|
||||||
{
|
{
|
||||||
go_assert(saw_errors());
|
go_assert(saw_errors());
|
||||||
return Expression::make_error(loc);
|
return Expression::make_error(loc);
|
||||||
|
@ -14757,14 +14772,34 @@ Interface_field_reference_expression::create_thunk(Gogo* gogo,
|
||||||
gogo->add_statement(s);
|
gogo->add_statement(s);
|
||||||
Block* b = gogo->finish_block(loc);
|
Block* b = gogo->finish_block(loc);
|
||||||
gogo->add_block(b, loc);
|
gogo->add_block(b, loc);
|
||||||
|
|
||||||
|
// This is called after lowering but before determine_types.
|
||||||
gogo->lower_block(new_no, b);
|
gogo->lower_block(new_no, b);
|
||||||
gogo->flatten_block(new_no, b);
|
|
||||||
gogo->finish_function(loc);
|
gogo->finish_function(loc);
|
||||||
|
|
||||||
ins.first->second->push_back(std::make_pair(name, new_no));
|
ins.first->second->push_back(std::make_pair(name, new_no));
|
||||||
return new_no;
|
return new_no;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lookup a thunk to call method NAME on TYPE.
|
||||||
|
|
||||||
|
Named_object*
|
||||||
|
Interface_field_reference_expression::lookup_thunk(Interface_type* type,
|
||||||
|
const std::string& name)
|
||||||
|
{
|
||||||
|
Interface_method_thunks::const_iterator p =
|
||||||
|
Interface_field_reference_expression::interface_method_thunks.find(type);
|
||||||
|
if (p == Interface_field_reference_expression::interface_method_thunks.end())
|
||||||
|
return NULL;
|
||||||
|
for (Method_thunks::const_iterator pm = p->second->begin();
|
||||||
|
pm != p->second->end();
|
||||||
|
++pm)
|
||||||
|
if (pm->first == name)
|
||||||
|
return pm->second;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the backend representation for a method value.
|
// Get the backend representation for a method value.
|
||||||
|
|
||||||
Bexpression*
|
Bexpression*
|
||||||
|
@ -14778,9 +14813,11 @@ Interface_field_reference_expression::do_get_backend(Translate_context* context)
|
||||||
}
|
}
|
||||||
|
|
||||||
Named_object* thunk =
|
Named_object* thunk =
|
||||||
Interface_field_reference_expression::create_thunk(context->gogo(),
|
Interface_field_reference_expression::lookup_thunk(type, this->name_);
|
||||||
type, this->name_);
|
|
||||||
if (thunk->is_erroneous())
|
// The thunk should have been created during the
|
||||||
|
// create_function_descriptors pass.
|
||||||
|
if (thunk == NULL || thunk->is_erroneous())
|
||||||
{
|
{
|
||||||
go_assert(saw_errors());
|
go_assert(saw_errors());
|
||||||
return context->backend()->error_expression();
|
return context->backend()->error_expression();
|
||||||
|
|
|
@ -3405,6 +3405,10 @@ class Bound_method_expression : public Expression
|
||||||
static Named_object*
|
static Named_object*
|
||||||
create_thunk(Gogo*, const Method* method, Named_object* function);
|
create_thunk(Gogo*, const Method* method, Named_object* function);
|
||||||
|
|
||||||
|
// Look up a thunk.
|
||||||
|
static Named_object*
|
||||||
|
lookup_thunk(Named_object* function);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int
|
int
|
||||||
do_traverse(Traverse*);
|
do_traverse(Traverse*);
|
||||||
|
@ -3578,6 +3582,10 @@ class Interface_field_reference_expression : public Expression
|
||||||
static Named_object*
|
static Named_object*
|
||||||
create_thunk(Gogo*, Interface_type* type, const std::string& name);
|
create_thunk(Gogo*, Interface_type* type, const std::string& name);
|
||||||
|
|
||||||
|
// Look up a thunk.
|
||||||
|
static Named_object*
|
||||||
|
lookup_thunk(Interface_type* type, const std::string& name);
|
||||||
|
|
||||||
// Return an expression for the pointer to the function to call.
|
// Return an expression for the pointer to the function to call.
|
||||||
Expression*
|
Expression*
|
||||||
get_function();
|
get_function();
|
||||||
|
|
|
@ -3430,6 +3430,11 @@ Create_function_descriptors::expression(Expression** pexpr)
|
||||||
if (args->traverse(this) == TRAVERSE_EXIT)
|
if (args->traverse(this) == TRAVERSE_EXIT)
|
||||||
return TRAVERSE_EXIT;
|
return TRAVERSE_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Traverse the subexpressions of the function, if any.
|
||||||
|
if (fn->traverse_subexpressions(this) == TRAVERSE_EXIT)
|
||||||
|
return TRAVERSE_EXIT;
|
||||||
|
|
||||||
return TRAVERSE_SKIP_COMPONENTS;
|
return TRAVERSE_SKIP_COMPONENTS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue