mirror of git://gcc.gnu.org/git/gcc.git
Use temporary variables for calls with multiple results.
From-SVN: r176998
This commit is contained in:
parent
c469244ec0
commit
8586635cd8
|
@ -926,7 +926,8 @@ Parser_expression::do_type()
|
||||||
// if necessary.
|
// if necessary.
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
Var_expression::do_lower(Gogo* gogo, Named_object* function, int)
|
Var_expression::do_lower(Gogo* gogo, Named_object* function,
|
||||||
|
Statement_inserter* inserter, int)
|
||||||
{
|
{
|
||||||
if (this->variable_->is_variable())
|
if (this->variable_->is_variable())
|
||||||
{
|
{
|
||||||
|
@ -935,8 +936,11 @@ Var_expression::do_lower(Gogo* gogo, Named_object* function, int)
|
||||||
// reference to a variable which is local to an enclosing
|
// reference to a variable which is local to an enclosing
|
||||||
// function will be a reference to a field in a closure.
|
// function will be a reference to a field in a closure.
|
||||||
if (var->is_global())
|
if (var->is_global())
|
||||||
|
{
|
||||||
function = NULL;
|
function = NULL;
|
||||||
var->lower_init_expression(gogo, function);
|
inserter = NULL;
|
||||||
|
}
|
||||||
|
var->lower_init_expression(gogo, function, inserter);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -1061,7 +1065,9 @@ Temporary_reference_expression::do_get_tree(Translate_context* context)
|
||||||
// that here by adding a type cast. We need to use base() to push
|
// that here by adding a type cast. We need to use base() to push
|
||||||
// the circularity down one level.
|
// the circularity down one level.
|
||||||
tree ret = var_to_tree(bvar);
|
tree ret = var_to_tree(bvar);
|
||||||
if (POINTER_TYPE_P(TREE_TYPE(ret)) && VOID_TYPE_P(TREE_TYPE(TREE_TYPE(ret))))
|
if (!this->is_lvalue_
|
||||||
|
&& POINTER_TYPE_P(TREE_TYPE(ret))
|
||||||
|
&& VOID_TYPE_P(TREE_TYPE(TREE_TYPE(ret))))
|
||||||
{
|
{
|
||||||
Btype* type_btype = this->type()->base()->get_backend(context->gogo());
|
Btype* type_btype = this->type()->base()->get_backend(context->gogo());
|
||||||
tree type_tree = type_to_tree(type_btype);
|
tree type_tree = type_to_tree(type_btype);
|
||||||
|
@ -1072,7 +1078,7 @@ Temporary_reference_expression::do_get_tree(Translate_context* context)
|
||||||
|
|
||||||
// Make a reference to a temporary variable.
|
// Make a reference to a temporary variable.
|
||||||
|
|
||||||
Expression*
|
Temporary_reference_expression*
|
||||||
Expression::make_temporary_reference(Temporary_statement* statement,
|
Expression::make_temporary_reference(Temporary_statement* statement,
|
||||||
source_location location)
|
source_location location)
|
||||||
{
|
{
|
||||||
|
@ -1302,7 +1308,7 @@ Unknown_expression::name() const
|
||||||
// Lower a reference to an unknown name.
|
// Lower a reference to an unknown name.
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
Unknown_expression::do_lower(Gogo*, Named_object*, int)
|
Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
|
||||||
{
|
{
|
||||||
source_location location = this->location();
|
source_location location = this->location();
|
||||||
Named_object* no = this->named_object_;
|
Named_object* no = this->named_object_;
|
||||||
|
@ -2394,7 +2400,7 @@ class Const_expression : public Expression
|
||||||
do_traverse(Traverse*);
|
do_traverse(Traverse*);
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
do_lower(Gogo*, Named_object*, int);
|
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
do_is_constant() const
|
do_is_constant() const
|
||||||
|
@ -2462,7 +2468,8 @@ Const_expression::do_traverse(Traverse* traverse)
|
||||||
// predeclared constant iota into an integer value.
|
// predeclared constant iota into an integer value.
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
Const_expression::do_lower(Gogo* gogo, Named_object*, int iota_value)
|
Const_expression::do_lower(Gogo* gogo, Named_object*,
|
||||||
|
Statement_inserter*, int iota_value)
|
||||||
{
|
{
|
||||||
if (this->constant_->const_value()->expr()->classification()
|
if (this->constant_->const_value()->expr()->classification()
|
||||||
== EXPRESSION_IOTA)
|
== EXPRESSION_IOTA)
|
||||||
|
@ -2931,7 +2938,7 @@ class Iota_expression : public Parser_expression
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Expression*
|
Expression*
|
||||||
do_lower(Gogo*, Named_object*, int)
|
do_lower(Gogo*, Named_object*, Statement_inserter*, int)
|
||||||
{ go_unreachable(); }
|
{ go_unreachable(); }
|
||||||
|
|
||||||
// There should only ever be one of these.
|
// There should only ever be one of these.
|
||||||
|
@ -2988,7 +2995,7 @@ class Type_conversion_expression : public Expression
|
||||||
do_traverse(Traverse* traverse);
|
do_traverse(Traverse* traverse);
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
do_lower(Gogo*, Named_object*, int);
|
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
do_is_constant() const
|
do_is_constant() const
|
||||||
|
@ -3057,7 +3064,8 @@ Type_conversion_expression::do_traverse(Traverse* traverse)
|
||||||
// Convert to a constant at lowering time.
|
// Convert to a constant at lowering time.
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
Type_conversion_expression::do_lower(Gogo*, Named_object*, int)
|
Type_conversion_expression::do_lower(Gogo*, Named_object*,
|
||||||
|
Statement_inserter*, int)
|
||||||
{
|
{
|
||||||
Type* type = this->type_;
|
Type* type = this->type_;
|
||||||
Expression* val = this->expr_;
|
Expression* val = this->expr_;
|
||||||
|
@ -3753,7 +3761,7 @@ class Unary_expression : public Expression
|
||||||
{ return Expression::traverse(&this->expr_, traverse); }
|
{ return Expression::traverse(&this->expr_, traverse); }
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
do_lower(Gogo*, Named_object*, int);
|
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
do_is_constant() const;
|
do_is_constant() const;
|
||||||
|
@ -3808,7 +3816,7 @@ class Unary_expression : public Expression
|
||||||
// instead.
|
// instead.
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
Unary_expression::do_lower(Gogo*, Named_object*, int)
|
Unary_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
|
||||||
{
|
{
|
||||||
source_location loc = this->location();
|
source_location loc = this->location();
|
||||||
Operator op = this->op_;
|
Operator op = this->op_;
|
||||||
|
@ -5137,7 +5145,7 @@ Binary_expression::eval_complex(Operator op, Type* left_type,
|
||||||
// constants.
|
// constants.
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
Binary_expression::do_lower(Gogo*, Named_object*, int)
|
Binary_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
|
||||||
{
|
{
|
||||||
source_location location = this->location();
|
source_location location = this->location();
|
||||||
Operator op = this->op_;
|
Operator op = this->op_;
|
||||||
|
@ -6656,7 +6664,7 @@ class Builtin_call_expression : public Call_expression
|
||||||
protected:
|
protected:
|
||||||
// This overrides Call_expression::do_lower.
|
// This overrides Call_expression::do_lower.
|
||||||
Expression*
|
Expression*
|
||||||
do_lower(Gogo*, Named_object*, int);
|
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
do_is_constant() const;
|
do_is_constant() const;
|
||||||
|
@ -6864,7 +6872,8 @@ Find_call_expression::expression(Expression** pexpr)
|
||||||
// specific expressions. We also convert to a constant if we can.
|
// specific expressions. We also convert to a constant if we can.
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, int)
|
Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
|
||||||
|
Statement_inserter* inserter, int)
|
||||||
{
|
{
|
||||||
if (this->classification() == EXPRESSION_ERROR)
|
if (this->classification() == EXPRESSION_ERROR)
|
||||||
return this;
|
return this;
|
||||||
|
@ -6974,7 +6983,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, int)
|
||||||
this->set_is_error();
|
this->set_is_error();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
return this->lower_varargs(gogo, function, slice_type, 2);
|
return this->lower_varargs(gogo, function, inserter, slice_type, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
@ -8553,9 +8562,10 @@ Call_expression::do_traverse(Traverse* traverse)
|
||||||
// Lower a call statement.
|
// Lower a call statement.
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
Call_expression::do_lower(Gogo* gogo, Named_object* function, int)
|
Call_expression::do_lower(Gogo* gogo, Named_object* function,
|
||||||
|
Statement_inserter* inserter, int)
|
||||||
{
|
{
|
||||||
// A type case can look like a function call.
|
// A type cast can look like a function call.
|
||||||
if (this->fn_->is_type_expression()
|
if (this->fn_->is_type_expression()
|
||||||
&& this->args_ != NULL
|
&& this->args_ != NULL
|
||||||
&& this->args_->size() == 1)
|
&& this->args_->size() == 1)
|
||||||
|
@ -8597,6 +8607,29 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, int)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this call returns multiple results, create a temporary
|
||||||
|
// variable for each result.
|
||||||
|
size_t rc = this->result_count();
|
||||||
|
if (rc > 1 && this->results_ == NULL)
|
||||||
|
{
|
||||||
|
std::vector<Temporary_statement*>* temps =
|
||||||
|
new std::vector<Temporary_statement*>;
|
||||||
|
temps->reserve(rc);
|
||||||
|
const Typed_identifier_list* results =
|
||||||
|
this->fn_->type()->function_type()->results();
|
||||||
|
for (Typed_identifier_list::const_iterator p = results->begin();
|
||||||
|
p != results->end();
|
||||||
|
++p)
|
||||||
|
{
|
||||||
|
Temporary_statement* temp = Statement::make_temporary(p->type(),
|
||||||
|
NULL,
|
||||||
|
p->location());
|
||||||
|
inserter->insert(temp);
|
||||||
|
temps->push_back(temp);
|
||||||
|
}
|
||||||
|
this->results_ = temps;
|
||||||
|
}
|
||||||
|
|
||||||
// Handle a call to a varargs function by packaging up the extra
|
// Handle a call to a varargs function by packaging up the extra
|
||||||
// parameters.
|
// parameters.
|
||||||
if (this->fn_->type()->function_type() != NULL
|
if (this->fn_->type()->function_type() != NULL
|
||||||
|
@ -8606,7 +8639,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, int)
|
||||||
const Typed_identifier_list* parameters = fntype->parameters();
|
const Typed_identifier_list* parameters = fntype->parameters();
|
||||||
go_assert(parameters != NULL && !parameters->empty());
|
go_assert(parameters != NULL && !parameters->empty());
|
||||||
Type* varargs_type = parameters->back().type();
|
Type* varargs_type = parameters->back().type();
|
||||||
return this->lower_varargs(gogo, function, varargs_type,
|
return this->lower_varargs(gogo, function, inserter, varargs_type,
|
||||||
parameters->size());
|
parameters->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8622,6 +8655,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, int)
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
|
Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
|
||||||
|
Statement_inserter* inserter,
|
||||||
Type* varargs_type, size_t param_count)
|
Type* varargs_type, size_t param_count)
|
||||||
{
|
{
|
||||||
if (this->varargs_are_lowered_)
|
if (this->varargs_are_lowered_)
|
||||||
|
@ -8702,13 +8736,12 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
|
||||||
|
|
||||||
// Lower all the new subexpressions.
|
// Lower all the new subexpressions.
|
||||||
Expression* ret = this;
|
Expression* ret = this;
|
||||||
gogo->lower_expression(function, &ret);
|
gogo->lower_expression(function, inserter, &ret);
|
||||||
go_assert(ret == this);
|
go_assert(ret == this);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the function type. Returns NULL if we don't know the type. If
|
// Get the function type. This can return NULL in error cases.
|
||||||
// this returns NULL, and if_ERROR is true, issues an error.
|
|
||||||
|
|
||||||
Function_type*
|
Function_type*
|
||||||
Call_expression::get_function_type() const
|
Call_expression::get_function_type() const
|
||||||
|
@ -8729,6 +8762,16 @@ Call_expression::result_count() const
|
||||||
return fntype->results()->size();
|
return fntype->results()->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the temporary which holds a result.
|
||||||
|
|
||||||
|
Temporary_statement*
|
||||||
|
Call_expression::result(size_t i) const
|
||||||
|
{
|
||||||
|
go_assert(this->results_ != NULL
|
||||||
|
&& this->results_->size() > i);
|
||||||
|
return (*this->results_)[i];
|
||||||
|
}
|
||||||
|
|
||||||
// Return whether this is a call to the predeclared function recover.
|
// Return whether this is a call to the predeclared function recover.
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -8759,6 +8802,21 @@ Call_expression::do_set_recover_arg(Expression*)
|
||||||
go_unreachable();
|
go_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We have found an error with this call expression; return true if
|
||||||
|
// we should report it.
|
||||||
|
|
||||||
|
bool
|
||||||
|
Call_expression::issue_error()
|
||||||
|
{
|
||||||
|
if (this->issued_error_)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->issued_error_ = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get the type.
|
// Get the type.
|
||||||
|
|
||||||
Type*
|
Type*
|
||||||
|
@ -8941,15 +8999,12 @@ Call_expression::do_check_types(Gogo*)
|
||||||
|
|
||||||
// Return whether we have to use a temporary variable to ensure that
|
// Return whether we have to use a temporary variable to ensure that
|
||||||
// we evaluate this call expression in order. If the call returns no
|
// we evaluate this call expression in order. If the call returns no
|
||||||
// results then it will inevitably be executed last. If the call
|
// results then it will inevitably be executed last.
|
||||||
// returns more than one result then it will be used with Call_result
|
|
||||||
// expressions. So we only have to use a temporary variable if the
|
|
||||||
// call returns exactly one result.
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Call_expression::do_must_eval_in_order() const
|
Call_expression::do_must_eval_in_order() const
|
||||||
{
|
{
|
||||||
return this->result_count() == 1;
|
return this->result_count() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the function and the first argument to use when calling a bound
|
// Get the function and the first argument to use when calling a bound
|
||||||
|
@ -9193,16 +9248,56 @@ Call_expression::do_get_tree(Translate_context* context)
|
||||||
ret = build1(NOP_EXPR, rettype, ret);
|
ret = build1(NOP_EXPR, rettype, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is more than one result, we will refer to the call
|
if (this->results_ != NULL)
|
||||||
// multiple times.
|
ret = this->set_results(context, ret);
|
||||||
if (fntype->results() != NULL && fntype->results()->size() > 1)
|
|
||||||
ret = save_expr(ret);
|
|
||||||
|
|
||||||
this->tree_ = ret;
|
this->tree_ = ret;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the result variables if this call returns multiple results.
|
||||||
|
|
||||||
|
tree
|
||||||
|
Call_expression::set_results(Translate_context* context, tree call_tree)
|
||||||
|
{
|
||||||
|
tree stmt_list = NULL_TREE;
|
||||||
|
|
||||||
|
call_tree = save_expr(call_tree);
|
||||||
|
|
||||||
|
if (TREE_CODE(TREE_TYPE(call_tree)) != RECORD_TYPE)
|
||||||
|
{
|
||||||
|
go_assert(saw_errors());
|
||||||
|
return call_tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
source_location loc = this->location();
|
||||||
|
tree field = TYPE_FIELDS(TREE_TYPE(call_tree));
|
||||||
|
size_t rc = this->result_count();
|
||||||
|
for (size_t i = 0; i < rc; ++i, field = DECL_CHAIN(field))
|
||||||
|
{
|
||||||
|
go_assert(field != NULL_TREE);
|
||||||
|
|
||||||
|
Temporary_statement* temp = this->result(i);
|
||||||
|
Temporary_reference_expression* ref =
|
||||||
|
Expression::make_temporary_reference(temp, loc);
|
||||||
|
ref->set_is_lvalue();
|
||||||
|
tree temp_tree = ref->get_tree(context);
|
||||||
|
if (temp_tree == error_mark_node)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tree val_tree = build3_loc(loc, COMPONENT_REF, TREE_TYPE(field),
|
||||||
|
call_tree, field, NULL_TREE);
|
||||||
|
tree set_tree = build2_loc(loc, MODIFY_EXPR, void_type_node, temp_tree,
|
||||||
|
val_tree);
|
||||||
|
|
||||||
|
append_to_statement_list(set_tree, &stmt_list);
|
||||||
|
}
|
||||||
|
go_assert(field == NULL_TREE);
|
||||||
|
|
||||||
|
return save_expr(stmt_list);
|
||||||
|
}
|
||||||
|
|
||||||
// Make a call expression.
|
// Make a call expression.
|
||||||
|
|
||||||
Call_expression*
|
Call_expression*
|
||||||
|
@ -9292,8 +9387,9 @@ Call_result_expression::do_type()
|
||||||
return Type::make_error_type();
|
return Type::make_error_type();
|
||||||
}
|
}
|
||||||
const Typed_identifier_list* results = fntype->results();
|
const Typed_identifier_list* results = fntype->results();
|
||||||
if (results == NULL)
|
if (results == NULL || results->size() < 2)
|
||||||
{
|
{
|
||||||
|
if (ce->issue_error())
|
||||||
this->report_error(_("number of results does not match "
|
this->report_error(_("number of results does not match "
|
||||||
"number of values"));
|
"number of values"));
|
||||||
return Type::make_error_type();
|
return Type::make_error_type();
|
||||||
|
@ -9307,6 +9403,7 @@ Call_result_expression::do_type()
|
||||||
}
|
}
|
||||||
if (pr == results->end())
|
if (pr == results->end())
|
||||||
{
|
{
|
||||||
|
if (ce->issue_error())
|
||||||
this->report_error(_("number of results does not match "
|
this->report_error(_("number of results does not match "
|
||||||
"number of values"));
|
"number of values"));
|
||||||
return Type::make_error_type();
|
return Type::make_error_type();
|
||||||
|
@ -9332,27 +9429,18 @@ Call_result_expression::do_determine_type(const Type_context*)
|
||||||
this->call_->determine_type_no_context();
|
this->call_->determine_type_no_context();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the tree.
|
// Return the tree. We just refer to the temporary set by the call
|
||||||
|
// expression. We don't do this at lowering time because it makes it
|
||||||
|
// hard to evaluate the call at the right time.
|
||||||
|
|
||||||
tree
|
tree
|
||||||
Call_result_expression::do_get_tree(Translate_context* context)
|
Call_result_expression::do_get_tree(Translate_context* context)
|
||||||
{
|
{
|
||||||
tree call_tree = this->call_->get_tree(context);
|
Call_expression* ce = this->call_->call_expression();
|
||||||
if (call_tree == error_mark_node)
|
go_assert(ce != NULL);
|
||||||
return error_mark_node;
|
Temporary_statement* ts = ce->result(this->index_);
|
||||||
if (TREE_CODE(TREE_TYPE(call_tree)) != RECORD_TYPE)
|
Expression* ref = Expression::make_temporary_reference(ts, this->location());
|
||||||
{
|
return ref->get_tree(context);
|
||||||
go_assert(saw_errors());
|
|
||||||
return error_mark_node;
|
|
||||||
}
|
|
||||||
tree field = TYPE_FIELDS(TREE_TYPE(call_tree));
|
|
||||||
for (unsigned int i = 0; i < this->index_; ++i)
|
|
||||||
{
|
|
||||||
go_assert(field != NULL_TREE);
|
|
||||||
field = DECL_CHAIN(field);
|
|
||||||
}
|
|
||||||
go_assert(field != NULL_TREE);
|
|
||||||
return build3(COMPONENT_REF, TREE_TYPE(field), call_tree, field, NULL_TREE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a reference to a single result of a call which returns
|
// Make a reference to a single result of a call which returns
|
||||||
|
@ -9383,7 +9471,7 @@ Index_expression::do_traverse(Traverse* traverse)
|
||||||
// expression into an array index, a string index, or a map index.
|
// expression into an array index, a string index, or a map index.
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
Index_expression::do_lower(Gogo*, Named_object*, int)
|
Index_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
|
||||||
{
|
{
|
||||||
source_location location = this->location();
|
source_location location = this->location();
|
||||||
Expression* left = this->left_;
|
Expression* left = this->left_;
|
||||||
|
@ -10542,7 +10630,7 @@ class Selector_expression : public Parser_expression
|
||||||
{ return Expression::traverse(&this->left_, traverse); }
|
{ return Expression::traverse(&this->left_, traverse); }
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
do_lower(Gogo*, Named_object*, int);
|
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
do_copy()
|
do_copy()
|
||||||
|
@ -10565,7 +10653,8 @@ class Selector_expression : public Parser_expression
|
||||||
// hand side.
|
// hand side.
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
Selector_expression::do_lower(Gogo* gogo, Named_object*, int)
|
Selector_expression::do_lower(Gogo* gogo, Named_object*, Statement_inserter*,
|
||||||
|
int)
|
||||||
{
|
{
|
||||||
Expression* left = this->left_;
|
Expression* left = this->left_;
|
||||||
if (left->is_type_expression())
|
if (left->is_type_expression())
|
||||||
|
@ -10734,6 +10823,8 @@ Selector_expression::lower_method_expression(Gogo* gogo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gogo->start_block(location);
|
||||||
|
|
||||||
Call_expression* call = Expression::make_call(bm, args,
|
Call_expression* call = Expression::make_call(bm, args,
|
||||||
method_type->is_varargs(),
|
method_type->is_varargs(),
|
||||||
location);
|
location);
|
||||||
|
@ -10756,6 +10847,13 @@ Selector_expression::lower_method_expression(Gogo* gogo)
|
||||||
}
|
}
|
||||||
gogo->add_statement(s);
|
gogo->add_statement(s);
|
||||||
|
|
||||||
|
Block* b = gogo->finish_block(location);
|
||||||
|
|
||||||
|
gogo->add_block(b, location);
|
||||||
|
|
||||||
|
// Lower the call in case there are multiple results.
|
||||||
|
gogo->lower_block(no, b);
|
||||||
|
|
||||||
gogo->finish_function(location);
|
gogo->finish_function(location);
|
||||||
|
|
||||||
return Expression::make_func_reference(no, NULL, location);
|
return Expression::make_func_reference(no, NULL, location);
|
||||||
|
@ -11860,7 +11958,7 @@ class Composite_literal_expression : public Parser_expression
|
||||||
do_traverse(Traverse* traverse);
|
do_traverse(Traverse* traverse);
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
do_lower(Gogo*, Named_object*, int);
|
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
do_copy()
|
do_copy()
|
||||||
|
@ -11884,7 +11982,7 @@ class Composite_literal_expression : public Parser_expression
|
||||||
make_array(Type*, Expression_list*);
|
make_array(Type*, Expression_list*);
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
lower_map(Gogo*, Named_object*, Type*);
|
lower_map(Gogo*, Named_object*, Statement_inserter*, Type*);
|
||||||
|
|
||||||
// The type of the composite literal.
|
// The type of the composite literal.
|
||||||
Type* type_;
|
Type* type_;
|
||||||
|
@ -11913,7 +12011,8 @@ Composite_literal_expression::do_traverse(Traverse* traverse)
|
||||||
// the type.
|
// the type.
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function, int)
|
Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function,
|
||||||
|
Statement_inserter* inserter, int)
|
||||||
{
|
{
|
||||||
Type* type = this->type_;
|
Type* type = this->type_;
|
||||||
|
|
||||||
|
@ -11940,7 +12039,7 @@ Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function, int)
|
||||||
else if (type->array_type() != NULL)
|
else if (type->array_type() != NULL)
|
||||||
return this->lower_array(type);
|
return this->lower_array(type);
|
||||||
else if (type->map_type() != NULL)
|
else if (type->map_type() != NULL)
|
||||||
return this->lower_map(gogo, function, type);
|
return this->lower_map(gogo, function, inserter, type);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error_at(this->location(),
|
error_at(this->location(),
|
||||||
|
@ -12244,6 +12343,7 @@ Composite_literal_expression::make_array(Type* type, Expression_list* vals)
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function,
|
Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function,
|
||||||
|
Statement_inserter* inserter,
|
||||||
Type* type)
|
Type* type)
|
||||||
{
|
{
|
||||||
source_location location = this->location();
|
source_location location = this->location();
|
||||||
|
@ -12272,7 +12372,7 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function,
|
||||||
if ((*p)->unknown_expression() != NULL)
|
if ((*p)->unknown_expression() != NULL)
|
||||||
{
|
{
|
||||||
(*p)->unknown_expression()->clear_is_composite_literal_key();
|
(*p)->unknown_expression()->clear_is_composite_literal_key();
|
||||||
gogo->lower_expression(function, &*p);
|
gogo->lower_expression(function, inserter, &*p);
|
||||||
go_assert((*p)->is_error_expression());
|
go_assert((*p)->is_error_expression());
|
||||||
return Expression::make_error(location);
|
return Expression::make_error(location);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
class Gogo;
|
class Gogo;
|
||||||
class Translate_context;
|
class Translate_context;
|
||||||
class Traverse;
|
class Traverse;
|
||||||
|
class Statement_inserter;
|
||||||
class Type;
|
class Type;
|
||||||
struct Type_context;
|
struct Type_context;
|
||||||
class Function_type;
|
class Function_type;
|
||||||
|
@ -128,7 +129,7 @@ class Expression
|
||||||
// Make a reference to a temporary variable. Temporary variables
|
// Make a reference to a temporary variable. Temporary variables
|
||||||
// are always created by a single statement, which is what we use to
|
// are always created by a single statement, which is what we use to
|
||||||
// refer to them.
|
// refer to them.
|
||||||
static Expression*
|
static Temporary_reference_expression*
|
||||||
make_temporary_reference(Temporary_statement*, source_location);
|
make_temporary_reference(Temporary_statement*, source_location);
|
||||||
|
|
||||||
// Make a sink expression--a reference to the blank identifier _.
|
// Make a sink expression--a reference to the blank identifier _.
|
||||||
|
@ -521,13 +522,18 @@ class Expression
|
||||||
traverse_subexpressions(Traverse*);
|
traverse_subexpressions(Traverse*);
|
||||||
|
|
||||||
// Lower an expression. This is called immediately after parsing.
|
// Lower an expression. This is called immediately after parsing.
|
||||||
// IOTA_VALUE is the value that we should give to any iota
|
// FUNCTION is the function we are in; it will be NULL for an
|
||||||
// expressions. This function must resolve expressions which could
|
// expression initializing a global variable. INSERTER may be used
|
||||||
// not be fully parsed into their final form. It returns the same
|
// to insert statements before the statement or initializer
|
||||||
// Expression or a new one.
|
// containing this expression; it is normally used to create
|
||||||
|
// temporary variables. IOTA_VALUE is the value that we should give
|
||||||
|
// to any iota expressions. This function must resolve expressions
|
||||||
|
// which could not be fully parsed into their final form. It
|
||||||
|
// returns the same Expression or a new one.
|
||||||
Expression*
|
Expression*
|
||||||
lower(Gogo* gogo, Named_object* function, int iota_value)
|
lower(Gogo* gogo, Named_object* function, Statement_inserter* inserter,
|
||||||
{ return this->do_lower(gogo, function, iota_value); }
|
int iota_value)
|
||||||
|
{ return this->do_lower(gogo, function, inserter, iota_value); }
|
||||||
|
|
||||||
// Determine the real type of an expression with abstract integer,
|
// Determine the real type of an expression with abstract integer,
|
||||||
// floating point, or complex type. TYPE_CONTEXT describes the
|
// floating point, or complex type. TYPE_CONTEXT describes the
|
||||||
|
@ -636,7 +642,7 @@ class Expression
|
||||||
|
|
||||||
// Return a lowered expression.
|
// Return a lowered expression.
|
||||||
virtual Expression*
|
virtual Expression*
|
||||||
do_lower(Gogo*, Named_object*, int)
|
do_lower(Gogo*, Named_object*, Statement_inserter*, int)
|
||||||
{ return this; }
|
{ return this; }
|
||||||
|
|
||||||
// Return whether this is a constant expression.
|
// Return whether this is a constant expression.
|
||||||
|
@ -871,7 +877,7 @@ class Parser_expression : public Expression
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual Expression*
|
virtual Expression*
|
||||||
do_lower(Gogo*, Named_object*, int) = 0;
|
do_lower(Gogo*, Named_object*, Statement_inserter*, int) = 0;
|
||||||
|
|
||||||
Type*
|
Type*
|
||||||
do_type();
|
do_type();
|
||||||
|
@ -906,7 +912,7 @@ class Var_expression : public Expression
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Expression*
|
Expression*
|
||||||
do_lower(Gogo*, Named_object*, int);
|
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
|
||||||
|
|
||||||
Type*
|
Type*
|
||||||
do_type();
|
do_type();
|
||||||
|
@ -941,9 +947,15 @@ class Temporary_reference_expression : public Expression
|
||||||
Temporary_reference_expression(Temporary_statement* statement,
|
Temporary_reference_expression(Temporary_statement* statement,
|
||||||
source_location location)
|
source_location location)
|
||||||
: Expression(EXPRESSION_TEMPORARY_REFERENCE, location),
|
: Expression(EXPRESSION_TEMPORARY_REFERENCE, location),
|
||||||
statement_(statement)
|
statement_(statement), is_lvalue_(false)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
// Indicate that this reference appears on the left hand side of an
|
||||||
|
// assignment statement.
|
||||||
|
void
|
||||||
|
set_is_lvalue()
|
||||||
|
{ this->is_lvalue_ = true; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Type*
|
Type*
|
||||||
do_type();
|
do_type();
|
||||||
|
@ -969,6 +981,9 @@ class Temporary_reference_expression : public Expression
|
||||||
private:
|
private:
|
||||||
// The statement where the temporary variable is defined.
|
// The statement where the temporary variable is defined.
|
||||||
Temporary_statement* statement_;
|
Temporary_statement* statement_;
|
||||||
|
// Whether this reference appears on the left hand side of an
|
||||||
|
// assignment statement.
|
||||||
|
bool is_lvalue_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A string expression.
|
// A string expression.
|
||||||
|
@ -1099,7 +1114,7 @@ class Binary_expression : public Expression
|
||||||
do_traverse(Traverse* traverse);
|
do_traverse(Traverse* traverse);
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
do_lower(Gogo*, Named_object*, int);
|
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
do_is_constant() const
|
do_is_constant() const
|
||||||
|
@ -1156,9 +1171,9 @@ class Call_expression : public Expression
|
||||||
Call_expression(Expression* fn, Expression_list* args, bool is_varargs,
|
Call_expression(Expression* fn, Expression_list* args, bool is_varargs,
|
||||||
source_location location)
|
source_location location)
|
||||||
: Expression(EXPRESSION_CALL, location),
|
: Expression(EXPRESSION_CALL, location),
|
||||||
fn_(fn), args_(args), type_(NULL), tree_(NULL), is_varargs_(is_varargs),
|
fn_(fn), args_(args), type_(NULL), results_(NULL), tree_(NULL),
|
||||||
varargs_are_lowered_(false), types_are_determined_(false),
|
is_varargs_(is_varargs), varargs_are_lowered_(false),
|
||||||
is_deferred_(false)
|
types_are_determined_(false), is_deferred_(false), issued_error_(false)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
// The function to call.
|
// The function to call.
|
||||||
|
@ -1183,6 +1198,12 @@ class Call_expression : public Expression
|
||||||
size_t
|
size_t
|
||||||
result_count() const;
|
result_count() const;
|
||||||
|
|
||||||
|
// Return the temporary variable which holds result I. This is only
|
||||||
|
// valid after the expression has been lowered, and is only valid
|
||||||
|
// for calls which return multiple results.
|
||||||
|
Temporary_statement*
|
||||||
|
result(size_t i) const;
|
||||||
|
|
||||||
// Return whether this is a call to the predeclared function
|
// Return whether this is a call to the predeclared function
|
||||||
// recover.
|
// recover.
|
||||||
bool
|
bool
|
||||||
|
@ -1207,12 +1228,17 @@ class Call_expression : public Expression
|
||||||
set_is_deferred()
|
set_is_deferred()
|
||||||
{ this->is_deferred_ = true; }
|
{ this->is_deferred_ = true; }
|
||||||
|
|
||||||
|
// We have found an error with this call expression; return true if
|
||||||
|
// we should report it.
|
||||||
|
bool
|
||||||
|
issue_error();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int
|
int
|
||||||
do_traverse(Traverse*);
|
do_traverse(Traverse*);
|
||||||
|
|
||||||
virtual Expression*
|
virtual Expression*
|
||||||
do_lower(Gogo*, Named_object*, int);
|
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
|
||||||
|
|
||||||
void
|
void
|
||||||
do_discarding_value()
|
do_discarding_value()
|
||||||
|
@ -1256,8 +1282,8 @@ class Call_expression : public Expression
|
||||||
|
|
||||||
// Let a builtin expression lower varargs.
|
// Let a builtin expression lower varargs.
|
||||||
Expression*
|
Expression*
|
||||||
lower_varargs(Gogo*, Named_object* function, Type* varargs_type,
|
lower_varargs(Gogo*, Named_object* function, Statement_inserter* inserter,
|
||||||
size_t param_count);
|
Type* varargs_type, size_t param_count);
|
||||||
|
|
||||||
// Let a builtin expression check whether types have been
|
// Let a builtin expression check whether types have been
|
||||||
// determined.
|
// determined.
|
||||||
|
@ -1276,6 +1302,9 @@ class Call_expression : public Expression
|
||||||
Interface_field_reference_expression*,
|
Interface_field_reference_expression*,
|
||||||
tree*);
|
tree*);
|
||||||
|
|
||||||
|
tree
|
||||||
|
set_results(Translate_context*, tree);
|
||||||
|
|
||||||
// The function to call.
|
// The function to call.
|
||||||
Expression* fn_;
|
Expression* fn_;
|
||||||
// The arguments to pass. This may be NULL if there are no
|
// The arguments to pass. This may be NULL if there are no
|
||||||
|
@ -1283,6 +1312,9 @@ class Call_expression : public Expression
|
||||||
Expression_list* args_;
|
Expression_list* args_;
|
||||||
// The type of the expression, to avoid recomputing it.
|
// The type of the expression, to avoid recomputing it.
|
||||||
Type* type_;
|
Type* type_;
|
||||||
|
// The list of temporaries which will hold the results if the
|
||||||
|
// function returns a tuple.
|
||||||
|
std::vector<Temporary_statement*>* results_;
|
||||||
// The tree for the call, used for a call which returns a tuple.
|
// The tree for the call, used for a call which returns a tuple.
|
||||||
tree tree_;
|
tree tree_;
|
||||||
// True if the last argument is a varargs argument (f(a...)).
|
// True if the last argument is a varargs argument (f(a...)).
|
||||||
|
@ -1293,6 +1325,10 @@ class Call_expression : public Expression
|
||||||
bool types_are_determined_;
|
bool types_are_determined_;
|
||||||
// True if the call is an argument to a defer statement.
|
// True if the call is an argument to a defer statement.
|
||||||
bool is_deferred_;
|
bool is_deferred_;
|
||||||
|
// True if we reported an error about a mismatch between call
|
||||||
|
// results and uses. This is to avoid producing multiple errors
|
||||||
|
// when there are multiple Call_result_expressions.
|
||||||
|
bool issued_error_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// An expression which represents a pointer to a function.
|
// An expression which represents a pointer to a function.
|
||||||
|
@ -1390,7 +1426,7 @@ class Unknown_expression : public Parser_expression
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Expression*
|
Expression*
|
||||||
do_lower(Gogo*, Named_object*, int);
|
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
do_copy()
|
do_copy()
|
||||||
|
@ -1425,7 +1461,7 @@ class Index_expression : public Parser_expression
|
||||||
do_traverse(Traverse*);
|
do_traverse(Traverse*);
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
do_lower(Gogo*, Named_object*, int);
|
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
|
||||||
|
|
||||||
Expression*
|
Expression*
|
||||||
do_copy()
|
do_copy()
|
||||||
|
|
|
@ -1148,9 +1148,13 @@ class Lower_parse_tree : public Traverse
|
||||||
| traverse_functions
|
| traverse_functions
|
||||||
| traverse_statements
|
| traverse_statements
|
||||||
| traverse_expressions),
|
| traverse_expressions),
|
||||||
gogo_(gogo), function_(function), iota_value_(-1)
|
gogo_(gogo), function_(function), iota_value_(-1), inserter_()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
void
|
||||||
|
set_inserter(const Statement_inserter* inserter)
|
||||||
|
{ this->inserter_ = *inserter; }
|
||||||
|
|
||||||
int
|
int
|
||||||
variable(Named_object*);
|
variable(Named_object*);
|
||||||
|
|
||||||
|
@ -1173,18 +1177,44 @@ class Lower_parse_tree : public Traverse
|
||||||
Named_object* function_;
|
Named_object* function_;
|
||||||
// Value to use for the predeclared constant iota.
|
// Value to use for the predeclared constant iota.
|
||||||
int iota_value_;
|
int iota_value_;
|
||||||
|
// Current statement inserter for use by expressions.
|
||||||
|
Statement_inserter inserter_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Lower variables. We handle variables specially to break loops in
|
// Lower variables.
|
||||||
// which a variable initialization expression refers to itself. The
|
|
||||||
// loop breaking is in lower_init_expression.
|
|
||||||
|
|
||||||
int
|
int
|
||||||
Lower_parse_tree::variable(Named_object* no)
|
Lower_parse_tree::variable(Named_object* no)
|
||||||
{
|
{
|
||||||
if (no->is_variable())
|
if (!no->is_variable())
|
||||||
no->var_value()->lower_init_expression(this->gogo_, this->function_);
|
|
||||||
return TRAVERSE_CONTINUE;
|
return TRAVERSE_CONTINUE;
|
||||||
|
|
||||||
|
if (no->is_variable() && no->var_value()->is_global())
|
||||||
|
{
|
||||||
|
// Global variables can have loops in their initialization
|
||||||
|
// expressions. This is handled in lower_init_expression.
|
||||||
|
no->var_value()->lower_init_expression(this->gogo_, this->function_,
|
||||||
|
&this->inserter_);
|
||||||
|
return TRAVERSE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a local variable. We are going to return
|
||||||
|
// TRAVERSE_SKIP_COMPONENTS here because we want to traverse the
|
||||||
|
// initialization expression when we reach the variable declaration
|
||||||
|
// statement. However, that means that we need to traverse the type
|
||||||
|
// ourselves.
|
||||||
|
if (no->var_value()->has_type())
|
||||||
|
{
|
||||||
|
Type* type = no->var_value()->type();
|
||||||
|
if (type != NULL)
|
||||||
|
{
|
||||||
|
if (Type::traverse(type, this) == TRAVERSE_EXIT)
|
||||||
|
return TRAVERSE_EXIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
go_assert(!no->var_value()->has_pre_init());
|
||||||
|
|
||||||
|
return TRAVERSE_SKIP_COMPONENTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lower constants. We handle constants specially so that we can set
|
// Lower constants. We handle constants specially so that we can set
|
||||||
|
@ -1238,27 +1268,38 @@ Lower_parse_tree::function(Named_object* no)
|
||||||
int
|
int
|
||||||
Lower_parse_tree::statement(Block* block, size_t* pindex, Statement* sorig)
|
Lower_parse_tree::statement(Block* block, size_t* pindex, Statement* sorig)
|
||||||
{
|
{
|
||||||
|
Statement_inserter hold_inserter(this->inserter_);
|
||||||
|
this->inserter_ = Statement_inserter(block, pindex);
|
||||||
|
|
||||||
// Lower the expressions first.
|
// Lower the expressions first.
|
||||||
int t = sorig->traverse_contents(this);
|
int t = sorig->traverse_contents(this);
|
||||||
if (t == TRAVERSE_EXIT)
|
if (t == TRAVERSE_EXIT)
|
||||||
|
{
|
||||||
|
this->inserter_ = hold_inserter;
|
||||||
return t;
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
// Keep lowering until nothing changes.
|
// Keep lowering until nothing changes.
|
||||||
Statement* s = sorig;
|
Statement* s = sorig;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
Statement* snew = s->lower(this->gogo_, this->function_, block);
|
Statement* snew = s->lower(this->gogo_, this->function_, block,
|
||||||
|
&this->inserter_);
|
||||||
if (snew == s)
|
if (snew == s)
|
||||||
break;
|
break;
|
||||||
s = snew;
|
s = snew;
|
||||||
t = s->traverse_contents(this);
|
t = s->traverse_contents(this);
|
||||||
if (t == TRAVERSE_EXIT)
|
if (t == TRAVERSE_EXIT)
|
||||||
|
{
|
||||||
|
this->inserter_ = hold_inserter;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (s != sorig)
|
if (s != sorig)
|
||||||
block->replace_statement(*pindex, s);
|
block->replace_statement(*pindex, s);
|
||||||
|
|
||||||
|
this->inserter_ = hold_inserter;
|
||||||
return TRAVERSE_SKIP_COMPONENTS;
|
return TRAVERSE_SKIP_COMPONENTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1277,7 +1318,7 @@ Lower_parse_tree::expression(Expression** pexpr)
|
||||||
{
|
{
|
||||||
Expression* e = *pexpr;
|
Expression* e = *pexpr;
|
||||||
Expression* enew = e->lower(this->gogo_, this->function_,
|
Expression* enew = e->lower(this->gogo_, this->function_,
|
||||||
this->iota_value_);
|
&this->inserter_, this->iota_value_);
|
||||||
if (enew == e)
|
if (enew == e)
|
||||||
break;
|
break;
|
||||||
*pexpr = enew;
|
*pexpr = enew;
|
||||||
|
@ -1304,12 +1345,16 @@ Gogo::lower_block(Named_object* function, Block* block)
|
||||||
block->traverse(&lower_parse_tree);
|
block->traverse(&lower_parse_tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lower an expression.
|
// Lower an expression. INSERTER may be NULL, in which case the
|
||||||
|
// expression had better not need to create any temporaries.
|
||||||
|
|
||||||
void
|
void
|
||||||
Gogo::lower_expression(Named_object* function, Expression** pexpr)
|
Gogo::lower_expression(Named_object* function, Statement_inserter* inserter,
|
||||||
|
Expression** pexpr)
|
||||||
{
|
{
|
||||||
Lower_parse_tree lower_parse_tree(this, function);
|
Lower_parse_tree lower_parse_tree(this, function);
|
||||||
|
if (inserter != NULL)
|
||||||
|
lower_parse_tree.set_inserter(inserter);
|
||||||
lower_parse_tree.expression(pexpr);
|
lower_parse_tree.expression(pexpr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1951,12 +1996,27 @@ Order_eval::statement(Block* block, size_t* pindex, Statement* s)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
source_location loc = (*pexpr)->location();
|
source_location loc = (*pexpr)->location();
|
||||||
Temporary_statement* ts = Statement::make_temporary(NULL, *pexpr, loc);
|
Statement* s;
|
||||||
block->insert_statement_before(*pindex, ts);
|
if ((*pexpr)->call_expression() == NULL
|
||||||
++*pindex;
|
|| (*pexpr)->call_expression()->result_count() < 2)
|
||||||
|
{
|
||||||
|
Temporary_statement* ts = Statement::make_temporary(NULL, *pexpr,
|
||||||
|
loc);
|
||||||
|
s = ts;
|
||||||
*pexpr = Expression::make_temporary_reference(ts, loc);
|
*pexpr = Expression::make_temporary_reference(ts, loc);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// A call expression which returns multiple results needs to
|
||||||
|
// be handled specially. We can't create a temporary
|
||||||
|
// because there is no type to give it. Any actual uses of
|
||||||
|
// the values will be done via Call_result_expressions.
|
||||||
|
s = Statement::make_statement(*pexpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
block->insert_statement_before(*pindex, s);
|
||||||
|
++*pindex;
|
||||||
|
}
|
||||||
|
|
||||||
if (init != orig_init)
|
if (init != orig_init)
|
||||||
vds->var()->var_value()->set_init(init);
|
vds->var()->var_value()->set_init(init);
|
||||||
|
@ -1978,7 +2038,7 @@ Order_eval::variable(Named_object* no)
|
||||||
return TRAVERSE_CONTINUE;
|
return TRAVERSE_CONTINUE;
|
||||||
|
|
||||||
Find_eval_ordering find_eval_ordering;
|
Find_eval_ordering find_eval_ordering;
|
||||||
init->traverse_subexpressions(&find_eval_ordering);
|
Expression::traverse(&init, &find_eval_ordering);
|
||||||
|
|
||||||
if (find_eval_ordering.size() <= 1)
|
if (find_eval_ordering.size() <= 1)
|
||||||
{
|
{
|
||||||
|
@ -1993,10 +2053,23 @@ Order_eval::variable(Named_object* no)
|
||||||
{
|
{
|
||||||
Expression** pexpr = *p;
|
Expression** pexpr = *p;
|
||||||
source_location loc = (*pexpr)->location();
|
source_location loc = (*pexpr)->location();
|
||||||
Temporary_statement* ts = Statement::make_temporary(NULL, *pexpr, loc);
|
Statement* s;
|
||||||
var->add_preinit_statement(this->gogo_, ts);
|
if ((*pexpr)->call_expression() == NULL
|
||||||
|
|| (*pexpr)->call_expression()->result_count() < 2)
|
||||||
|
{
|
||||||
|
Temporary_statement* ts = Statement::make_temporary(NULL, *pexpr,
|
||||||
|
loc);
|
||||||
|
s = ts;
|
||||||
*pexpr = Expression::make_temporary_reference(ts, loc);
|
*pexpr = Expression::make_temporary_reference(ts, loc);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// A call expression which returns multiple results needs to
|
||||||
|
// be handled specially.
|
||||||
|
s = Statement::make_statement(*pexpr);
|
||||||
|
}
|
||||||
|
var->add_preinit_statement(this->gogo_, s);
|
||||||
|
}
|
||||||
|
|
||||||
return TRAVERSE_SKIP_COMPONENTS;
|
return TRAVERSE_SKIP_COMPONENTS;
|
||||||
}
|
}
|
||||||
|
@ -2181,6 +2254,8 @@ Build_recover_thunks::function(Named_object* orig_no)
|
||||||
}
|
}
|
||||||
args->push_back(this->can_recover_arg(location));
|
args->push_back(this->can_recover_arg(location));
|
||||||
|
|
||||||
|
gogo->start_block(location);
|
||||||
|
|
||||||
Call_expression* call = Expression::make_call(fn, args, false, location);
|
Call_expression* call = Expression::make_call(fn, args, false, location);
|
||||||
|
|
||||||
Statement* s;
|
Statement* s;
|
||||||
|
@ -2202,6 +2277,13 @@ Build_recover_thunks::function(Named_object* orig_no)
|
||||||
s->determine_types();
|
s->determine_types();
|
||||||
gogo->add_statement(s);
|
gogo->add_statement(s);
|
||||||
|
|
||||||
|
Block* b = gogo->finish_block(location);
|
||||||
|
|
||||||
|
gogo->add_block(b, location);
|
||||||
|
|
||||||
|
// Lower the call in case it returns multiple results.
|
||||||
|
gogo->lower_block(new_no, b);
|
||||||
|
|
||||||
gogo->finish_function(location);
|
gogo->finish_function(location);
|
||||||
|
|
||||||
// Swap the function bodies and types.
|
// Swap the function bodies and types.
|
||||||
|
@ -3152,78 +3234,64 @@ Block::traverse(Traverse* traverse)
|
||||||
| Traverse::traverse_expressions
|
| Traverse::traverse_expressions
|
||||||
| Traverse::traverse_types)) != 0)
|
| Traverse::traverse_types)) != 0)
|
||||||
{
|
{
|
||||||
|
const unsigned int e_or_t = (Traverse::traverse_expressions
|
||||||
|
| Traverse::traverse_types);
|
||||||
|
const unsigned int e_or_t_or_s = (e_or_t
|
||||||
|
| Traverse::traverse_statements);
|
||||||
for (Bindings::const_definitions_iterator pb =
|
for (Bindings::const_definitions_iterator pb =
|
||||||
this->bindings_->begin_definitions();
|
this->bindings_->begin_definitions();
|
||||||
pb != this->bindings_->end_definitions();
|
pb != this->bindings_->end_definitions();
|
||||||
++pb)
|
++pb)
|
||||||
{
|
{
|
||||||
|
int t = TRAVERSE_CONTINUE;
|
||||||
switch ((*pb)->classification())
|
switch ((*pb)->classification())
|
||||||
{
|
{
|
||||||
case Named_object::NAMED_OBJECT_CONST:
|
case Named_object::NAMED_OBJECT_CONST:
|
||||||
if ((traverse_mask & Traverse::traverse_constants) != 0)
|
if ((traverse_mask & Traverse::traverse_constants) != 0)
|
||||||
|
t = traverse->constant(*pb, false);
|
||||||
|
if (t == TRAVERSE_CONTINUE
|
||||||
|
&& (traverse_mask & e_or_t) != 0)
|
||||||
{
|
{
|
||||||
if (traverse->constant(*pb, false) == TRAVERSE_EXIT)
|
Type* tc = (*pb)->const_value()->type();
|
||||||
return TRAVERSE_EXIT;
|
if (tc != NULL
|
||||||
}
|
&& Type::traverse(tc, traverse) == TRAVERSE_EXIT)
|
||||||
if ((traverse_mask & Traverse::traverse_types) != 0
|
|
||||||
|| (traverse_mask & Traverse::traverse_expressions) != 0)
|
|
||||||
{
|
|
||||||
Type* t = (*pb)->const_value()->type();
|
|
||||||
if (t != NULL
|
|
||||||
&& Type::traverse(t, traverse) == TRAVERSE_EXIT)
|
|
||||||
return TRAVERSE_EXIT;
|
|
||||||
}
|
|
||||||
if ((traverse_mask & Traverse::traverse_expressions) != 0
|
|
||||||
|| (traverse_mask & Traverse::traverse_types) != 0)
|
|
||||||
{
|
|
||||||
if ((*pb)->const_value()->traverse_expression(traverse)
|
|
||||||
== TRAVERSE_EXIT)
|
|
||||||
return TRAVERSE_EXIT;
|
return TRAVERSE_EXIT;
|
||||||
|
t = (*pb)->const_value()->traverse_expression(traverse);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Named_object::NAMED_OBJECT_VAR:
|
case Named_object::NAMED_OBJECT_VAR:
|
||||||
case Named_object::NAMED_OBJECT_RESULT_VAR:
|
case Named_object::NAMED_OBJECT_RESULT_VAR:
|
||||||
if ((traverse_mask & Traverse::traverse_variables) != 0)
|
if ((traverse_mask & Traverse::traverse_variables) != 0)
|
||||||
|
t = traverse->variable(*pb);
|
||||||
|
if (t == TRAVERSE_CONTINUE
|
||||||
|
&& (traverse_mask & e_or_t) != 0)
|
||||||
{
|
{
|
||||||
if (traverse->variable(*pb) == TRAVERSE_EXIT)
|
if ((*pb)->is_result_variable()
|
||||||
return TRAVERSE_EXIT;
|
|| (*pb)->var_value()->has_type())
|
||||||
}
|
|
||||||
if (((traverse_mask & Traverse::traverse_types) != 0
|
|
||||||
|| (traverse_mask & Traverse::traverse_expressions) != 0)
|
|
||||||
&& ((*pb)->is_result_variable()
|
|
||||||
|| (*pb)->var_value()->has_type()))
|
|
||||||
{
|
{
|
||||||
Type* t = ((*pb)->is_variable()
|
Type* tv = ((*pb)->is_variable()
|
||||||
? (*pb)->var_value()->type()
|
? (*pb)->var_value()->type()
|
||||||
: (*pb)->result_var_value()->type());
|
: (*pb)->result_var_value()->type());
|
||||||
if (t != NULL
|
if (tv != NULL
|
||||||
&& Type::traverse(t, traverse) == TRAVERSE_EXIT)
|
&& Type::traverse(tv, traverse) == TRAVERSE_EXIT)
|
||||||
return TRAVERSE_EXIT;
|
return TRAVERSE_EXIT;
|
||||||
}
|
}
|
||||||
if ((*pb)->is_variable()
|
|
||||||
&& ((traverse_mask & Traverse::traverse_expressions) != 0
|
|
||||||
|| (traverse_mask & Traverse::traverse_types) != 0))
|
|
||||||
{
|
|
||||||
if ((*pb)->var_value()->traverse_expression(traverse)
|
|
||||||
== TRAVERSE_EXIT)
|
|
||||||
return TRAVERSE_EXIT;
|
|
||||||
}
|
}
|
||||||
|
if (t == TRAVERSE_CONTINUE
|
||||||
|
&& (traverse_mask & e_or_t_or_s) != 0
|
||||||
|
&& (*pb)->is_variable())
|
||||||
|
t = (*pb)->var_value()->traverse_expression(traverse,
|
||||||
|
traverse_mask);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Named_object::NAMED_OBJECT_FUNC:
|
case Named_object::NAMED_OBJECT_FUNC:
|
||||||
case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
|
case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
|
||||||
// FIXME: Where will nested functions be found?
|
|
||||||
go_unreachable();
|
go_unreachable();
|
||||||
|
|
||||||
case Named_object::NAMED_OBJECT_TYPE:
|
case Named_object::NAMED_OBJECT_TYPE:
|
||||||
if ((traverse_mask & Traverse::traverse_types) != 0
|
if ((traverse_mask & e_or_t) != 0)
|
||||||
|| (traverse_mask & Traverse::traverse_expressions) != 0)
|
t = Type::traverse((*pb)->type_value(), traverse);
|
||||||
{
|
|
||||||
if (Type::traverse((*pb)->type_value(), traverse)
|
|
||||||
== TRAVERSE_EXIT)
|
|
||||||
return TRAVERSE_EXIT;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
|
case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
|
||||||
|
@ -3237,6 +3305,9 @@ Block::traverse(Traverse* traverse)
|
||||||
default:
|
default:
|
||||||
go_unreachable();
|
go_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (t == TRAVERSE_EXIT)
|
||||||
|
return TRAVERSE_EXIT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3351,14 +3422,17 @@ Variable::Variable(Type* type, Expression* init, bool is_global,
|
||||||
// Traverse the initializer expression.
|
// Traverse the initializer expression.
|
||||||
|
|
||||||
int
|
int
|
||||||
Variable::traverse_expression(Traverse* traverse)
|
Variable::traverse_expression(Traverse* traverse, unsigned int traverse_mask)
|
||||||
{
|
{
|
||||||
if (this->preinit_ != NULL)
|
if (this->preinit_ != NULL)
|
||||||
{
|
{
|
||||||
if (this->preinit_->traverse(traverse) == TRAVERSE_EXIT)
|
if (this->preinit_->traverse(traverse) == TRAVERSE_EXIT)
|
||||||
return TRAVERSE_EXIT;
|
return TRAVERSE_EXIT;
|
||||||
}
|
}
|
||||||
if (this->init_ != NULL)
|
if (this->init_ != NULL
|
||||||
|
&& ((traverse_mask
|
||||||
|
& (Traverse::traverse_expressions | Traverse::traverse_types))
|
||||||
|
!= 0))
|
||||||
{
|
{
|
||||||
if (Expression::traverse(&this->init_, traverse) == TRAVERSE_EXIT)
|
if (Expression::traverse(&this->init_, traverse) == TRAVERSE_EXIT)
|
||||||
return TRAVERSE_EXIT;
|
return TRAVERSE_EXIT;
|
||||||
|
@ -3369,7 +3443,8 @@ Variable::traverse_expression(Traverse* traverse)
|
||||||
// Lower the initialization expression after parsing is complete.
|
// Lower the initialization expression after parsing is complete.
|
||||||
|
|
||||||
void
|
void
|
||||||
Variable::lower_init_expression(Gogo* gogo, Named_object* function)
|
Variable::lower_init_expression(Gogo* gogo, Named_object* function,
|
||||||
|
Statement_inserter* inserter)
|
||||||
{
|
{
|
||||||
if (this->init_ != NULL && !this->init_is_lowered_)
|
if (this->init_ != NULL && !this->init_is_lowered_)
|
||||||
{
|
{
|
||||||
|
@ -3381,7 +3456,14 @@ Variable::lower_init_expression(Gogo* gogo, Named_object* function)
|
||||||
}
|
}
|
||||||
this->seen_ = true;
|
this->seen_ = true;
|
||||||
|
|
||||||
gogo->lower_expression(function, &this->init_);
|
Statement_inserter global_inserter;
|
||||||
|
if (this->is_global_)
|
||||||
|
{
|
||||||
|
global_inserter = Statement_inserter(gogo, this);
|
||||||
|
inserter = &global_inserter;
|
||||||
|
}
|
||||||
|
|
||||||
|
gogo->lower_expression(function, inserter, &this->init_);
|
||||||
|
|
||||||
this->seen_ = false;
|
this->seen_ = false;
|
||||||
|
|
||||||
|
@ -4508,70 +4590,60 @@ Bindings::traverse(Traverse* traverse, bool is_global)
|
||||||
|
|
||||||
// We don't use an iterator because we permit the traversal to add
|
// We don't use an iterator because we permit the traversal to add
|
||||||
// new global objects.
|
// new global objects.
|
||||||
|
const unsigned int e_or_t = (Traverse::traverse_expressions
|
||||||
|
| Traverse::traverse_types);
|
||||||
|
const unsigned int e_or_t_or_s = (e_or_t
|
||||||
|
| Traverse::traverse_statements);
|
||||||
for (size_t i = 0; i < this->named_objects_.size(); ++i)
|
for (size_t i = 0; i < this->named_objects_.size(); ++i)
|
||||||
{
|
{
|
||||||
Named_object* p = this->named_objects_[i];
|
Named_object* p = this->named_objects_[i];
|
||||||
|
int t = TRAVERSE_CONTINUE;
|
||||||
switch (p->classification())
|
switch (p->classification())
|
||||||
{
|
{
|
||||||
case Named_object::NAMED_OBJECT_CONST:
|
case Named_object::NAMED_OBJECT_CONST:
|
||||||
if ((traverse_mask & Traverse::traverse_constants) != 0)
|
if ((traverse_mask & Traverse::traverse_constants) != 0)
|
||||||
|
t = traverse->constant(p, is_global);
|
||||||
|
if (t == TRAVERSE_CONTINUE
|
||||||
|
&& (traverse_mask & e_or_t) != 0)
|
||||||
{
|
{
|
||||||
if (traverse->constant(p, is_global) == TRAVERSE_EXIT)
|
Type* tc = p->const_value()->type();
|
||||||
return TRAVERSE_EXIT;
|
if (tc != NULL
|
||||||
}
|
&& Type::traverse(tc, traverse) == TRAVERSE_EXIT)
|
||||||
if ((traverse_mask & Traverse::traverse_types) != 0
|
|
||||||
|| (traverse_mask & Traverse::traverse_expressions) != 0)
|
|
||||||
{
|
|
||||||
Type* t = p->const_value()->type();
|
|
||||||
if (t != NULL
|
|
||||||
&& Type::traverse(t, traverse) == TRAVERSE_EXIT)
|
|
||||||
return TRAVERSE_EXIT;
|
|
||||||
if (p->const_value()->traverse_expression(traverse)
|
|
||||||
== TRAVERSE_EXIT)
|
|
||||||
return TRAVERSE_EXIT;
|
return TRAVERSE_EXIT;
|
||||||
|
t = p->const_value()->traverse_expression(traverse);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Named_object::NAMED_OBJECT_VAR:
|
case Named_object::NAMED_OBJECT_VAR:
|
||||||
case Named_object::NAMED_OBJECT_RESULT_VAR:
|
case Named_object::NAMED_OBJECT_RESULT_VAR:
|
||||||
if ((traverse_mask & Traverse::traverse_variables) != 0)
|
if ((traverse_mask & Traverse::traverse_variables) != 0)
|
||||||
|
t = traverse->variable(p);
|
||||||
|
if (t == TRAVERSE_CONTINUE
|
||||||
|
&& (traverse_mask & e_or_t) != 0)
|
||||||
{
|
{
|
||||||
if (traverse->variable(p) == TRAVERSE_EXIT)
|
if (p->is_result_variable()
|
||||||
return TRAVERSE_EXIT;
|
|| p->var_value()->has_type())
|
||||||
}
|
|
||||||
if (((traverse_mask & Traverse::traverse_types) != 0
|
|
||||||
|| (traverse_mask & Traverse::traverse_expressions) != 0)
|
|
||||||
&& (p->is_result_variable()
|
|
||||||
|| p->var_value()->has_type()))
|
|
||||||
{
|
{
|
||||||
Type* t = (p->is_variable()
|
Type* tv = (p->is_variable()
|
||||||
? p->var_value()->type()
|
? p->var_value()->type()
|
||||||
: p->result_var_value()->type());
|
: p->result_var_value()->type());
|
||||||
if (t != NULL
|
if (tv != NULL
|
||||||
&& Type::traverse(t, traverse) == TRAVERSE_EXIT)
|
&& Type::traverse(tv, traverse) == TRAVERSE_EXIT)
|
||||||
return TRAVERSE_EXIT;
|
return TRAVERSE_EXIT;
|
||||||
}
|
}
|
||||||
if (p->is_variable()
|
|
||||||
&& ((traverse_mask & Traverse::traverse_types) != 0
|
|
||||||
|| (traverse_mask & Traverse::traverse_expressions) != 0))
|
|
||||||
{
|
|
||||||
if (p->var_value()->traverse_expression(traverse)
|
|
||||||
== TRAVERSE_EXIT)
|
|
||||||
return TRAVERSE_EXIT;
|
|
||||||
}
|
}
|
||||||
|
if (t == TRAVERSE_CONTINUE
|
||||||
|
&& (traverse_mask & e_or_t_or_s) != 0
|
||||||
|
&& p->is_variable())
|
||||||
|
t = p->var_value()->traverse_expression(traverse, traverse_mask);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Named_object::NAMED_OBJECT_FUNC:
|
case Named_object::NAMED_OBJECT_FUNC:
|
||||||
if ((traverse_mask & Traverse::traverse_functions) != 0)
|
if ((traverse_mask & Traverse::traverse_functions) != 0)
|
||||||
{
|
t = traverse->function(p);
|
||||||
int t = traverse->function(p);
|
|
||||||
if (t == TRAVERSE_EXIT)
|
|
||||||
return TRAVERSE_EXIT;
|
|
||||||
else if (t == TRAVERSE_SKIP_COMPONENTS)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((traverse_mask
|
if (t == TRAVERSE_CONTINUE
|
||||||
|
&& (traverse_mask
|
||||||
& (Traverse::traverse_variables
|
& (Traverse::traverse_variables
|
||||||
| Traverse::traverse_constants
|
| Traverse::traverse_constants
|
||||||
| Traverse::traverse_functions
|
| Traverse::traverse_functions
|
||||||
|
@ -4591,12 +4663,8 @@ Bindings::traverse(Traverse* traverse, bool is_global)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Named_object::NAMED_OBJECT_TYPE:
|
case Named_object::NAMED_OBJECT_TYPE:
|
||||||
if ((traverse_mask & Traverse::traverse_types) != 0
|
if ((traverse_mask & e_or_t) != 0)
|
||||||
|| (traverse_mask & Traverse::traverse_expressions) != 0)
|
t = Type::traverse(p->type_value(), traverse);
|
||||||
{
|
|
||||||
if (Type::traverse(p->type_value(), traverse) == TRAVERSE_EXIT)
|
|
||||||
return TRAVERSE_EXIT;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
|
case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
|
||||||
|
@ -4608,6 +4676,9 @@ Bindings::traverse(Traverse* traverse, bool is_global)
|
||||||
default:
|
default:
|
||||||
go_unreachable();
|
go_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (t == TRAVERSE_EXIT)
|
||||||
|
return TRAVERSE_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRAVERSE_CONTINUE;
|
return TRAVERSE_CONTINUE;
|
||||||
|
@ -4805,3 +4876,20 @@ Traverse::type(Type*)
|
||||||
{
|
{
|
||||||
go_unreachable();
|
go_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Class Statement_inserter.
|
||||||
|
|
||||||
|
void
|
||||||
|
Statement_inserter::insert(Statement* s)
|
||||||
|
{
|
||||||
|
if (this->block_ != NULL)
|
||||||
|
{
|
||||||
|
go_assert(this->pindex_ != NULL);
|
||||||
|
this->block_->insert_statement_before(*this->pindex_, s);
|
||||||
|
++*this->pindex_;
|
||||||
|
}
|
||||||
|
else if (this->var_ != NULL)
|
||||||
|
this->var_->add_preinit_statement(this->gogo_, s);
|
||||||
|
else
|
||||||
|
go_unreachable();
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#define GO_GOGO_H
|
#define GO_GOGO_H
|
||||||
|
|
||||||
class Traverse;
|
class Traverse;
|
||||||
|
class Statement_inserter;
|
||||||
class Type;
|
class Type;
|
||||||
class Type_hash_identical;
|
class Type_hash_identical;
|
||||||
class Type_equal;
|
class Type_equal;
|
||||||
|
@ -366,7 +367,7 @@ class Gogo
|
||||||
|
|
||||||
// Lower an expression.
|
// Lower an expression.
|
||||||
void
|
void
|
||||||
lower_expression(Named_object* function, Expression**);
|
lower_expression(Named_object* function, Statement_inserter*, Expression**);
|
||||||
|
|
||||||
// Lower a constant.
|
// Lower a constant.
|
||||||
void
|
void
|
||||||
|
@ -1157,7 +1158,7 @@ class Variable
|
||||||
|
|
||||||
// Lower the initialization expression after parsing is complete.
|
// Lower the initialization expression after parsing is complete.
|
||||||
void
|
void
|
||||||
lower_init_expression(Gogo*, Named_object*);
|
lower_init_expression(Gogo*, Named_object*, Statement_inserter*);
|
||||||
|
|
||||||
// A special case: the init value is used only to determine the
|
// A special case: the init value is used only to determine the
|
||||||
// type. This is used if the variable is defined using := with the
|
// type. This is used if the variable is defined using := with the
|
||||||
|
@ -1208,7 +1209,7 @@ class Variable
|
||||||
|
|
||||||
// Traverse the initializer expression.
|
// Traverse the initializer expression.
|
||||||
int
|
int
|
||||||
traverse_expression(Traverse*);
|
traverse_expression(Traverse*, unsigned int traverse_mask);
|
||||||
|
|
||||||
// Determine the type of the variable if necessary.
|
// Determine the type of the variable if necessary.
|
||||||
void
|
void
|
||||||
|
@ -2463,6 +2464,46 @@ class Traverse
|
||||||
Expressions_seen* expressions_seen_;
|
Expressions_seen* expressions_seen_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A class which makes it easier to insert new statements before the
|
||||||
|
// current statement during a traversal.
|
||||||
|
|
||||||
|
class Statement_inserter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Empty constructor.
|
||||||
|
Statement_inserter()
|
||||||
|
: block_(NULL), pindex_(NULL), gogo_(NULL), var_(NULL)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
// Constructor for a statement in a block.
|
||||||
|
Statement_inserter(Block* block, size_t *pindex)
|
||||||
|
: block_(block), pindex_(pindex), gogo_(NULL), var_(NULL)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
// Constructor for a global variable.
|
||||||
|
Statement_inserter(Gogo* gogo, Variable* var)
|
||||||
|
: block_(NULL), pindex_(NULL), gogo_(gogo), var_(var)
|
||||||
|
{ go_assert(var->is_global()); }
|
||||||
|
|
||||||
|
// We use the default copy constructor and assignment operator.
|
||||||
|
|
||||||
|
// Insert S before the statement we are traversing, or before the
|
||||||
|
// initialization expression of a global variable.
|
||||||
|
void
|
||||||
|
insert(Statement* s);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// The block that the statement is in.
|
||||||
|
Block* block_;
|
||||||
|
// The index of the statement that we are traversing.
|
||||||
|
size_t* pindex_;
|
||||||
|
// The IR, needed when looking at an initializer expression for a
|
||||||
|
// global variable.
|
||||||
|
Gogo* gogo_;
|
||||||
|
// The global variable, when looking at an initializer expression.
|
||||||
|
Variable* var_;
|
||||||
|
};
|
||||||
|
|
||||||
// When translating the gogo IR into the backend data structure, this
|
// When translating the gogo IR into the backend data structure, this
|
||||||
// is the context we pass down the blocks and statements.
|
// is the context we pass down the blocks and statements.
|
||||||
|
|
||||||
|
|
|
@ -217,6 +217,16 @@ Variable_declaration_statement::do_traverse_assignments(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lower the variable's initialization expression.
|
||||||
|
|
||||||
|
Statement*
|
||||||
|
Variable_declaration_statement::do_lower(Gogo* gogo, Named_object* function,
|
||||||
|
Block*, Statement_inserter* inserter)
|
||||||
|
{
|
||||||
|
this->var_->var_value()->lower_init_expression(gogo, function, inserter);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
// Convert a variable declaration to the backend representation.
|
// Convert a variable declaration to the backend representation.
|
||||||
|
|
||||||
Bstatement*
|
Bstatement*
|
||||||
|
@ -244,7 +254,7 @@ Variable_declaration_statement::do_get_backend(Translate_context* context)
|
||||||
Expression_list* params = new Expression_list();
|
Expression_list* params = new Expression_list();
|
||||||
params->push_back(Expression::make_type(var->type(), loc));
|
params->push_back(Expression::make_type(var->type(), loc));
|
||||||
Expression* call = Expression::make_call(func, params, false, loc);
|
Expression* call = Expression::make_call(func, params, false, loc);
|
||||||
context->gogo()->lower_expression(context->function(), &call);
|
context->gogo()->lower_expression(context->function(), NULL, &call);
|
||||||
Temporary_statement* temp = Statement::make_temporary(NULL, call, loc);
|
Temporary_statement* temp = Statement::make_temporary(NULL, call, loc);
|
||||||
Bstatement* btemp = temp->get_backend(context);
|
Bstatement* btemp = temp->get_backend(context);
|
||||||
|
|
||||||
|
@ -386,7 +396,7 @@ Temporary_statement::do_get_backend(Translate_context* context)
|
||||||
{
|
{
|
||||||
Expression* init = Expression::make_cast(this->type_, this->init_,
|
Expression* init = Expression::make_cast(this->type_, this->init_,
|
||||||
this->location());
|
this->location());
|
||||||
context->gogo()->lower_expression(context->function(), &init);
|
context->gogo()->lower_expression(context->function(), NULL, &init);
|
||||||
binit = tree_to_expr(init->get_tree(context));
|
binit = tree_to_expr(init->get_tree(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,7 +608,7 @@ class Assignment_operation_statement : public Statement
|
||||||
{ go_unreachable(); }
|
{ go_unreachable(); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Named_object*, Block*);
|
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
|
||||||
|
|
||||||
Bstatement*
|
Bstatement*
|
||||||
do_get_backend(Translate_context*)
|
do_get_backend(Translate_context*)
|
||||||
|
@ -628,7 +638,7 @@ Assignment_operation_statement::do_traverse(Traverse* traverse)
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Assignment_operation_statement::do_lower(Gogo*, Named_object*,
|
Assignment_operation_statement::do_lower(Gogo*, Named_object*,
|
||||||
Block* enclosing)
|
Block* enclosing, Statement_inserter*)
|
||||||
{
|
{
|
||||||
source_location loc = this->location();
|
source_location loc = this->location();
|
||||||
|
|
||||||
|
@ -725,7 +735,7 @@ class Tuple_assignment_statement : public Statement
|
||||||
{ go_unreachable(); }
|
{ go_unreachable(); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Named_object*, Block*);
|
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
|
||||||
|
|
||||||
Bstatement*
|
Bstatement*
|
||||||
do_get_backend(Translate_context*)
|
do_get_backend(Translate_context*)
|
||||||
|
@ -752,7 +762,8 @@ Tuple_assignment_statement::do_traverse(Traverse* traverse)
|
||||||
// up into a set of single assignments.
|
// up into a set of single assignments.
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
|
Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
|
||||||
|
Statement_inserter*)
|
||||||
{
|
{
|
||||||
source_location loc = this->location();
|
source_location loc = this->location();
|
||||||
|
|
||||||
|
@ -852,7 +863,7 @@ public:
|
||||||
{ go_unreachable(); }
|
{ go_unreachable(); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Named_object*, Block*);
|
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
|
||||||
|
|
||||||
Bstatement*
|
Bstatement*
|
||||||
do_get_backend(Translate_context*)
|
do_get_backend(Translate_context*)
|
||||||
|
@ -882,7 +893,7 @@ Tuple_map_assignment_statement::do_traverse(Traverse* traverse)
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Tuple_map_assignment_statement::do_lower(Gogo*, Named_object*,
|
Tuple_map_assignment_statement::do_lower(Gogo*, Named_object*,
|
||||||
Block* enclosing)
|
Block* enclosing, Statement_inserter*)
|
||||||
{
|
{
|
||||||
source_location loc = this->location();
|
source_location loc = this->location();
|
||||||
|
|
||||||
|
@ -923,7 +934,8 @@ Tuple_map_assignment_statement::do_lower(Gogo*, Named_object*,
|
||||||
b->add_statement(present_temp);
|
b->add_statement(present_temp);
|
||||||
|
|
||||||
// present_temp = mapaccess2(MAP, &key_temp, &val_temp)
|
// present_temp = mapaccess2(MAP, &key_temp, &val_temp)
|
||||||
Expression* ref = Expression::make_temporary_reference(key_temp, loc);
|
Temporary_reference_expression* ref =
|
||||||
|
Expression::make_temporary_reference(key_temp, loc);
|
||||||
Expression* a1 = Expression::make_unary(OPERATOR_AND, ref, loc);
|
Expression* a1 = Expression::make_unary(OPERATOR_AND, ref, loc);
|
||||||
ref = Expression::make_temporary_reference(val_temp, loc);
|
ref = Expression::make_temporary_reference(val_temp, loc);
|
||||||
Expression* a2 = Expression::make_unary(OPERATOR_AND, ref, loc);
|
Expression* a2 = Expression::make_unary(OPERATOR_AND, ref, loc);
|
||||||
|
@ -931,6 +943,7 @@ Tuple_map_assignment_statement::do_lower(Gogo*, Named_object*,
|
||||||
map_index->map(), a1, a2);
|
map_index->map(), a1, a2);
|
||||||
|
|
||||||
ref = Expression::make_temporary_reference(present_temp, loc);
|
ref = Expression::make_temporary_reference(present_temp, loc);
|
||||||
|
ref->set_is_lvalue();
|
||||||
Statement* s = Statement::make_assignment(ref, call, loc);
|
Statement* s = Statement::make_assignment(ref, call, loc);
|
||||||
b->add_statement(s);
|
b->add_statement(s);
|
||||||
|
|
||||||
|
@ -979,7 +992,7 @@ class Map_assignment_statement : public Statement
|
||||||
{ go_unreachable(); }
|
{ go_unreachable(); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Named_object*, Block*);
|
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
|
||||||
|
|
||||||
Bstatement*
|
Bstatement*
|
||||||
do_get_backend(Translate_context*)
|
do_get_backend(Translate_context*)
|
||||||
|
@ -1008,7 +1021,8 @@ Map_assignment_statement::do_traverse(Traverse* traverse)
|
||||||
// Lower a map assignment to a function call.
|
// Lower a map assignment to a function call.
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Map_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
|
Map_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
|
||||||
|
Statement_inserter*)
|
||||||
{
|
{
|
||||||
source_location loc = this->location();
|
source_location loc = this->location();
|
||||||
|
|
||||||
|
@ -1093,7 +1107,7 @@ class Tuple_receive_assignment_statement : public Statement
|
||||||
{ go_unreachable(); }
|
{ go_unreachable(); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Named_object*, Block*);
|
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
|
||||||
|
|
||||||
Bstatement*
|
Bstatement*
|
||||||
do_get_backend(Translate_context*)
|
do_get_backend(Translate_context*)
|
||||||
|
@ -1125,7 +1139,8 @@ Tuple_receive_assignment_statement::do_traverse(Traverse* traverse)
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
|
Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
|
||||||
Block* enclosing)
|
Block* enclosing,
|
||||||
|
Statement_inserter*)
|
||||||
{
|
{
|
||||||
source_location loc = this->location();
|
source_location loc = this->location();
|
||||||
|
|
||||||
|
@ -1160,13 +1175,15 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
|
||||||
b->add_statement(closed_temp);
|
b->add_statement(closed_temp);
|
||||||
|
|
||||||
// closed_temp = chanrecv[23](channel, &val_temp)
|
// closed_temp = chanrecv[23](channel, &val_temp)
|
||||||
Expression* ref = Expression::make_temporary_reference(val_temp, loc);
|
Temporary_reference_expression* ref =
|
||||||
|
Expression::make_temporary_reference(val_temp, loc);
|
||||||
Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
|
Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
|
||||||
Expression* call = Runtime::make_call((this->for_select_
|
Expression* call = Runtime::make_call((this->for_select_
|
||||||
? Runtime::CHANRECV3
|
? Runtime::CHANRECV3
|
||||||
: Runtime::CHANRECV2),
|
: Runtime::CHANRECV2),
|
||||||
loc, 2, this->channel_, p2);
|
loc, 2, this->channel_, p2);
|
||||||
ref = Expression::make_temporary_reference(closed_temp, loc);
|
ref = Expression::make_temporary_reference(closed_temp, loc);
|
||||||
|
ref->set_is_lvalue();
|
||||||
Statement* s = Statement::make_assignment(ref, call, loc);
|
Statement* s = Statement::make_assignment(ref, call, loc);
|
||||||
b->add_statement(s);
|
b->add_statement(s);
|
||||||
|
|
||||||
|
@ -1217,7 +1234,7 @@ class Tuple_type_guard_assignment_statement : public Statement
|
||||||
{ go_unreachable(); }
|
{ go_unreachable(); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Named_object*, Block*);
|
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
|
||||||
|
|
||||||
Bstatement*
|
Bstatement*
|
||||||
do_get_backend(Translate_context*)
|
do_get_backend(Translate_context*)
|
||||||
|
@ -1256,7 +1273,8 @@ Tuple_type_guard_assignment_statement::do_traverse(Traverse* traverse)
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Tuple_type_guard_assignment_statement::do_lower(Gogo*, Named_object*,
|
Tuple_type_guard_assignment_statement::do_lower(Gogo*, Named_object*,
|
||||||
Block* enclosing)
|
Block* enclosing,
|
||||||
|
Statement_inserter*)
|
||||||
{
|
{
|
||||||
source_location loc = this->location();
|
source_location loc = this->location();
|
||||||
|
|
||||||
|
@ -1378,6 +1396,10 @@ class Expression_statement : public Statement
|
||||||
expr_(expr)
|
expr_(expr)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
Expression*
|
||||||
|
expr()
|
||||||
|
{ return this->expr_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int
|
int
|
||||||
do_traverse(Traverse* traverse)
|
do_traverse(Traverse* traverse)
|
||||||
|
@ -1513,7 +1535,7 @@ class Inc_dec_statement : public Statement
|
||||||
{ go_unreachable(); }
|
{ go_unreachable(); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Named_object*, Block*);
|
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
|
||||||
|
|
||||||
Bstatement*
|
Bstatement*
|
||||||
do_get_backend(Translate_context*)
|
do_get_backend(Translate_context*)
|
||||||
|
@ -1529,7 +1551,7 @@ class Inc_dec_statement : public Statement
|
||||||
// Lower to += or -=.
|
// Lower to += or -=.
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Inc_dec_statement::do_lower(Gogo*, Named_object*, Block*)
|
Inc_dec_statement::do_lower(Gogo*, Named_object*, Block*, Statement_inserter*)
|
||||||
{
|
{
|
||||||
source_location loc = this->location();
|
source_location loc = this->location();
|
||||||
|
|
||||||
|
@ -2017,6 +2039,8 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name,
|
||||||
Named_object* function = gogo->start_function(thunk_name, thunk_type, true,
|
Named_object* function = gogo->start_function(thunk_name, thunk_type, true,
|
||||||
location);
|
location);
|
||||||
|
|
||||||
|
gogo->start_block(location);
|
||||||
|
|
||||||
// For a defer statement, start with a call to
|
// For a defer statement, start with a call to
|
||||||
// __go_set_defer_retaddr. */
|
// __go_set_defer_retaddr. */
|
||||||
Label* retaddr_label = NULL;
|
Label* retaddr_label = NULL;
|
||||||
|
@ -2122,26 +2146,10 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name,
|
||||||
call_params = NULL;
|
call_params = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression* call = Expression::make_call(func_to_call, call_params, false,
|
Call_expression* call = Expression::make_call(func_to_call, call_params,
|
||||||
location);
|
false, location);
|
||||||
// We need to lower in case this is a builtin function.
|
|
||||||
call = call->lower(gogo, function, -1);
|
|
||||||
Call_expression* call_ce = call->call_expression();
|
|
||||||
if (call_ce != NULL && may_call_recover)
|
|
||||||
call_ce->set_is_deferred();
|
|
||||||
|
|
||||||
Statement* call_statement = Statement::make_statement(call);
|
Statement* call_statement = Statement::make_statement(call);
|
||||||
|
|
||||||
// We already ran the determine_types pass, so we need to run it
|
|
||||||
// just for this statement now.
|
|
||||||
call_statement->determine_types();
|
|
||||||
|
|
||||||
// Sanity check.
|
|
||||||
call->check_types(gogo);
|
|
||||||
|
|
||||||
if (call_ce != NULL && recover_arg != NULL)
|
|
||||||
call_ce->set_recover_arg(recover_arg);
|
|
||||||
|
|
||||||
gogo->add_statement(call_statement);
|
gogo->add_statement(call_statement);
|
||||||
|
|
||||||
// If this is a defer statement, the label comes immediately after
|
// If this is a defer statement, the label comes immediately after
|
||||||
|
@ -2155,6 +2163,31 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name,
|
||||||
gogo->add_statement(Statement::make_return_statement(vals, location));
|
gogo->add_statement(Statement::make_return_statement(vals, location));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Block* b = gogo->finish_block(location);
|
||||||
|
|
||||||
|
gogo->add_block(b, location);
|
||||||
|
|
||||||
|
gogo->lower_block(function, b);
|
||||||
|
|
||||||
|
// We already ran the determine_types pass, so we need to run it
|
||||||
|
// just for the call statement now. The other types are known.
|
||||||
|
call_statement->determine_types();
|
||||||
|
|
||||||
|
if (may_call_recover || recover_arg != NULL)
|
||||||
|
{
|
||||||
|
// Dig up the call expression, which may have been changed
|
||||||
|
// during lowering.
|
||||||
|
go_assert(call_statement->classification() == STATEMENT_EXPRESSION);
|
||||||
|
Expression_statement* es =
|
||||||
|
static_cast<Expression_statement*>(call_statement);
|
||||||
|
Call_expression* ce = es->expr()->call_expression();
|
||||||
|
go_assert(ce != NULL);
|
||||||
|
if (may_call_recover)
|
||||||
|
ce->set_is_deferred();
|
||||||
|
if (recover_arg != NULL)
|
||||||
|
ce->set_recover_arg(recover_arg);
|
||||||
|
}
|
||||||
|
|
||||||
// That is all the thunk has to do.
|
// That is all the thunk has to do.
|
||||||
gogo->finish_function(location);
|
gogo->finish_function(location);
|
||||||
}
|
}
|
||||||
|
@ -2265,7 +2298,8 @@ Return_statement::do_traverse_assignments(Traverse_assignments* tassign)
|
||||||
// panic/recover work correctly.
|
// panic/recover work correctly.
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing)
|
Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing,
|
||||||
|
Statement_inserter*)
|
||||||
{
|
{
|
||||||
if (this->is_lowered_)
|
if (this->is_lowered_)
|
||||||
return this;
|
return this;
|
||||||
|
@ -3305,7 +3339,8 @@ Switch_statement::do_traverse(Traverse* traverse)
|
||||||
// of if statements.
|
// of if statements.
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
|
Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
|
||||||
|
Statement_inserter*)
|
||||||
{
|
{
|
||||||
source_location loc = this->location();
|
source_location loc = this->location();
|
||||||
|
|
||||||
|
@ -3578,7 +3613,8 @@ Type_switch_statement::do_traverse(Traverse* traverse)
|
||||||
// equality testing.
|
// equality testing.
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Type_switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
|
Type_switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
|
||||||
|
Statement_inserter*)
|
||||||
{
|
{
|
||||||
const source_location loc = this->location();
|
const source_location loc = this->location();
|
||||||
|
|
||||||
|
@ -3629,8 +3665,9 @@ Type_switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
|
||||||
? Runtime::EFACETYPE
|
? Runtime::EFACETYPE
|
||||||
: Runtime::IFACETYPE),
|
: Runtime::IFACETYPE),
|
||||||
loc, 1, ref);
|
loc, 1, ref);
|
||||||
Expression* lhs = Expression::make_temporary_reference(descriptor_temp,
|
Temporary_reference_expression* lhs =
|
||||||
loc);
|
Expression::make_temporary_reference(descriptor_temp, loc);
|
||||||
|
lhs->set_is_lvalue();
|
||||||
Statement* s = Statement::make_assignment(lhs, call, loc);
|
Statement* s = Statement::make_assignment(lhs, call, loc);
|
||||||
b->add_statement(s);
|
b->add_statement(s);
|
||||||
}
|
}
|
||||||
|
@ -3815,7 +3852,7 @@ Send_statement::do_get_backend(Translate_context* context)
|
||||||
call = Runtime::make_call(code, loc, 3, this->channel_, val,
|
call = Runtime::make_call(code, loc, 3, this->channel_, val,
|
||||||
Expression::make_boolean(this->for_select_, loc));
|
Expression::make_boolean(this->for_select_, loc));
|
||||||
|
|
||||||
context->gogo()->lower_expression(context->function(), &call);
|
context->gogo()->lower_expression(context->function(), NULL, &call);
|
||||||
Bexpression* bcall = tree_to_expr(call->get_tree(context));
|
Bexpression* bcall = tree_to_expr(call->get_tree(context));
|
||||||
Bstatement* s = context->backend()->expression_statement(bcall);
|
Bstatement* s = context->backend()->expression_statement(bcall);
|
||||||
|
|
||||||
|
@ -4154,7 +4191,7 @@ Select_clauses::get_backend(Translate_context* context,
|
||||||
Expression* nil2 = nil1->copy();
|
Expression* nil2 = nil1->copy();
|
||||||
Expression* call = Runtime::make_call(Runtime::SELECT, location, 4,
|
Expression* call = Runtime::make_call(Runtime::SELECT, location, 4,
|
||||||
zero, default_arg, nil1, nil2);
|
zero, default_arg, nil1, nil2);
|
||||||
context->gogo()->lower_expression(context->function(), &call);
|
context->gogo()->lower_expression(context->function(), NULL, &call);
|
||||||
Bexpression* bcall = tree_to_expr(call->get_tree(context));
|
Bexpression* bcall = tree_to_expr(call->get_tree(context));
|
||||||
s = context->backend()->expression_statement(bcall);
|
s = context->backend()->expression_statement(bcall);
|
||||||
}
|
}
|
||||||
|
@ -4175,7 +4212,7 @@ Select_clauses::get_backend(Translate_context* context,
|
||||||
Expression* chans = Expression::make_composite_literal(chan_array_type, 0,
|
Expression* chans = Expression::make_composite_literal(chan_array_type, 0,
|
||||||
false, chan_init,
|
false, chan_init,
|
||||||
location);
|
location);
|
||||||
context->gogo()->lower_expression(context->function(), &chans);
|
context->gogo()->lower_expression(context->function(), NULL, &chans);
|
||||||
Temporary_statement* chan_temp = Statement::make_temporary(chan_array_type,
|
Temporary_statement* chan_temp = Statement::make_temporary(chan_array_type,
|
||||||
chans,
|
chans,
|
||||||
location);
|
location);
|
||||||
|
@ -4187,7 +4224,7 @@ Select_clauses::get_backend(Translate_context* context,
|
||||||
0, false,
|
0, false,
|
||||||
is_send_init,
|
is_send_init,
|
||||||
location);
|
location);
|
||||||
context->gogo()->lower_expression(context->function(), &is_sends);
|
context->gogo()->lower_expression(context->function(), NULL, &is_sends);
|
||||||
Temporary_statement* is_send_temp =
|
Temporary_statement* is_send_temp =
|
||||||
Statement::make_temporary(is_send_array_type, is_sends, location);
|
Statement::make_temporary(is_send_array_type, is_sends, location);
|
||||||
statements.push_back(is_send_temp->get_backend(context));
|
statements.push_back(is_send_temp->get_backend(context));
|
||||||
|
@ -4213,7 +4250,7 @@ Select_clauses::get_backend(Translate_context* context,
|
||||||
Expression* call = Runtime::make_call(Runtime::SELECT, location, 4,
|
Expression* call = Runtime::make_call(Runtime::SELECT, location, 4,
|
||||||
ecount->copy(), default_arg,
|
ecount->copy(), default_arg,
|
||||||
chan_arg, is_send_arg);
|
chan_arg, is_send_arg);
|
||||||
context->gogo()->lower_expression(context->function(), &call);
|
context->gogo()->lower_expression(context->function(), NULL, &call);
|
||||||
Bexpression* bcall = tree_to_expr(call->get_tree(context));
|
Bexpression* bcall = tree_to_expr(call->get_tree(context));
|
||||||
|
|
||||||
std::vector<std::vector<Bexpression*> > cases;
|
std::vector<std::vector<Bexpression*> > cases;
|
||||||
|
@ -4309,7 +4346,7 @@ Select_statement::break_label()
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Select_statement::do_lower(Gogo* gogo, Named_object* function,
|
Select_statement::do_lower(Gogo* gogo, Named_object* function,
|
||||||
Block* enclosing)
|
Block* enclosing, Statement_inserter*)
|
||||||
{
|
{
|
||||||
if (this->is_lowered_)
|
if (this->is_lowered_)
|
||||||
return this;
|
return this;
|
||||||
|
@ -4366,7 +4403,8 @@ For_statement::do_traverse(Traverse* traverse)
|
||||||
// complex statements make it easier to handle garbage collection.
|
// complex statements make it easier to handle garbage collection.
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
For_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
|
For_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
|
||||||
|
Statement_inserter*)
|
||||||
{
|
{
|
||||||
Statement* s;
|
Statement* s;
|
||||||
source_location loc = this->location();
|
source_location loc = this->location();
|
||||||
|
@ -4497,7 +4535,8 @@ For_range_statement::do_traverse(Traverse* traverse)
|
||||||
// statements.
|
// statements.
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing)
|
For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
|
||||||
|
Statement_inserter*)
|
||||||
{
|
{
|
||||||
Type* range_type = this->range_->type();
|
Type* range_type = this->range_->type();
|
||||||
if (range_type->points_to() != NULL
|
if (range_type->points_to() != NULL
|
||||||
|
@ -4711,8 +4750,10 @@ For_range_statement::lower_range_array(Gogo* gogo,
|
||||||
Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
|
Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
|
||||||
mpz_clear(zval);
|
mpz_clear(zval);
|
||||||
|
|
||||||
ref = Expression::make_temporary_reference(index_temp, loc);
|
Temporary_reference_expression* tref =
|
||||||
Statement* s = Statement::make_assignment(ref, zexpr, loc);
|
Expression::make_temporary_reference(index_temp, loc);
|
||||||
|
tref->set_is_lvalue();
|
||||||
|
Statement* s = Statement::make_assignment(tref, zexpr, loc);
|
||||||
init->add_statement(s);
|
init->add_statement(s);
|
||||||
|
|
||||||
*pinit = init;
|
*pinit = init;
|
||||||
|
@ -4738,8 +4779,9 @@ For_range_statement::lower_range_array(Gogo* gogo,
|
||||||
Expression* ref2 = Expression::make_temporary_reference(index_temp, loc);
|
Expression* ref2 = Expression::make_temporary_reference(index_temp, loc);
|
||||||
Expression* index = Expression::make_index(ref, ref2, NULL, loc);
|
Expression* index = Expression::make_index(ref, ref2, NULL, loc);
|
||||||
|
|
||||||
ref = Expression::make_temporary_reference(value_temp, loc);
|
tref = Expression::make_temporary_reference(value_temp, loc);
|
||||||
s = Statement::make_assignment(ref, index, loc);
|
tref->set_is_lvalue();
|
||||||
|
s = Statement::make_assignment(tref, index, loc);
|
||||||
|
|
||||||
iter_init->add_statement(s);
|
iter_init->add_statement(s);
|
||||||
}
|
}
|
||||||
|
@ -4749,8 +4791,9 @@ For_range_statement::lower_range_array(Gogo* gogo,
|
||||||
// index_temp++
|
// index_temp++
|
||||||
|
|
||||||
Block* post = new Block(enclosing, loc);
|
Block* post = new Block(enclosing, loc);
|
||||||
ref = Expression::make_temporary_reference(index_temp, loc);
|
tref = Expression::make_temporary_reference(index_temp, loc);
|
||||||
s = Statement::make_inc_statement(ref);
|
tref->set_is_lvalue();
|
||||||
|
s = Statement::make_inc_statement(tref);
|
||||||
post->add_statement(s);
|
post->add_statement(s);
|
||||||
*ppost = post;
|
*ppost = post;
|
||||||
}
|
}
|
||||||
|
@ -4798,7 +4841,9 @@ For_range_statement::lower_range_string(Gogo*,
|
||||||
mpz_init_set_ui(zval, 0UL);
|
mpz_init_set_ui(zval, 0UL);
|
||||||
Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
|
Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
|
||||||
|
|
||||||
Expression* ref = Expression::make_temporary_reference(index_temp, loc);
|
Temporary_reference_expression* ref =
|
||||||
|
Expression::make_temporary_reference(index_temp, loc);
|
||||||
|
ref->set_is_lvalue();
|
||||||
Statement* s = Statement::make_assignment(ref, zexpr, loc);
|
Statement* s = Statement::make_assignment(ref, zexpr, loc);
|
||||||
|
|
||||||
init->add_statement(s);
|
init->add_statement(s);
|
||||||
|
@ -4829,14 +4874,20 @@ For_range_statement::lower_range_string(Gogo*,
|
||||||
if (value_temp == NULL)
|
if (value_temp == NULL)
|
||||||
{
|
{
|
||||||
ref = Expression::make_temporary_reference(next_index_temp, loc);
|
ref = Expression::make_temporary_reference(next_index_temp, loc);
|
||||||
|
ref->set_is_lvalue();
|
||||||
s = Statement::make_assignment(ref, call, loc);
|
s = Statement::make_assignment(ref, call, loc);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Expression_list* lhs = new Expression_list();
|
Expression_list* lhs = new Expression_list();
|
||||||
lhs->push_back(Expression::make_temporary_reference(next_index_temp,
|
|
||||||
loc));
|
ref = Expression::make_temporary_reference(next_index_temp, loc);
|
||||||
lhs->push_back(Expression::make_temporary_reference(value_temp, loc));
|
ref->set_is_lvalue();
|
||||||
|
lhs->push_back(ref);
|
||||||
|
|
||||||
|
ref = Expression::make_temporary_reference(value_temp, loc);
|
||||||
|
ref->set_is_lvalue();
|
||||||
|
lhs->push_back(ref);
|
||||||
|
|
||||||
Expression_list* rhs = new Expression_list();
|
Expression_list* rhs = new Expression_list();
|
||||||
rhs->push_back(Expression::make_call_result(call, 0));
|
rhs->push_back(Expression::make_call_result(call, 0));
|
||||||
|
@ -4865,7 +4916,9 @@ For_range_statement::lower_range_string(Gogo*,
|
||||||
|
|
||||||
Block* post = new Block(enclosing, loc);
|
Block* post = new Block(enclosing, loc);
|
||||||
|
|
||||||
Expression* lhs = Expression::make_temporary_reference(index_temp, loc);
|
Temporary_reference_expression* lhs =
|
||||||
|
Expression::make_temporary_reference(index_temp, loc);
|
||||||
|
lhs->set_is_lvalue();
|
||||||
Expression* rhs = Expression::make_temporary_reference(next_index_temp, loc);
|
Expression* rhs = Expression::make_temporary_reference(next_index_temp, loc);
|
||||||
s = Statement::make_assignment(lhs, rhs, loc);
|
s = Statement::make_assignment(lhs, rhs, loc);
|
||||||
|
|
||||||
|
@ -5024,8 +5077,12 @@ For_range_statement::lower_range_channel(Gogo*,
|
||||||
iter_init->add_statement(ok_temp);
|
iter_init->add_statement(ok_temp);
|
||||||
|
|
||||||
Expression* cref = this->make_range_ref(range_object, range_temp, loc);
|
Expression* cref = this->make_range_ref(range_object, range_temp, loc);
|
||||||
Expression* iref = Expression::make_temporary_reference(index_temp, loc);
|
Temporary_reference_expression* iref =
|
||||||
Expression* oref = Expression::make_temporary_reference(ok_temp, loc);
|
Expression::make_temporary_reference(index_temp, loc);
|
||||||
|
iref->set_is_lvalue();
|
||||||
|
Temporary_reference_expression* oref =
|
||||||
|
Expression::make_temporary_reference(ok_temp, loc);
|
||||||
|
oref->set_is_lvalue();
|
||||||
Statement* s = Statement::make_tuple_receive_assignment(iref, oref, cref,
|
Statement* s = Statement::make_tuple_receive_assignment(iref, oref, cref,
|
||||||
false, loc);
|
false, loc);
|
||||||
iter_init->add_statement(s);
|
iter_init->add_statement(s);
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
class Gogo;
|
class Gogo;
|
||||||
class Traverse;
|
class Traverse;
|
||||||
|
class Statement_inserter;
|
||||||
class Block;
|
class Block;
|
||||||
class Function;
|
class Function;
|
||||||
class Unnamed_label;
|
class Unnamed_label;
|
||||||
|
@ -290,9 +291,11 @@ class Statement
|
||||||
// simplify statements for further processing. It returns the same
|
// simplify statements for further processing. It returns the same
|
||||||
// Statement or a new one. FUNCTION is the function containing this
|
// Statement or a new one. FUNCTION is the function containing this
|
||||||
// statement. BLOCK is the block containing this statement.
|
// statement. BLOCK is the block containing this statement.
|
||||||
|
// INSERTER can be used to insert new statements before this one.
|
||||||
Statement*
|
Statement*
|
||||||
lower(Gogo* gogo, Named_object* function, Block* block)
|
lower(Gogo* gogo, Named_object* function, Block* block,
|
||||||
{ return this->do_lower(gogo, function, block); }
|
Statement_inserter* inserter)
|
||||||
|
{ return this->do_lower(gogo, function, block, inserter); }
|
||||||
|
|
||||||
// Set type information for unnamed constants.
|
// Set type information for unnamed constants.
|
||||||
void
|
void
|
||||||
|
@ -385,7 +388,7 @@ class Statement
|
||||||
// Implemented by the child class: lower this statement to a simpler
|
// Implemented by the child class: lower this statement to a simpler
|
||||||
// one.
|
// one.
|
||||||
virtual Statement*
|
virtual Statement*
|
||||||
do_lower(Gogo*, Named_object*, Block*)
|
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*)
|
||||||
{ return this; }
|
{ return this; }
|
||||||
|
|
||||||
// Implemented by child class: set type information for unnamed
|
// Implemented by child class: set type information for unnamed
|
||||||
|
@ -535,6 +538,9 @@ class Variable_declaration_statement : public Statement
|
||||||
bool
|
bool
|
||||||
do_traverse_assignments(Traverse_assignments*);
|
do_traverse_assignments(Traverse_assignments*);
|
||||||
|
|
||||||
|
Statement*
|
||||||
|
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
|
||||||
|
|
||||||
Bstatement*
|
Bstatement*
|
||||||
do_get_backend(Translate_context*);
|
do_get_backend(Translate_context*);
|
||||||
|
|
||||||
|
@ -566,7 +572,7 @@ class Return_statement : public Statement
|
||||||
do_traverse_assignments(Traverse_assignments*);
|
do_traverse_assignments(Traverse_assignments*);
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Named_object*, Block*);
|
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
do_may_fall_through() const
|
do_may_fall_through() const
|
||||||
|
@ -806,7 +812,7 @@ class Select_statement : public Statement
|
||||||
{ return this->clauses_->traverse(traverse); }
|
{ return this->clauses_->traverse(traverse); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Named_object*, Block*);
|
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
|
||||||
|
|
||||||
void
|
void
|
||||||
do_determine_types()
|
do_determine_types()
|
||||||
|
@ -993,7 +999,7 @@ class For_statement : public Statement
|
||||||
{ go_unreachable(); }
|
{ go_unreachable(); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Named_object*, Block*);
|
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
|
||||||
|
|
||||||
Bstatement*
|
Bstatement*
|
||||||
do_get_backend(Translate_context*)
|
do_get_backend(Translate_context*)
|
||||||
|
@ -1051,7 +1057,7 @@ class For_range_statement : public Statement
|
||||||
{ go_unreachable(); }
|
{ go_unreachable(); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Named_object*, Block*);
|
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
|
||||||
|
|
||||||
Bstatement*
|
Bstatement*
|
||||||
do_get_backend(Translate_context*)
|
do_get_backend(Translate_context*)
|
||||||
|
@ -1280,7 +1286,7 @@ class Switch_statement : public Statement
|
||||||
do_traverse(Traverse*);
|
do_traverse(Traverse*);
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Named_object*, Block*);
|
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
|
||||||
|
|
||||||
Bstatement*
|
Bstatement*
|
||||||
do_get_backend(Translate_context*)
|
do_get_backend(Translate_context*)
|
||||||
|
@ -1426,7 +1432,7 @@ class Type_switch_statement : public Statement
|
||||||
do_traverse(Traverse*);
|
do_traverse(Traverse*);
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Named_object*, Block*);
|
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
|
||||||
|
|
||||||
Bstatement*
|
Bstatement*
|
||||||
do_get_backend(Translate_context*)
|
do_get_backend(Translate_context*)
|
||||||
|
|
Loading…
Reference in New Issue