aboutsummaryrefslogtreecommitdiff
path: root/gcc/go/gofrontend/statements.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/go/gofrontend/statements.cc')
-rw-r--r--gcc/go/gofrontend/statements.cc1198
1 files changed, 893 insertions, 305 deletions
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index 5d652a1..e9675eb 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -134,7 +134,7 @@ Statement::import_statement(Import_function_body* ifb, Location loc)
// After lowering return statements have no expressions. The
// return expressions are assigned to result parameters.
ifb->advance(6);
- return Statement::make_return_statement(NULL, loc);
+ return Statement::make_return_statement(ifb->function(), NULL, loc);
}
else if (ifb->match_c_string("var $t"))
return Temporary_statement::do_import(ifb, loc);
@@ -278,6 +278,12 @@ Variable_declaration_statement::do_traverse(Traverse*)
return TRAVERSE_CONTINUE;
}
+void
+Variable_declaration_statement::do_determine_types(Gogo* gogo)
+{
+ this->var_->var_value()->determine_type(gogo);
+}
+
// Lower the variable's initialization expression.
Statement*
@@ -327,6 +333,8 @@ Variable_declaration_statement::do_add_conversions()
Bstatement*
Variable_declaration_statement::do_get_backend(Translate_context* context)
{
+ if (this->var_->is_redefinition())
+ return context->backend()->error_statement();
Bfunction* bfunction = context->function()->func_value()->get_decl();
Variable* var = this->var_->var_value();
Bvariable* bvar = this->var_->get_backend_variable(context->gogo(),
@@ -969,7 +977,9 @@ Assignment_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
Expression::make_dereference(call, Expression::NIL_CHECK_NOT_NEEDED,
loc);
ref = Expression::make_temporary_reference(val_temp, loc);
- b->add_statement(Statement::make_assignment(indir, ref, loc));
+ Statement* s = Statement::make_assignment(indir, ref, loc);
+ s->determine_types(gogo);
+ b->add_statement(s);
return Statement::make_block_statement(b, loc);
}
@@ -1017,45 +1027,59 @@ Assignment_statement::do_determine_types(Gogo* gogo)
this->rhs_->determine_type(gogo, &context);
}
-// Check types for an assignment.
+// Check types for an assignment from RHS to LHS. Returns true if the
+// assignment is OK.
-void
-Assignment_statement::do_check_types(Gogo*)
+bool
+Assignment_statement::check_assignment_types(Expression* lhs,
+ Type* rhs_type,
+ Location loc)
{
// The left hand side must be either addressable, a map index
// expression, or the blank identifier.
- if (!this->lhs_->is_addressable()
- && this->lhs_->map_index_expression() == NULL
- && !this->lhs_->is_sink_expression())
+ if (!lhs->is_addressable()
+ && !Index_expression::is_map_index(lhs)
+ && !lhs->is_sink_expression())
{
- if (!this->lhs_->type()->is_error())
- this->report_error(_("invalid left hand side of assignment"));
- return;
+ if (!lhs->type()->is_error())
+ go_error_at(lhs->location(), "invalid left hand side of assignment");
+ return false;
}
- Type* lhs_type = this->lhs_->type();
- Type* rhs_type = this->rhs_->type();
+ Type* lhs_type = lhs->type();
- // Invalid assignment of nil to the blank identifier.
- if (lhs_type->is_sink_type()
- && rhs_type->is_nil_type())
+ // Check for invalid assignment of nil to the blank identifier.
+ if (lhs_type->is_sink_type() && rhs_type->is_nil_type())
{
- this->report_error(_("use of untyped nil"));
- return;
+ go_error_at(loc, "use of untyped nil");
+ return false;
}
std::string reason;
if (!Type::are_assignable(lhs_type, rhs_type, &reason))
{
if (reason.empty())
- go_error_at(this->location(), "incompatible types in assignment");
+ go_error_at(loc, "incompatible types in assignment");
else
- go_error_at(this->location(), "incompatible types in assignment (%s)",
+ go_error_at(loc, "incompatible types in assignment (%s)",
reason.c_str());
- this->set_is_error();
+ return false;
}
- if (lhs_type->is_error() || rhs_type->is_error())
+ if (lhs_type->is_error_type() || rhs_type->is_error_type())
+ return false;
+
+ return true;
+}
+
+// Check types for an assignment.
+
+void
+Assignment_statement::do_check_types(Gogo*)
+{
+ if (!Assignment_statement::check_assignment_types(this->lhs_,
+ this->rhs_->type(),
+ this->location()))
this->set_is_error();
}
@@ -1173,6 +1197,12 @@ class Assignment_operation_statement : public Statement
int
do_traverse(Traverse*);
+ void
+ do_determine_types(Gogo*);
+
+ void
+ do_check_types(Gogo*);
+
Statement*
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
@@ -1184,6 +1214,9 @@ class Assignment_operation_statement : public Statement
do_dump_statement(Ast_dump_context*) const;
private:
+ Operator
+ get_binop();
+
// The operator (OPERATOR_PLUSEQ, etc.).
Operator op_;
// Left hand side.
@@ -1202,11 +1235,137 @@ Assignment_operation_statement::do_traverse(Traverse* traverse)
return this->traverse_expression(traverse, &this->rhs_);
}
+void
+Assignment_operation_statement::do_determine_types(Gogo* gogo)
+{
+ this->lhs_->determine_type_no_context(gogo);
+ Type* rhs_context_type = this->lhs_->type();
+ if (rhs_context_type->is_sink_type())
+ rhs_context_type = NULL;
+ Type_context context(rhs_context_type, false);
+ this->rhs_->determine_type(gogo, &context);
+}
+
+// Get the binary operator from the assignment operator.
+
+Operator
+Assignment_operation_statement::get_binop()
+{
+ switch (this->op_)
+ {
+ case OPERATOR_PLUSEQ:
+ return OPERATOR_PLUS;
+ case OPERATOR_MINUSEQ:
+ return OPERATOR_MINUS;
+ case OPERATOR_OREQ:
+ return OPERATOR_OR;
+ case OPERATOR_XOREQ:
+ return OPERATOR_XOR;
+ case OPERATOR_MULTEQ:
+ return OPERATOR_MULT;
+ case OPERATOR_DIVEQ:
+ return OPERATOR_DIV;
+ case OPERATOR_MODEQ:
+ return OPERATOR_MOD;
+ case OPERATOR_LSHIFTEQ:
+ return OPERATOR_LSHIFT;
+ case OPERATOR_RSHIFTEQ:
+ return OPERATOR_RSHIFT;
+ case OPERATOR_ANDEQ:
+ return OPERATOR_AND;
+ case OPERATOR_BITCLEAREQ:
+ return OPERATOR_BITCLEAR;
+ default:
+ go_unreachable();
+ }
+}
+
+void
+Assignment_operation_statement::do_check_types(Gogo*)
+{
+ if (this->lhs_->is_sink_expression())
+ {
+ this->report_error(_("cannot use %<_%> as value"));
+ return;
+ }
+
+
+ Type* lhs_type = this->lhs_->type();
+ Type* rhs_type = this->rhs_->type();
+
+ if (!this->lhs_->is_addressable()
+ && !Index_expression::is_map_index(this->lhs_))
+ {
+ if (!lhs_type->is_error())
+ this->report_error(_("invalid left hand side of assignment"));
+ this->set_is_error();
+ return;
+ }
+
+ if (this->op_ != OPERATOR_LSHIFTEQ && this->op_ != OPERATOR_RSHIFTEQ)
+ {
+ if (!Type::are_compatible_for_binop(lhs_type, rhs_type))
+ {
+ this->report_error(_("incompatible type in binary expression"));
+ return;
+ }
+ if (!Binary_expression::check_operator_type(this->get_binop(), lhs_type,
+ rhs_type, this->location()))
+ {
+ this->set_is_error();
+ return;
+ }
+ if (this->op_ == OPERATOR_DIVEQ || this->op_ == OPERATOR_MODEQ)
+ {
+ Numeric_constant rconst;
+ unsigned long rval;
+ if (lhs_type->integer_type() != NULL
+ && this->rhs_->numeric_constant_value(&rconst)
+ && rconst.to_unsigned_long(&rval) == Numeric_constant::NC_UL_VALID
+ && rval == 0)
+ {
+ this->report_error(_("integer division by zero"));
+ return;
+ }
+ }
+ }
+ else
+ {
+ if (lhs_type->integer_type() == NULL)
+ {
+ this->report_error(_("shift of non-integer operand"));
+ return;
+ }
+
+ if (rhs_type->is_string_type()
+ || (!rhs_type->is_abstract()
+ && rhs_type->integer_type() == NULL))
+ {
+ this->report_error(_("shift count not integer"));
+ return;
+ }
+
+ Numeric_constant nc;
+ if (this->rhs_->numeric_constant_value(&nc))
+ {
+ mpz_t val;
+ if (!nc.to_int(&val))
+ {
+ this->report_error(_("shift count not integer"));
+ return;
+ }
+ if (mpz_sgn(val) < 0)
+ this->report_error(_("negative shift count"));
+ mpz_clear(val);
+ }
+ }
+}
+
// Lower an assignment operation statement to a regular assignment
// statement.
Statement*
-Assignment_operation_statement::do_lower(Gogo*, Named_object*,
+Assignment_operation_statement::do_lower(Gogo* gogo, Named_object*,
Block* enclosing, Statement_inserter*)
{
Location loc = this->location();
@@ -1229,48 +1388,10 @@ Assignment_operation_statement::do_lower(Gogo*, Named_object*,
Expression* lval = this->lhs_->copy();
- Operator op;
- switch (this->op_)
- {
- case OPERATOR_PLUSEQ:
- op = OPERATOR_PLUS;
- break;
- case OPERATOR_MINUSEQ:
- op = OPERATOR_MINUS;
- break;
- case OPERATOR_OREQ:
- op = OPERATOR_OR;
- break;
- case OPERATOR_XOREQ:
- op = OPERATOR_XOR;
- break;
- case OPERATOR_MULTEQ:
- op = OPERATOR_MULT;
- break;
- case OPERATOR_DIVEQ:
- op = OPERATOR_DIV;
- break;
- case OPERATOR_MODEQ:
- op = OPERATOR_MOD;
- break;
- case OPERATOR_LSHIFTEQ:
- op = OPERATOR_LSHIFT;
- break;
- case OPERATOR_RSHIFTEQ:
- op = OPERATOR_RSHIFT;
- break;
- case OPERATOR_ANDEQ:
- op = OPERATOR_AND;
- break;
- case OPERATOR_BITCLEAREQ:
- op = OPERATOR_BITCLEAR;
- break;
- default:
- go_unreachable();
- }
-
- Expression* binop = Expression::make_binary(op, lval, this->rhs_, loc);
+ Expression* binop = Expression::make_binary(this->get_binop(), lval,
+ this->rhs_, loc);
Statement* s = Statement::make_assignment(this->lhs_, binop, loc);
+ s->determine_types(gogo);
if (b->statements()->empty())
{
delete b;
@@ -1322,6 +1443,12 @@ class Tuple_assignment_statement : public Statement
int
do_traverse(Traverse* traverse);
+ void
+ do_determine_types(Gogo*);
+
+ void
+ do_check_types(Gogo*);
+
Statement*
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
@@ -1349,15 +1476,53 @@ Tuple_assignment_statement::do_traverse(Traverse* traverse)
return this->traverse_expression_list(traverse, this->rhs_);
}
+void
+Tuple_assignment_statement::do_determine_types(Gogo* gogo)
+{
+ Expression_list::iterator pr = this->rhs_->begin();
+ for (Expression_list::iterator pl = this->lhs_->begin();
+ pl != this->lhs_->end();
+ ++pl, ++pr)
+ {
+ go_assert(pr != this->rhs_->end());
+ (*pl)->determine_type_no_context(gogo);
+ Type* rhs_context_type = (*pl)->type();
+ if (rhs_context_type->is_sink_type())
+ rhs_context_type = NULL;
+ Type_context context(rhs_context_type, false);
+ (*pr)->determine_type(gogo, &context);
+ }
+ go_assert(pr == this->rhs_->end());
+}
+
+void
+Tuple_assignment_statement::do_check_types(Gogo*)
+{
+ Expression_list::iterator pr = this->rhs_->begin();
+ for (Expression_list::iterator pl = this->lhs_->begin();
+ pl != this->lhs_->end();
+ ++pl, ++pr)
+ {
+ go_assert(pr != this->rhs_->end());
+ if (!Assignment_statement::check_assignment_types(*pl, (*pr)->type(),
+ this->location()))
+ this->set_is_error();
+ }
+ go_assert(pr == this->rhs_->end());
+}
+
// Lower a tuple assignment. We use temporary variables to split it
// up into a set of single assignments.
Statement*
-Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
- Statement_inserter*)
+Tuple_assignment_statement::do_lower(Gogo* gogo, Named_object*,
+ Block* enclosing, Statement_inserter*)
{
Location loc = this->location();
+ if (this->classification() == STATEMENT_ERROR)
+ return Statement::make_error_statement(loc);
+
Block* b = new Block(enclosing, loc);
// First move out any subexpressions on the left hand side. The
@@ -1417,7 +1582,9 @@ Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
continue;
Expression* ref = Expression::make_temporary_reference(*ptemp, loc);
- b->add_statement(Statement::make_assignment(*plhs, ref, loc));
+ Statement* s = Statement::make_assignment(*plhs, ref, loc);
+ s->determine_types(gogo);
+ b->add_statement(s);
++ptemp;
}
go_assert(ptemp == temps.end() || saw_errors());
@@ -1464,6 +1631,12 @@ public:
int
do_traverse(Traverse* traverse);
+ void
+ do_determine_types(Gogo*);
+
+ void
+ do_check_types(Gogo*);
+
Statement*
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
@@ -1494,6 +1667,45 @@ Tuple_map_assignment_statement::do_traverse(Traverse* traverse)
return this->traverse_expression(traverse, &this->map_index_);
}
+void
+Tuple_map_assignment_statement::do_determine_types(Gogo* gogo)
+{
+ this->val_->determine_type_no_context(gogo);
+ this->present_->determine_type_no_context(gogo);
+ this->map_index_->determine_type_no_context(gogo);
+}
+
+void
+Tuple_map_assignment_statement::do_check_types(Gogo*)
+{
+ Expression* map_expr = this->map_index_;
+ Map_type* map_type;
+ if (map_expr->map_index_expression() != NULL)
+ map_type = map_expr->map_index_expression()->get_map_type();
+ else if (map_expr->index_expression() != NULL)
+ map_type = map_expr->index_expression()->left()->type()->map_type();
+ else
+ {
+ this->report_error(_("expected map index on right hand side"));
+ return;
+ }
+ if (map_type == NULL || map_type->is_error())
+ {
+ go_assert(saw_errors());
+ this->set_is_error();
+ return;
+ }
+
+ if (!Assignment_statement::check_assignment_types(this->val_,
+ map_type->val_type(),
+ this->location()))
+ this->set_is_error();
+ if (!Assignment_statement::check_assignment_types(this->present_,
+ Type::make_boolean_type(),
+ this->location()))
+ this->set_is_error();
+}
+
// Lower a tuple map assignment.
Statement*
@@ -1502,15 +1714,13 @@ Tuple_map_assignment_statement::do_lower(Gogo* gogo, Named_object*,
{
Location loc = this->location();
+ if (this->classification() == STATEMENT_ERROR)
+ return Statement::make_error_statement(loc);
+
Map_index_expression* map_index = this->map_index_->map_index_expression();
- if (map_index == NULL)
- {
- this->report_error(_("expected map index on right hand side"));
- return Statement::make_error_statement(loc);
- }
+ go_assert(map_index != NULL);
Map_type* map_type = map_index->get_map_type();
- if (map_type == NULL)
- return Statement::make_error_statement(loc);
+ go_assert(map_type != NULL);
// Avoid copy for string([]byte) conversions used in map keys.
// mapaccess doesn't keep the reference, so this is safe.
@@ -1607,11 +1817,13 @@ Tuple_map_assignment_statement::do_lower(Gogo* gogo, Named_object*,
Expression* res = Expression::make_call_result(call, 0);
res = Expression::make_unsafe_cast(val_ptr_type, res, loc);
Statement* s = Statement::make_assignment(ref, res, loc);
+ s->determine_types(gogo);
b->add_statement(s);
ref = Expression::make_temporary_reference(present_temp, loc);
ref->set_is_lvalue();
res = Expression::make_call_result(call, 1);
s = Statement::make_assignment(ref, res, loc);
+ s->determine_types(gogo);
b->add_statement(s);
// val = *val__ptr_temp
@@ -1619,11 +1831,13 @@ Tuple_map_assignment_statement::do_lower(Gogo* gogo, Named_object*,
Expression* ind =
Expression::make_dereference(ref, Expression::NIL_CHECK_NOT_NEEDED, loc);
s = Statement::make_assignment(this->val_, ind, loc);
+ s->determine_types(gogo);
b->add_statement(s);
// present = present_temp
ref = Expression::make_temporary_reference(present_temp, loc);
s = Statement::make_assignment(this->present_, ref, loc);
+ s->determine_types(gogo);
b->add_statement(s);
return Statement::make_block_statement(b, loc);
@@ -1669,6 +1883,12 @@ class Tuple_receive_assignment_statement : public Statement
int
do_traverse(Traverse* traverse);
+ void
+ do_determine_types(Gogo*);
+
+ void
+ do_check_types(Gogo*);
+
Statement*
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
@@ -1699,6 +1919,39 @@ Tuple_receive_assignment_statement::do_traverse(Traverse* traverse)
return this->traverse_expression(traverse, &this->channel_);
}
+void
+Tuple_receive_assignment_statement::do_determine_types(Gogo* gogo)
+{
+ this->val_->determine_type_no_context(gogo);
+ this->closed_->determine_type_no_context(gogo);
+ this->channel_->determine_type_no_context(gogo);
+}
+
+void
+Tuple_receive_assignment_statement::do_check_types(Gogo*)
+{
+ Channel_type* ct = this->channel_->type()->channel_type();
+ if (ct == NULL)
+ {
+ this->report_error(_("expected channel"));
+ return;
+ }
+ if (!ct->may_receive())
+ {
+ this->report_error(_("invalid receive on send-only channel"));
+ return;
+ }
+
+ if (!Assignment_statement::check_assignment_types(this->val_,
+ ct->element_type(),
+ this->location()))
+ this->set_is_error();
+ if (!Assignment_statement::check_assignment_types(this->closed_,
+ Type::make_boolean_type(),
+ this->location()))
+ this->set_is_error();
+}
+
// Lower to a function call.
Statement*
@@ -1708,17 +1961,11 @@ Tuple_receive_assignment_statement::do_lower(Gogo* gogo, Named_object*,
{
Location loc = this->location();
+ if (this->classification() == STATEMENT_ERROR)
+ return Statement::make_error_statement(loc);
+
Channel_type* channel_type = this->channel_->type()->channel_type();
- if (channel_type == NULL)
- {
- this->report_error(_("expected channel"));
- return Statement::make_error_statement(loc);
- }
- if (!channel_type->may_receive())
- {
- this->report_error(_("invalid receive on send-only channel"));
- return Statement::make_error_statement(loc);
- }
+ go_assert(channel_type != NULL && channel_type->may_receive());
Block* b = new Block(enclosing, loc);
@@ -1750,16 +1997,19 @@ Tuple_receive_assignment_statement::do_lower(Gogo* gogo, Named_object*,
ref = Expression::make_temporary_reference(closed_temp, loc);
ref->set_is_lvalue();
Statement* s = Statement::make_assignment(ref, call, loc);
+ s->determine_types(gogo);
b->add_statement(s);
// val = val_temp
ref = Expression::make_temporary_reference(val_temp, loc);
s = Statement::make_assignment(this->val_, ref, loc);
+ s->determine_types(gogo);
b->add_statement(s);
// closed = closed_temp
ref = Expression::make_temporary_reference(closed_temp, loc);
s = Statement::make_assignment(this->closed_, ref, loc);
+ s->determine_types(gogo);
b->add_statement(s);
return Statement::make_block_statement(b, loc);
@@ -1808,6 +2058,12 @@ class Tuple_type_guard_assignment_statement : public Statement
int
do_traverse(Traverse*);
+ void
+ do_determine_types(Gogo*);
+
+ void
+ do_check_types(Gogo*);
+
Statement*
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
@@ -1847,6 +2103,34 @@ Tuple_type_guard_assignment_statement::do_traverse(Traverse* traverse)
return this->traverse_expression(traverse, &this->expr_);
}
+void
+Tuple_type_guard_assignment_statement::do_determine_types(Gogo* gogo)
+{
+ this->val_->determine_type_no_context(gogo);
+ this->ok_->determine_type_no_context(gogo);
+ this->expr_->determine_type_no_context(gogo);
+}
+
+void
+Tuple_type_guard_assignment_statement::do_check_types(Gogo*)
+{
+ Type* expr_type = this->expr_->type();
+ if (expr_type->interface_type() == NULL)
+ {
+ if (!expr_type->is_error() && !this->type_->is_error())
+ this->report_error(_("type assertion only valid for interface types"));
+ return;
+ }
+
+ if (!Assignment_statement::check_assignment_types(this->val_, this->type_,
+ this->location()))
+ this->set_is_error();
+ if (!Assignment_statement::check_assignment_types(this->ok_,
+ Type::make_boolean_type(),
+ this->location()))
+ this->set_is_error();
+}
+
// Lower to a function call.
Statement*
@@ -1856,13 +2140,11 @@ Tuple_type_guard_assignment_statement::do_lower(Gogo* gogo, Named_object*,
{
Location loc = this->location();
+ if (this->classification() == STATEMENT_ERROR)
+ return Statement::make_error_statement(loc);
+
Type* expr_type = this->expr_->type();
- if (expr_type->interface_type() == NULL)
- {
- if (!expr_type->is_error() && !this->type_->is_error())
- this->report_error(_("type assertion only valid for interface types"));
- return Statement::make_error_statement(loc);
- }
+ go_assert(expr_type->interface_type() != NULL);
Block* b = new Block(enclosing, loc);
@@ -1907,12 +2189,14 @@ Tuple_type_guard_assignment_statement::do_lower(Gogo* gogo, Named_object*,
Expression* res = Expression::make_call_result(call, 0);
res = Expression::make_unsafe_cast(this->type_, res, loc);
Statement* s = Statement::make_assignment(this->val_, res, loc);
+ s->determine_types(gogo);
b->add_statement(s);
res = Expression::make_call_result(call, 1);
if (!this->ok_->type()->is_boolean_type())
res = Expression::make_cast(Type::lookup_bool_type(), res, loc);
s = Statement::make_assignment(this->ok_, res, loc);
+ s->determine_types(gogo);
b->add_statement(s);
}
@@ -1971,11 +2255,13 @@ Tuple_type_guard_assignment_statement::lower_to_object_type(
Expression* ok_ref = Expression::make_temporary_reference(ok_temp, loc);
s = Statement::make_assignment(ok_ref, call, loc);
}
+ s->determine_types(gogo);
b->add_statement(s);
// val = val_temp
ref = Expression::make_temporary_reference(val_temp, loc);
s = Statement::make_assignment(this->val_, ref, loc);
+ s->determine_types(gogo);
b->add_statement(s);
// ok = ok_temp
@@ -1983,6 +2269,7 @@ Tuple_type_guard_assignment_statement::lower_to_object_type(
{
ref = Expression::make_temporary_reference(ok_temp, loc);
s = Statement::make_assignment(this->ok_, ref, loc);
+ s->determine_types(gogo);
b->add_statement(s);
}
}
@@ -2050,35 +2337,12 @@ Expression_statement::do_check_types(Gogo*)
bool
Expression_statement::do_may_fall_through() const
{
+ // The builtin function panic does not return.
const Call_expression* call = this->expr_->call_expression();
- if (call != NULL)
- {
- const Expression* fn = call->fn();
- // panic is still an unknown named object.
- const Unknown_expression* ue = fn->unknown_expression();
- if (ue != NULL)
- {
- Named_object* no = ue->named_object();
-
- if (no->is_unknown())
- no = no->unknown_value()->real_named_object();
- if (no != NULL)
- {
- Function_type* fntype;
- if (no->is_function())
- fntype = no->func_value()->type();
- else if (no->is_function_declaration())
- fntype = no->func_declaration_value()->type();
- else
- fntype = NULL;
-
- // The builtin function panic does not return.
- if (fntype != NULL && fntype->is_builtin() && no->name() == "panic")
- return false;
- }
- }
- }
- return true;
+ if (call == NULL)
+ return true;
+ const Builtin_call_expression* bce = call->builtin_call_expression();
+ return bce == NULL || bce->code() != Builtin_call_expression::BUILTIN_PANIC;
}
// Export an expression statement.
@@ -2225,6 +2489,12 @@ class Inc_dec_statement : public Statement
do_traverse(Traverse* traverse)
{ return this->traverse_expression(traverse, &this->expr_); }
+ void
+ do_determine_types(Gogo*);
+
+ void
+ do_check_types(Gogo*);
+
Statement*
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
@@ -2242,17 +2512,36 @@ class Inc_dec_statement : public Statement
bool is_inc_;
};
+void
+Inc_dec_statement::do_determine_types(Gogo* gogo)
+{
+ this->expr_->determine_type_no_context(gogo);
+}
+
+void
+Inc_dec_statement::do_check_types(Gogo*)
+{
+ if (!this->expr_->is_addressable()
+ && !Index_expression::is_map_index(this->expr_))
+ {
+ if (!this->expr_->type()->is_error())
+ this->report_error(_("invalid left hand side of assignment"));
+ this->set_is_error();
+ return;
+ }
+ if (!this->expr_->type()->is_numeric_type())
+ {
+ this->report_error(_("increment or decrement of non-numeric type"));
+ return;
+ }
+}
+
// Lower to += or -=.
Statement*
Inc_dec_statement::do_lower(Gogo*, Named_object*, Block*, Statement_inserter*)
{
Location loc = this->location();
- if (!this->expr_->type()->is_numeric_type())
- {
- this->report_error("increment or decrement of non-numeric type");
- return Statement::make_error_statement(loc);
- }
Expression* oexpr = Expression::make_integer_ul(1, this->expr_->type(), loc);
Operator op = this->is_inc_ ? OPERATOR_PLUSEQ : OPERATOR_MINUSEQ;
return Statement::make_assignment_operation(op, this->expr_, oexpr, loc);
@@ -2370,12 +2659,16 @@ void
Thunk_statement::do_check_types(Gogo*)
{
if (!this->call_->discarding_value())
- return;
+ {
+ this->set_is_error();
+ return;
+ }
Call_expression* ce = this->call_->call_expression();
if (ce == NULL)
{
if (!this->call_->is_error_expression())
this->report_error("expected call expression");
+ this->set_is_error();
return;
}
}
@@ -2888,6 +3181,7 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name,
Statement* call_statement = Statement::make_statement(call, true);
+ call_statement->determine_types(gogo);
gogo->add_statement(call_statement);
// If this is a defer statement, the label comes immediately after
@@ -2898,7 +3192,10 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name,
Expression_list* vals = new Expression_list();
vals->push_back(Expression::make_boolean(false, location));
- gogo->add_statement(Statement::make_return_statement(vals, location));
+ Statement* s = Statement::make_return_statement(function, vals,
+ location);
+ s->determine_types(gogo);
+ gogo->add_statement(s);
}
Block* b = gogo->finish_block(location);
@@ -2983,6 +3280,7 @@ Go_statement::do_get_backend(Translate_context* context)
Gogo* gogo = context->gogo();
Expression* call = Runtime::make_call(gogo, Runtime::GO, this->location(), 2,
fn, arg);
+ call->determine_type_no_context(gogo);
Bexpression* bcall = call->get_backend(context);
Bfunction* bfunction = context->function()->func_value()->get_decl();
return context->backend()->expression_statement(bfunction, bcall);
@@ -3024,7 +3322,7 @@ Defer_statement::do_get_backend(Translate_context* context)
Expression* call;
if (this->on_stack_)
{
- if (context->gogo()->debug_optimization())
+ if (gogo->debug_optimization())
go_debug(loc, "stack allocated defer");
Type* defer_type = Defer_statement::defer_struct_type();
@@ -3037,6 +3335,7 @@ Defer_statement::do_get_backend(Translate_context* context)
else
call = Runtime::make_call(gogo, Runtime::DEFERPROC, loc, 3,
ds, fn, arg);
+ call->determine_type_no_context(gogo);
Bexpression* bcall = call->get_backend(context);
Bfunction* bfunction = context->function()->func_value()->get_decl();
return context->backend()->expression_statement(bfunction, bcall);
@@ -3082,80 +3381,97 @@ Statement::make_defer_statement(Call_expression* call,
// Class Return_statement.
-// Lower a return statement. If we are returning a function call
-// which returns multiple values which match the current function,
-// split up the call's results. If the return statement lists
-// explicit values, implement this statement by assigning the values
-// to the result variables and change this statement to a naked
-// return. This lets panic/recover work correctly.
-
-Statement*
-Return_statement::do_lower(Gogo* gogo, Named_object* function,
- Block* enclosing, Statement_inserter*)
+void
+Return_statement::do_determine_types(Gogo* gogo)
{
- if (this->is_lowered_)
- return this;
+ if (this->types_are_determined_)
+ return;
+ this->types_are_determined_ = true;
- Expression_list* vals = this->vals_;
- this->vals_ = NULL;
- this->is_lowered_ = true;
+ size_t vals_count = this->vals_ == NULL ? 0 : this->vals_->size();
+ if (vals_count == 0)
+ return;
- Location loc = this->location();
+ Function::Results* results =
+ this->function_->func_value()->result_variables();
+ size_t results_count = results == NULL ? 0 : results->size();
- size_t vals_count = vals == NULL ? 0 : vals->size();
- Function::Results* results = function->func_value()->result_variables();
+ // If the current function has multiple return values, and we are
+ // returning a single call expression, split up the call expression.
+ if (results_count > 1
+ && vals_count == 1
+ && this->vals_->front()->call_expression() != NULL)
+ {
+ Call_expression* call = this->vals_->front()->call_expression();
+ call->set_expected_result_count(results_count);
+ call->determine_type_no_context(gogo);
+ delete this->vals_;
+ this->vals_ = new Expression_list();
+ for (size_t i = 0; i < results_count; ++i)
+ this->vals_->push_back(Expression::make_call_result(call, i));
+ vals_count = results_count;
+ }
+
+ if (vals_count != results_count)
+ {
+ // This is an error which we will report later. Determine all
+ // types to avoid knockon errors.
+ for (Expression_list::const_iterator pe = this->vals_->begin();
+ pe != this->vals_->end();
+ ++pe)
+ (*pe)->determine_type_no_context(gogo);
+ return;
+ }
+
+ Expression_list::const_iterator pe = this->vals_->begin();
+ for (Function::Results::const_iterator pr = results->begin();
+ pr != results->end();
+ ++pr, ++pe)
+ {
+ Type* rvtype = (*pr)->result_var_value()->type();
+ Type_context context(rvtype, false);
+ (*pe)->determine_type(gogo, &context);
+ }
+}
+
+void
+Return_statement::do_check_types(Gogo*)
+{
+ size_t vals_count = this->vals_ == NULL ? 0 : this->vals_->size();
+ Function::Results* results =
+ this->function_->func_value()->result_variables();
size_t results_count = results == NULL ? 0 : results->size();
if (vals_count == 0)
{
- if (results_count > 0 && !function->func_value()->results_are_named())
- {
- this->report_error(_("not enough arguments to return"));
- return this;
- }
- return this;
+ if (results_count > 0
+ && !this->function_->func_value()->results_are_named())
+ this->report_error(_("not enough arguments to return"));
+ return;
}
if (results_count == 0)
{
this->report_error(_("return with value in function "
"with no return type"));
- return this;
- }
-
- // If the current function has multiple return values, and we are
- // returning a single call expression, split up the call expression.
- if (results_count > 1
- && vals->size() == 1
- && vals->front()->call_expression() != NULL)
- {
- Call_expression* call = vals->front()->call_expression();
- call->set_expected_result_count(results_count);
- delete vals;
- vals = new Expression_list;
- for (size_t i = 0; i < results_count; ++i)
- vals->push_back(Expression::make_call_result(call, i));
- vals_count = results_count;
+ delete this->vals_;
+ this->vals_ = NULL;
+ return;
}
if (vals_count < results_count)
{
this->report_error(_("not enough arguments to return"));
- return this;
+ return;
}
if (vals_count > results_count)
{
this->report_error(_("too many values in return statement"));
- return this;
+ return;
}
- Block* b = new Block(enclosing, loc);
-
- Expression_list* lhs = new Expression_list();
- Expression_list* rhs = new Expression_list();
-
- Expression_list::const_iterator pe = vals->begin();
+ Expression_list::const_iterator pe = this->vals_->begin();
int i = 1;
for (Function::Results::const_iterator pr = results->begin();
pr != results->end();
@@ -3164,22 +3480,9 @@ Return_statement::do_lower(Gogo* gogo, Named_object* function,
Named_object* rv = *pr;
Expression* e = *pe;
- // Check types now so that we give a good error message. The
- // result type is known. We determine the expression type
- // early.
-
- Type *rvtype = rv->result_var_value()->type();
- Type_context type_context(rvtype, false);
- e->determine_type(gogo, &type_context);
-
std::string reason;
- if (Type::are_assignable(rvtype, e->type(), &reason))
- {
- Expression* ve = Expression::make_var_reference(rv, e->location());
- lhs->push_back(ve);
- rhs->push_back(e);
- }
- else
+ if (!Type::are_assignable(rv->result_var_value()->type(), e->type(),
+ &reason))
{
if (reason.empty())
go_error_at(e->location(),
@@ -3188,21 +3491,77 @@ Return_statement::do_lower(Gogo* gogo, Named_object* function,
go_error_at(e->location(),
"incompatible type for return value %d (%s)",
i, reason.c_str());
+ this->set_is_error();
}
}
- go_assert(lhs->size() == rhs->size());
+}
+
+// Lower a return statement. If we are returning a function call
+// which returns multiple values which match the current function,
+// split up the call's results. If the return statement lists
+// explicit values, implement this statement by assigning the values
+// to the result variables and change this statement to a naked
+// return. This lets panic/recover work correctly.
+
+Statement*
+Return_statement::do_lower(Gogo* gogo, Named_object*,
+ Block* enclosing, Statement_inserter*)
+{
+ Location loc = this->location();
+
+ if (this->classification() == STATEMENT_ERROR)
+ return Statement::make_error_statement(loc);
+
+ if (this->is_lowered_)
+ return this;
+
+ Expression_list* vals = this->vals_;
+ this->vals_ = NULL;
+ this->is_lowered_ = true;
+
+ size_t vals_count = vals == NULL ? 0 : vals->size();
+
+ if (vals_count == 0)
+ return this;
+
+ Function::Results* results =
+ this->function_->func_value()->result_variables();
+ size_t results_count = results == NULL ? 0 : results->size();
+
+ go_assert(vals_count == results_count);
+
+ Block* b = new Block(enclosing, loc);
+
+ Expression_list* lhs = new Expression_list();
+ Expression_list* rhs = new Expression_list();
+
+ Expression_list::const_iterator pe = vals->begin();
+ for (Function::Results::const_iterator pr = results->begin();
+ pr != results->end();
+ ++pr, ++pe)
+ {
+ Named_object* rv = *pr;
+ Expression* e = *pe;
+ Expression* ve = Expression::make_var_reference(rv, e->location());
+ lhs->push_back(ve);
+ rhs->push_back(e);
+ }
- if (lhs->empty())
- ;
- else if (lhs->size() == 1)
+ if (lhs->size() == 1)
{
- b->add_statement(Statement::make_assignment(lhs->front(), rhs->front(),
- loc));
+ Statement* s = Statement::make_assignment(lhs->front(), rhs->front(),
+ loc);
+ s->determine_types(gogo);
+ b->add_statement(s);
delete lhs;
delete rhs;
}
else
- b->add_statement(Statement::make_tuple_assignment(lhs, rhs, loc));
+ {
+ Statement* s = Statement::make_tuple_assignment(lhs, rhs, loc);
+ s->determine_types(gogo);
+ b->add_statement(s);
+ }
b->add_statement(this);
@@ -3261,16 +3620,17 @@ Return_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
// Make a return statement.
Return_statement*
-Statement::make_return_statement(Expression_list* vals,
+Statement::make_return_statement(Named_object* function, Expression_list* vals,
Location location)
{
- return new Return_statement(vals, location);
+ return new Return_statement(function, vals, location);
}
// Make a statement that returns the result of a call expression.
Statement*
-Statement::make_return_from_call(Call_expression* call, Location location)
+Statement::make_return_from_call(Named_object* function, Call_expression* call,
+ Location location)
{
size_t rc = call->result_count();
if (rc == 0)
@@ -3285,7 +3645,7 @@ Statement::make_return_from_call(Call_expression* call, Location location)
for (size_t i = 0; i < rc; ++i)
vals->push_back(Expression::make_call_result(call, i));
}
- return Statement::make_return_statement(vals, location);
+ return Statement::make_return_statement(function, vals, location);
}
}
@@ -3942,7 +4302,8 @@ Case_clauses::Case_clause::is_constant() const
// test. We branch to FINISH_LABEL at the end of the statements.
void
-Case_clauses::Case_clause::lower(Block* b, Temporary_statement* val_temp,
+Case_clauses::Case_clause::lower(Gogo* gogo, Block* b,
+ Temporary_statement* val_temp,
Unnamed_label* start_label,
Unnamed_label* finish_label) const
{
@@ -3980,6 +4341,7 @@ Case_clauses::Case_clause::lower(Block* b, Temporary_statement* val_temp,
// if !COND { goto NEXT_CASE_LABEL }
cond = Expression::make_unary(OPERATOR_NOT, cond, loc);
s = Statement::make_if_statement(cond, then_block, NULL, loc);
+ s->determine_types(gogo);
b->add_statement(s);
}
@@ -4024,11 +4386,11 @@ Case_clauses::Case_clause::check_types(Type* type)
p != this->cases_->end();
++p)
{
- if (!Type::are_assignable(type, (*p)->type(), NULL)
- && !Type::are_assignable((*p)->type(), type, NULL))
+ std::string reason;
+ if (!Type::are_compatible_for_comparison(true, type, (*p)->type(),
+ &reason))
{
- go_error_at((*p)->location(),
- "type mismatch between switch value and case clause");
+ go_error_at(this->location_, "%s", reason.c_str());
return false;
}
}
@@ -4179,7 +4541,7 @@ Case_clauses::is_constant() const
// Lower case clauses for a nonconstant switch.
void
-Case_clauses::lower(Block* b, Temporary_statement* val_temp,
+Case_clauses::lower(Gogo* gogo, Block* b, Temporary_statement* val_temp,
Unnamed_label* break_label) const
{
// The default case.
@@ -4217,7 +4579,7 @@ Case_clauses::lower(Block* b, Temporary_statement* val_temp,
}
if (!p->is_default())
- p->lower(b, val_temp, start_label, finish_label);
+ p->lower(gogo, b, val_temp, start_label, finish_label);
else
{
// We have to move the default case to the end, so that we
@@ -4229,7 +4591,7 @@ Case_clauses::lower(Block* b, Temporary_statement* val_temp,
}
if (default_case != NULL)
- default_case->lower(b, val_temp, default_start_label,
+ default_case->lower(gogo, b, val_temp, default_start_label,
default_finish_label);
}
@@ -4341,12 +4703,6 @@ class Constant_switch_statement : public Statement
int
do_traverse(Traverse*);
- void
- do_determine_types(Gogo*);
-
- void
- do_check_types(Gogo*);
-
Bstatement*
do_get_backend(Translate_context*);
@@ -4372,24 +4728,6 @@ Constant_switch_statement::do_traverse(Traverse* traverse)
return this->clauses_->traverse(traverse);
}
-// Determine types.
-
-void
-Constant_switch_statement::do_determine_types(Gogo* gogo)
-{
- this->val_->determine_type_no_context(gogo);
- this->clauses_->determine_types(gogo, this->val_->type());
-}
-
-// Check types.
-
-void
-Constant_switch_statement::do_check_types(Gogo*)
-{
- if (!this->clauses_->check_types(this->val_->type()))
- this->set_is_error();
-}
-
// Convert to GENERIC.
Bstatement*
@@ -4452,11 +4790,50 @@ Switch_statement::do_traverse(Traverse* traverse)
return this->clauses_->traverse(traverse);
}
+void
+Switch_statement::do_determine_types(Gogo* gogo)
+{
+ if (this->val_ != NULL)
+ this->val_->determine_type_no_context(gogo);
+ this->clauses_->determine_types(gogo,
+ (this->val_ == NULL
+ ? NULL
+ : this->val_->type()));
+}
+
+void
+Switch_statement::do_check_types(Gogo*)
+{
+ if (this->val_ != NULL
+ && (this->val_->is_error_expression()
+ || this->val_->type()->is_error()))
+ return;
+
+ if (this->val_ != NULL
+ && !this->val_->type()->is_comparable()
+ && !Type::are_compatible_for_comparison(true, this->val_->type(),
+ Type::make_nil_type(), NULL))
+ {
+ go_error_at(this->val_->location(),
+ "cannot switch on value whose type may not be compared");
+ this->set_is_error();
+ return;
+ }
+
+ Type* type;
+ if (this->val_ != NULL)
+ type = this->val_->type();
+ else
+ type = Type::make_boolean_type();
+ if (!this->clauses_->check_types(type))
+ this->set_is_error();
+}
+
// Lower a Switch_statement to a Constant_switch_statement or a series
// of if statements.
Statement*
-Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
+Switch_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
Statement_inserter*)
{
Location loc = this->location();
@@ -4476,16 +4853,6 @@ Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
return new Constant_switch_statement(this->val_, this->clauses_,
this->break_label_, loc);
- if (this->val_ != NULL
- && !this->val_->type()->is_comparable()
- && !Type::are_compatible_for_comparison(true, this->val_->type(),
- Type::make_nil_type(), NULL))
- {
- go_error_at(this->val_->location(),
- "cannot switch on value whose type may not be compared");
- return Statement::make_error_statement(loc);
- }
-
Block* b = new Block(enclosing, loc);
if (this->clauses_->empty())
@@ -4507,7 +4874,7 @@ Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
Temporary_statement* val_temp = Statement::make_temporary(type, val, loc);
b->add_statement(val_temp);
- this->clauses_->lower(b, val_temp, this->break_label());
+ this->clauses_->lower(gogo, b, val_temp, this->break_label());
Statement* s = Statement::make_unnamed_label_statement(this->break_label_);
b->add_statement(s);
@@ -4588,27 +4955,19 @@ Type_case_clauses::Type_case_clause::traverse(Traverse* traverse)
return TRAVERSE_CONTINUE;
}
-// Lower one clause in a type switch. Add statements to the block B.
-// The type descriptor we are switching on is in DESCRIPTOR_TEMP.
-// BREAK_LABEL is the label at the end of the type switch.
-// *STMTS_LABEL, if not NULL, is a label to put at the start of the
-// statements.
-
void
-Type_case_clauses::Type_case_clause::lower(Gogo* gogo,
- Type* switch_val_type,
- Block* b,
- Temporary_statement* descriptor_temp,
- Unnamed_label* break_label,
- Unnamed_label** stmts_label) const
+Type_case_clauses::Type_case_clause::determine_types(Gogo* gogo)
{
- Location loc = this->location_;
+ if (this->statements_ != NULL)
+ this->statements_->determine_types(gogo);
+}
- Unnamed_label* next_case_label = NULL;
+bool
+Type_case_clauses::Type_case_clause::check_types(Type* switch_val_type)
+{
if (!this->is_default_)
{
Type* type = this->type_;
-
std::string reason;
if (switch_val_type->interface_type() != NULL
&& !type->is_nil_constant_as_type()
@@ -4621,7 +4980,31 @@ Type_case_clauses::Type_case_clause::lower(Gogo* gogo,
else
go_error_at(this->location_, "impossible type switch case (%s)",
reason.c_str());
+ return false;
}
+ }
+ return true;
+}
+
+// Lower one clause in a type switch. Add statements to the block B.
+// The type descriptor we are switching on is in DESCRIPTOR_TEMP.
+// BREAK_LABEL is the label at the end of the type switch.
+// *STMTS_LABEL, if not NULL, is a label to put at the start of the
+// statements.
+
+void
+Type_case_clauses::Type_case_clause::lower(Gogo* gogo,
+ Block* b,
+ Temporary_statement* descriptor_temp,
+ Unnamed_label* break_label,
+ Unnamed_label** stmts_label) const
+{
+ Location loc = this->location_;
+
+ Unnamed_label* next_case_label = NULL;
+ if (!this->is_default_)
+ {
+ Type* type = this->type_;
Expression* ref = Expression::make_temporary_reference(descriptor_temp,
loc);
@@ -4670,6 +5053,7 @@ Type_case_clauses::Type_case_clause::lower(Gogo* gogo,
Statement* s = Statement::make_goto_unnamed_statement(dest, loc);
then_block->add_statement(s);
s = Statement::make_if_statement(cond, then_block, NULL, loc);
+ s->determine_types(gogo);
b->add_statement(s);
}
@@ -4774,6 +5158,29 @@ Type_case_clauses::traverse(Traverse* traverse)
return TRAVERSE_CONTINUE;
}
+void
+Type_case_clauses::determine_types(Gogo* gogo)
+{
+ for (Type_clauses::iterator p = this->clauses_.begin();
+ p != this->clauses_.end();
+ ++p)
+ p->determine_types(gogo);
+}
+
+bool
+Type_case_clauses::check_types(Type* switch_val_type)
+{
+ bool ret = true;
+ for (Type_clauses::iterator p = this->clauses_.begin();
+ p != this->clauses_.end();
+ ++p)
+ {
+ if (!p->check_types(switch_val_type))
+ ret = false;
+ }
+ return ret;
+}
+
// Check for duplicate types.
void
@@ -4802,8 +5209,7 @@ Type_case_clauses::check_duplicates() const
// BREAK_LABEL is the label at the end of the type switch.
void
-Type_case_clauses::lower(Gogo* gogo, Type* switch_val_type,
- Block* b,
+Type_case_clauses::lower(Gogo* gogo, Block* b,
Temporary_statement* descriptor_temp,
Unnamed_label* break_label) const
{
@@ -4815,8 +5221,7 @@ Type_case_clauses::lower(Gogo* gogo, Type* switch_val_type,
++p)
{
if (!p->is_default())
- p->lower(gogo, switch_val_type, b, descriptor_temp, break_label,
- &stmts_label);
+ p->lower(gogo, b, descriptor_temp, break_label, &stmts_label);
else
{
// We are generating a series of tests, which means that we
@@ -4827,8 +5232,7 @@ Type_case_clauses::lower(Gogo* gogo, Type* switch_val_type,
go_assert(stmts_label == NULL);
if (default_case != NULL)
- default_case->lower(gogo, switch_val_type, b, descriptor_temp, break_label,
- NULL);
+ default_case->lower(gogo, b, descriptor_temp, break_label, NULL);
}
// Return true if these clauses may fall through to the statements
@@ -4875,6 +5279,31 @@ Type_switch_statement::do_traverse(Traverse* traverse)
return TRAVERSE_CONTINUE;
}
+void
+Type_switch_statement::do_determine_types(Gogo* gogo)
+{
+ this->expr_->determine_type_no_context(gogo);
+ this->clauses_->determine_types(gogo);
+}
+
+void
+Type_switch_statement::do_check_types(Gogo*)
+{
+ if (this->clauses_ != NULL)
+ this->clauses_->check_duplicates();
+
+ Type* expr_type = this->expr_->type();
+ if (expr_type->interface_type() == NULL)
+ {
+ if (!expr_type->is_error())
+ this->report_error(_("cannot type switch on non-interface value"));
+ this->set_is_error();
+ }
+
+ if (!this->clauses_->check_types(expr_type))
+ this->set_is_error();
+}
+
// Lower a type switch statement to a series of if statements. The gc
// compiler is able to generate a table in some cases. However, that
// does not work for us because we may have type descriptors in
@@ -4887,19 +5316,11 @@ Type_switch_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
{
const Location loc = this->location();
- if (this->clauses_ != NULL)
- this->clauses_->check_duplicates();
+ if (this->classification() == STATEMENT_ERROR)
+ return Statement::make_error_statement(loc);
Block* b = new Block(enclosing, loc);
- Type* val_type = this->expr_->type();
- if (val_type->interface_type() == NULL)
- {
- if (!val_type->is_error())
- this->report_error(_("cannot type switch on non-interface value"));
- return Statement::make_error_statement(loc);
- }
-
Temporary_statement* val_temp =
Statement::make_temporary(NULL, this->expr_, loc);
b->add_statement(val_temp);
@@ -4917,10 +5338,11 @@ Type_switch_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
Expression::make_temporary_reference(descriptor_temp, loc);
lhs->set_is_lvalue();
Statement* s = Statement::make_assignment(lhs, td, loc);
+ s->determine_types(gogo);
b->add_statement(s);
if (this->clauses_ != NULL)
- this->clauses_->lower(gogo, val_type, b, descriptor_temp, this->break_label());
+ this->clauses_->lower(gogo, b, descriptor_temp, this->break_label());
s = Statement::make_unnamed_label_statement(this->break_label_);
b->add_statement(s);
@@ -5090,7 +5512,7 @@ Send_statement::do_get_backend(Translate_context* context)
Channel_type* channel_type = this->channel_->type()->channel_type();
Type* element_type = channel_type->element_type();
- Expression* val = Expression::convert_for_assignment(context->gogo(),
+ Expression* val = Expression::convert_for_assignment(gogo,
element_type,
this->val_, loc);
@@ -5159,8 +5581,8 @@ Send_statement::do_get_backend(Translate_context* context)
Expression* call = Runtime::make_call(gogo, Runtime::CHANSEND, loc, 2,
this->channel_, val);
-
- context->gogo()->lower_expression(context->function(), NULL, &call);
+ call->determine_type_no_context(gogo);
+ gogo->lower_expression(context->function(), NULL, &call);
Bexpression* bcall = call->get_backend(context);
Bfunction* bfunction = context->function()->func_value()->get_decl();
Bstatement* s = context->backend()->expression_statement(bfunction, bcall);
@@ -5259,7 +5681,7 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
loc);
if (this->is_send_)
- this->lower_send(b, scase, chanref);
+ this->lower_send(gogo, b, scase, chanref);
else
this->lower_recv(gogo, function, b, scase, chanref, recvok);
@@ -5272,7 +5694,8 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
// Lower a send clause in a select statement.
void
-Select_clauses::Select_clause::lower_send(Block* b, Expression* scase,
+Select_clauses::Select_clause::lower_send(Gogo* gogo, Block* b,
+ Expression* scase,
Expression* chanref)
{
Location loc = this->location_;
@@ -5300,7 +5723,7 @@ Select_clauses::Select_clause::lower_send(Block* b, Expression* scase,
Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type());
valaddr = Expression::make_cast(unsafe_pointer_type, valaddr, loc);
- this->set_case(b, scase, chanref, valaddr);
+ this->set_case(gogo, b, scase, chanref, valaddr);
}
// Lower a receive clause in a select statement.
@@ -5326,7 +5749,7 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function,
Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type());
valaddr = Expression::make_cast(unsafe_pointer_type, valaddr, loc);
- this->set_case(b, scase, chanref, valaddr);
+ this->set_case(gogo, b, scase, chanref, valaddr);
// If the block of statements is executed, arrange for the received
// value to move from VAL to the place where the statements expect
@@ -5345,7 +5768,9 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function,
{
init = new Block(b, loc);
valref = Expression::make_temporary_reference(val, loc);
- init->add_statement(Statement::make_assignment(this->val_, valref, loc));
+ Statement* s = Statement::make_assignment(this->val_, valref, loc);
+ s->determine_types(gogo);
+ init->add_statement(s);
}
if (this->closedvar_ != NULL)
@@ -5359,8 +5784,9 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function,
if (init == NULL)
init = new Block(b, loc);
Expression* cref = Expression::make_temporary_reference(recvok, loc);
- init->add_statement(Statement::make_assignment(this->closed_, cref,
- loc));
+ Statement* s = Statement::make_assignment(this->closed_, cref, loc);
+ s->determine_types(gogo);
+ init->add_statement(s);
}
if (init != NULL)
@@ -5378,7 +5804,8 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function,
// pass to the runtime function selectgo.
void
-Select_clauses::Select_clause::set_case(Block* b,
+Select_clauses::Select_clause::set_case(Gogo* gogo,
+ Block* b,
Expression* scase,
Expression* chanref,
Expression* elem)
@@ -5392,6 +5819,7 @@ Select_clauses::Select_clause::set_case(Block* b,
Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type());
chanref = Expression::make_unsafe_cast(unsafe_pointer_type, chanref, loc);
Statement* s = Statement::make_assignment(ref, chanref, loc);
+ s->determine_types(gogo);
b->add_statement(s);
if (elem != NULL)
@@ -5400,6 +5828,7 @@ Select_clauses::Select_clause::set_case(Block* b,
go_assert(scase_type->field(field_index)->is_field_name("elem"));
ref = Expression::make_field_reference(scase->copy(), field_index, loc);
s = Statement::make_assignment(ref, elem, loc);
+ s->determine_types(gogo);
b->add_statement(s);
}
}
@@ -5409,7 +5838,16 @@ Select_clauses::Select_clause::set_case(Block* b,
void
Select_clauses::Select_clause::determine_types(Gogo* gogo)
{
- go_assert(this->is_lowered_);
+ if (this->channel_ != NULL)
+ this->channel_->determine_type_no_context(gogo);
+ if (this->val_ != NULL)
+ this->val_->determine_type_no_context(gogo);
+ if (this->closed_ != NULL)
+ this->closed_->determine_type_no_context(gogo);
+ if (this->var_ != NULL && this->var_->is_variable())
+ this->var_->var_value()->determine_type(gogo);
+ if (this->closedvar_ != NULL && this->closedvar_->is_variable())
+ this->closedvar_->var_value()->determine_type(gogo);
if (this->statements_ != NULL)
this->statements_->determine_types(gogo);
}
@@ -5673,6 +6111,7 @@ Select_clauses::get_backend(Translate_context* context,
Gogo* gogo = context->gogo();
Expression* crash = Runtime::make_call(gogo, Runtime::UNREACHABLE,
location, 0);
+ crash->determine_type_no_context(gogo);
Bexpression* bcrash = crash->get_backend(context);
clauses[count] = context->backend()->expression_statement(bfunction, bcrash);
@@ -5740,6 +6179,7 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function,
{
Expression* call = Runtime::make_call(gogo, Runtime::BLOCK, loc, 0);
Statement *s = Statement::make_statement(call, false);
+ s->determine_types(gogo);
b->add_statement(s);
this->is_lowered_ = true;
return Statement::make_block_statement(b, loc);
@@ -5823,11 +6263,13 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function,
Expression* result = Expression::make_call_result(call, 0);
Expression* ref = Expression::make_temporary_reference(this->index_, loc);
Statement* s = Statement::make_assignment(ref, result, loc);
+ s->determine_types(gogo);
b->add_statement(s);
result = Expression::make_call_result(call, 1);
ref = Expression::make_temporary_reference(recvok, loc);
s = Statement::make_assignment(ref, result, loc);
+ s->determine_types(gogo);
b->add_statement(s);
this->is_lowered_ = true;
@@ -5857,8 +6299,10 @@ Select_statement::lower_one_case(Gogo* gogo, Block* b)
Block* bnil = new Block(b, loc);
Expression* call = Runtime::make_call(gogo, Runtime::BLOCK, loc, 0);
Statement* s = Statement::make_statement(call, false);
+ s->determine_types(gogo);
bnil->add_statement(s);
Statement* ifs = Statement::make_if_statement(cond, bnil, NULL, loc);
+ ifs->determine_types(gogo);
b->add_statement(ifs);
chanref = chanref->copy();
@@ -5866,6 +6310,7 @@ Select_statement::lower_one_case(Gogo* gogo, Block* b)
if (scase.is_send())
{
s = Statement::make_send_statement(chanref, scase.val(), cloc);
+ s->determine_types(gogo);
b->add_statement(s);
}
else
@@ -5888,6 +6333,7 @@ Select_statement::lower_one_case(Gogo* gogo, Block* b)
}
else
s = Statement::make_statement(recv, false);
+ s->determine_types(gogo);
b->add_statement(s);
}
else
@@ -5918,6 +6364,7 @@ Select_statement::lower_one_case(Gogo* gogo, Block* b)
}
s = Statement::make_tuple_receive_assignment(lhs, lhs2, chanref, cloc);
+ s->determine_types(gogo);
b->add_statement(s);
if (scase.var() != NULL)
@@ -6000,12 +6447,14 @@ Select_statement::lower_two_case(Gogo* gogo, Block* b)
Statement::make_temporary(Type::make_boolean_type(),
Expression::make_call_result(call, 0),
loc);
+ selected_temp->determine_types(gogo);
b->add_statement(selected_temp);
Temporary_statement* ok_temp =
Statement::make_temporary(Type::make_boolean_type(),
Expression::make_call_result(call, 1),
loc);
+ ok_temp->determine_types(gogo);
b->add_statement(ok_temp);
cond = Expression::make_temporary_reference(selected_temp, loc);
@@ -6017,6 +6466,7 @@ Select_statement::lower_two_case(Gogo* gogo, Block* b)
Statement* as = Statement::make_assignment(chancase.val(),
ref->copy(),
cloc);
+ as->determine_types(gogo);
bchan->add_statement(as);
}
else if (chancase.var() != NULL)
@@ -6031,6 +6481,7 @@ Select_statement::lower_two_case(Gogo* gogo, Block* b)
cloc);
Statement* as = Statement::make_assignment(chancase.closed(),
okref, cloc);
+ as->determine_types(gogo);
bchan->add_statement(as);
}
else if (chancase.closedvar() != NULL)
@@ -6047,6 +6498,7 @@ Select_statement::lower_two_case(Gogo* gogo, Block* b)
Statement* ifs =
Statement::make_if_statement(cond, bchan, defcase.statements(), loc);
+ ifs->determine_types(gogo);
b->add_statement(ifs);
Statement* label =
@@ -6129,16 +6581,47 @@ For_statement::do_traverse(Traverse* traverse)
return this->statements_->traverse(traverse);
}
+void
+For_statement::do_determine_types(Gogo* gogo)
+{
+ if (this->init_ != NULL)
+ this->init_->determine_types(gogo);
+ if (this->cond_ != NULL)
+ this->cond_->determine_type_no_context(gogo);
+ if (this->post_ != NULL)
+ this->post_->determine_types(gogo);
+ this->statements_->determine_types(gogo);
+}
+
+void
+For_statement::do_check_types(Gogo*)
+{
+ if (this->cond_ != NULL)
+ {
+ Type* type = this->cond_->type();
+ if (type->is_error())
+ this->set_is_error();
+ else if (!type->is_boolean_type())
+ {
+ go_error_at(this->cond_->location(), "expected boolean expression");
+ this->set_is_error();
+ }
+ }
+}
+
// Lower a For_statement into if statements and gotos. Getting rid of
// complex statements make it easier to handle garbage collection.
Statement*
-For_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
+For_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
Statement_inserter*)
{
- Statement* s;
Location loc = this->location();
+ if (this->classification() == STATEMENT_ERROR)
+ return Statement::make_error_statement(loc);
+
+ Statement* s;
Block* b = new Block(enclosing, this->location());
if (this->init_ != NULL)
{
@@ -6188,6 +6671,7 @@ For_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
then_block->add_statement(s);
s = Statement::make_if_statement(this->cond_, then_block, NULL, cond_loc);
+ s->determine_types(gogo);
b->add_statement(s);
}
@@ -6318,22 +6802,30 @@ For_range_statement::do_traverse(Traverse* traverse)
return this->statements_->traverse(traverse);
}
-// Lower a for range statement. For simplicity we lower this into a
-// for statement, which will then be lowered in turn to goto
-// statements.
+void
+For_range_statement::do_determine_types(Gogo* gogo)
+{
+ if (this->index_var_ != NULL)
+ this->index_var_->determine_type_no_context(gogo);
+ if (this->value_var_ != NULL)
+ this->value_var_->determine_type_no_context(gogo);
+ this->range_->determine_type_no_context(gogo);
+ this->statements_->determine_types(gogo);
+}
-Statement*
-For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
- Statement_inserter*)
+void
+For_range_statement::do_check_types(Gogo*)
{
Type* range_type = this->range_->type();
+
+ Type* index_type;
+ Type* value_type = NULL;
+
if (range_type->points_to() != NULL
&& range_type->points_to()->array_type() != NULL
&& !range_type->points_to()->is_slice_type())
range_type = range_type->points_to();
- Type* index_type;
- Type* value_type = NULL;
if (range_type->array_type() != NULL)
{
index_type = Type::lookup_integer_type("int");
@@ -6351,22 +6843,79 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
}
else if (range_type->channel_type() != NULL)
{
+ if (!range_type->channel_type()->may_receive())
+ this->report_error(_("invalid receive on send-only channel"));
index_type = range_type->channel_type()->element_type();
if (this->value_var_ != NULL)
{
if (!this->value_var_->type()->is_error())
this->report_error(_("too many variables for range clause "
"with channel"));
- return Statement::make_error_statement(this->location());
+ this->set_is_error();
+ return;
}
}
else
{
this->report_error(_("range clause must have "
"array, slice, string, map, or channel type"));
- return Statement::make_error_statement(this->location());
+ return;
}
+ if (this->index_var_ != NULL
+ && !Assignment_statement::check_assignment_types(this->index_var_,
+ index_type,
+ this->location()))
+ this->set_is_error();
+ if (this->value_var_ != NULL
+ && !Assignment_statement::check_assignment_types(this->value_var_,
+ value_type,
+ this->location()))
+ this->set_is_error();
+}
+
+// Lower a for range statement. For simplicity we lower this into a
+// for statement, which will then be lowered in turn to goto
+// statements.
+
+Statement*
+For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
+ Statement_inserter*)
+{
+ if (this->classification() == STATEMENT_ERROR)
+ return Statement::make_error_statement(this->location());
+
+ Type* range_type = this->range_->type();
+ if (range_type->points_to() != NULL
+ && range_type->points_to()->array_type() != NULL
+ && !range_type->points_to()->is_slice_type())
+ range_type = range_type->points_to();
+
+ Type* index_type;
+ Type* value_type = NULL;
+ if (range_type->array_type() != NULL)
+ {
+ index_type = Type::lookup_integer_type("int");
+ value_type = range_type->array_type()->element_type();
+ }
+ else if (range_type->is_string_type())
+ {
+ index_type = Type::lookup_integer_type("int");
+ value_type = Type::lookup_integer_type("rune");
+ }
+ else if (range_type->map_type() != NULL)
+ {
+ index_type = range_type->map_type()->key_type();
+ value_type = range_type->map_type()->val_type();
+ }
+ else if (range_type->channel_type() != NULL)
+ {
+ index_type = range_type->channel_type()->element_type();
+ go_assert(this->value_var_ == NULL);
+ }
+ else
+ go_unreachable();
+
// If there is only one iteration variable, and len(this->range_) is
// constant, then we do not evaluate the range variable. len(x) is
// a contant if x is a string constant or if x is an array. If x is
@@ -6412,6 +6961,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
{
if (gogo->debug_optimization())
go_debug(loc, "map range clear");
+ clear->determine_types(gogo);
temp_block->add_statement(clear);
return Statement::make_block_statement(temp_block, loc);
}
@@ -6429,6 +6979,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
{
if (gogo->debug_optimization())
go_debug(loc, "array range clear");
+ clear->determine_types(gogo);
temp_block->add_statement(clear);
return Statement::make_block_statement(temp_block, loc);
}
@@ -6505,6 +7056,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
assign = Statement::make_tuple_assignment(lhs, rhs, loc);
}
+ assign->determine_types(gogo);
body->add_statement(assign);
}
@@ -6515,6 +7067,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
For_statement* loop = Statement::make_for_statement(init, cond, post,
this->location());
loop->add_statements(body);
+ loop->determine_types(gogo);
loop->set_break_continue_labels(this->break_label_, this->continue_label_);
temp_block->add_statement(loop);
@@ -6596,12 +7149,14 @@ For_range_statement::lower_range_array(Gogo* gogo,
{
Expression* ref = this->make_range_ref(range_object, range_temp, loc);
range_temp = Statement::make_temporary(NULL, ref, loc);
+ range_temp->determine_types(gogo);
init->add_statement(range_temp);
len_arg = ref;
}
Expression* len_call = this->call_builtin(gogo, "len", len_arg, loc);
Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(),
len_call, loc);
+ len_temp->determine_types(gogo);
init->add_statement(len_temp);
Expression* zexpr = Expression::make_integer_ul(0, NULL, loc);
@@ -6610,6 +7165,7 @@ For_range_statement::lower_range_array(Gogo* gogo,
Expression::make_temporary_reference(index_temp, loc);
tref->set_is_lvalue();
Statement* s = Statement::make_assignment(tref, zexpr, loc);
+ s->determine_types(gogo);
init->add_statement(s);
*pinit = init;
@@ -6638,6 +7194,7 @@ For_range_statement::lower_range_array(Gogo* gogo,
tref = Expression::make_temporary_reference(value_temp, loc);
tref->set_is_lvalue();
s = Statement::make_assignment(tref, index, loc);
+ s->determine_types(gogo);
iter_init->add_statement(s);
}
@@ -6650,6 +7207,7 @@ For_range_statement::lower_range_array(Gogo* gogo,
tref = Expression::make_temporary_reference(index_temp, loc);
tref->set_is_lvalue();
s = Statement::make_inc_statement(tref);
+ s->determine_types(gogo);
post->add_statement(s);
*ppost = post;
}
@@ -6694,12 +7252,14 @@ For_range_statement::lower_range_slice(Gogo* gogo,
Expression* ref = this->make_range_ref(range_object, range_temp, loc);
Temporary_statement* for_temp = Statement::make_temporary(NULL, ref, loc);
+ for_temp->determine_types(gogo);
init->add_statement(for_temp);
ref = Expression::make_temporary_reference(for_temp, loc);
Expression* len_call = this->call_builtin(gogo, "len", ref, loc);
Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(),
len_call, loc);
+ len_temp->determine_types(gogo);
init->add_statement(len_temp);
Expression* zexpr = Expression::make_integer_ul(0, NULL, loc);
@@ -6708,6 +7268,7 @@ For_range_statement::lower_range_slice(Gogo* gogo,
Expression::make_temporary_reference(index_temp, loc);
tref->set_is_lvalue();
Statement* s = Statement::make_assignment(tref, zexpr, loc);
+ s->determine_types(gogo);
init->add_statement(s);
*pinit = init;
@@ -6736,6 +7297,7 @@ For_range_statement::lower_range_slice(Gogo* gogo,
tref = Expression::make_temporary_reference(value_temp, loc);
tref->set_is_lvalue();
s = Statement::make_assignment(tref, index, loc);
+ s->determine_types(gogo);
iter_init->add_statement(s);
}
@@ -6748,6 +7310,7 @@ For_range_statement::lower_range_slice(Gogo* gogo,
tref = Expression::make_temporary_reference(index_temp, loc);
tref->set_is_lvalue();
s = Statement::make_inc_statement(tref);
+ s->determine_types(gogo);
post->add_statement(s);
*ppost = post;
}
@@ -6796,6 +7359,7 @@ For_range_statement::lower_range_string(Gogo* gogo,
Call_expression* call = this->call_builtin(gogo, "len", ref, loc);
Temporary_statement* len_temp =
Statement::make_temporary(index_temp->type(), call, loc);
+ len_temp->determine_types(gogo);
init->add_statement(len_temp);
Temporary_statement* next_index_temp =
@@ -6807,6 +7371,7 @@ For_range_statement::lower_range_string(Gogo* gogo,
index_ref->set_is_lvalue();
Expression* zexpr = Expression::make_integer_ul(0, index_temp->type(), loc);
Statement* s = Statement::make_assignment(index_ref, zexpr, loc);
+ s->determine_types(gogo);
init->add_statement(s);
Type* rune_type;
@@ -6847,6 +7412,7 @@ For_range_statement::lower_range_string(Gogo* gogo,
Expression::make_temporary_reference(value_temp, loc);
value_ref->set_is_lvalue();
s = Statement::make_assignment(value_ref, ref, loc);
+ s->determine_types(gogo);
iter_init->add_statement(s);
value_ref = Expression::make_temporary_reference(value_temp, loc);
@@ -6864,6 +7430,7 @@ For_range_statement::lower_range_string(Gogo* gogo,
Expression* sum = Expression::make_binary(OPERATOR_PLUS, index_ref, one,
loc);
s = Statement::make_assignment(lhs, sum, loc);
+ s->determine_types(gogo);
then_block->add_statement(s);
Block* else_block = new Block(iter_init, loc);
@@ -6876,15 +7443,18 @@ For_range_statement::lower_range_string(Gogo* gogo,
value_ref->set_is_lvalue();
Expression* res = Expression::make_call_result(call, 0);
s = Statement::make_assignment(value_ref, res, loc);
+ s->determine_types(gogo);
else_block->add_statement(s);
lhs = Expression::make_temporary_reference(next_index_temp, loc);
lhs->set_is_lvalue();
res = Expression::make_call_result(call, 1);
s = Statement::make_assignment(lhs, res, loc);
+ s->determine_types(gogo);
else_block->add_statement(s);
s = Statement::make_if_statement(cond, then_block, else_block, loc);
+ s->determine_types(gogo);
iter_init->add_statement(s);
*piter_init = iter_init;
@@ -6898,6 +7468,7 @@ For_range_statement::lower_range_string(Gogo* gogo,
index_ref->set_is_lvalue();
ref = Expression::make_temporary_reference(next_index_temp, loc);
s = Statement::make_assignment(index_ref, ref, loc);
+ s->determine_types(gogo);
post->add_statement(s);
*ppost = post;
@@ -6951,7 +7522,9 @@ For_range_statement::lower_range_map(Gogo* gogo,
Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
Expression* call = Runtime::make_call(gogo, Runtime::MAPITERINIT, loc, 3,
p1, p2, p3);
- init->add_statement(Statement::make_statement(call, true));
+ Statement* s = Statement::make_statement(call, true);
+ s->determine_types(gogo);
+ init->add_statement(s);
*pinit = init;
@@ -6977,6 +7550,7 @@ For_range_statement::lower_range_map(Gogo* gogo,
rhs = Expression::make_dereference(ref, Expression::NIL_CHECK_NOT_NEEDED,
loc);
Statement* set = Statement::make_assignment(lhs, rhs, loc);
+ set->determine_types(gogo);
iter_init->add_statement(set);
if (value_temp != NULL)
@@ -6987,6 +7561,7 @@ For_range_statement::lower_range_map(Gogo* gogo,
rhs = Expression::make_dereference(rhs, Expression::NIL_CHECK_NOT_NEEDED,
loc);
set = Statement::make_assignment(lhs, rhs, loc);
+ set->determine_types(gogo);
iter_init->add_statement(set);
}
@@ -7000,7 +7575,9 @@ For_range_statement::lower_range_map(Gogo* gogo,
ref = Expression::make_temporary_reference(hiter, loc);
p1 = Expression::make_unary(OPERATOR_AND, ref, loc);
call = Runtime::make_call(gogo, Runtime::MAPITERNEXT, loc, 1, p1);
- post->add_statement(Statement::make_statement(call, true));
+ s = Statement::make_statement(call, true);
+ s->determine_types(gogo);
+ post->add_statement(s);
*ppost = post;
}
@@ -7008,7 +7585,7 @@ For_range_statement::lower_range_map(Gogo* gogo,
// Lower a for range over a channel.
void
-For_range_statement::lower_range_channel(Gogo*,
+For_range_statement::lower_range_channel(Gogo* gogo,
Block*,
Block* body_block,
Named_object* range_object,
@@ -7061,6 +7638,7 @@ For_range_statement::lower_range_channel(Gogo*,
oref->set_is_lvalue();
Statement* s = Statement::make_tuple_receive_assignment(iref, oref, cref,
loc);
+ s->determine_types(gogo);
iter_init->add_statement(s);
Block* then_block = new Block(iter_init, loc);
@@ -7070,6 +7648,7 @@ For_range_statement::lower_range_channel(Gogo*,
oref = Expression::make_temporary_reference(ok_temp, loc);
Expression* cond = Expression::make_unary(OPERATOR_NOT, oref, loc);
s = Statement::make_if_statement(cond, then_block, NULL, loc);
+ s->determine_types(gogo);
iter_init->add_statement(s);
*piter_init = iter_init;
@@ -7125,7 +7704,9 @@ For_range_statement::lower_map_range_clear(Gogo* gogo,
Expression* e1 = Expression::make_type_descriptor(map_type, loc);
Expression* e2 = this->make_range_ref(range_object, range_temp, loc);
call = Runtime::make_call(gogo, Runtime::MAPCLEAR, loc, 2, e1, e2);
- return Statement::make_statement(call, true);
+ Statement* s = Statement::make_statement(call, true);
+ s->determine_types(gogo);
+ return s;
}
// Match
@@ -7193,6 +7774,7 @@ For_range_statement::lower_array_range_clear(Gogo* gogo,
ref = this->make_range_ref(range_object, range_temp, loc);
Expression* len = this->call_builtin(gogo, "len", ref, loc);
Temporary_statement* tslen = Statement::make_temporary(NULL, len, loc);
+ tslen->determine_types(gogo);
temp_block->add_statement(tslen);
Expression* zero = Expression::make_integer_ul(0, this->index_var_->type(), loc);
@@ -7201,12 +7783,14 @@ For_range_statement::lower_array_range_clear(Gogo* gogo,
elem->array_index_expression()->set_needs_bounds_check(false);
Expression* e1 = Expression::make_unary(OPERATOR_AND, elem, loc);
Temporary_statement* ts1 = Statement::make_temporary(NULL, e1, loc);
+ ts1->determine_types(gogo);
b->add_statement(ts1);
len = Expression::make_temporary_reference(tslen, loc);
Expression* sz = Expression::make_integer_int64(elme_sz, len->type(), loc);
Expression* e2 = Expression::make_binary(OPERATOR_MULT, len, sz, loc);
Temporary_statement* ts2 = Statement::make_temporary(NULL, e2, loc);
+ ts2->determine_types(gogo);
b->add_statement(ts2);
Expression* ptr_arg = Expression::make_temporary_reference(ts1, loc);
@@ -7223,6 +7807,7 @@ For_range_statement::lower_array_range_clear(Gogo* gogo,
zero32, sz_arg);
}
Statement* cs3 = Statement::make_statement(call, true);
+ cs3->determine_types(gogo);
b->add_statement(cs3);
len = Expression::make_temporary_reference(tslen, loc);
@@ -7230,12 +7815,15 @@ For_range_statement::lower_array_range_clear(Gogo* gogo,
Expression* rhs = Expression::make_binary(OPERATOR_MINUS, len, one, loc);
Expression* lhs = this->index_var_->copy();
Statement* as4 = Statement::make_assignment(lhs, rhs, loc);
+ as4->determine_types(gogo);
b->add_statement(as4);
len = Expression::make_temporary_reference(tslen, loc);
zero = zero->copy();
Expression* cond = Expression::make_binary(OPERATOR_NOTEQ, len, zero, loc);
- return Statement::make_if_statement(cond, b, NULL, loc);
+ Statement* ret = Statement::make_if_statement(cond, b, NULL, loc);
+ ret->determine_types(gogo);
+ return ret;
}
// Return the break LABEL_EXPR.