compiler: Fix a, b, c := b, a, 1 when a and b already exist.

From-SVN: r192022
This commit is contained in:
Ian Lance Taylor 2012-10-03 05:03:24 +00:00
parent e1d90a813c
commit bed6238ce6
2 changed files with 60 additions and 16 deletions

View File

@ -1631,12 +1631,16 @@ Parse::init_vars(const Typed_identifier_list* til, Type* type,
// Note that INIT was already parsed with the old name bindings, so
// we don't have to worry that it will accidentally refer to the
// newly declared variables.
// newly declared variables. But we do have to worry about a mix of
// newly declared variables and old variables if the old variables
// appear in the initializations.
Expression_list::const_iterator pexpr;
if (init != NULL)
pexpr = init->begin();
bool any_new = false;
Expression_list* vars = new Expression_list();
Expression_list* vals = new Expression_list();
for (Typed_identifier_list::const_iterator p = til->begin();
p != til->end();
++p)
@ -1644,7 +1648,7 @@ Parse::init_vars(const Typed_identifier_list* til, Type* type,
if (init != NULL)
go_assert(pexpr != init->end());
this->init_var(*p, type, init == NULL ? NULL : *pexpr, is_coloneq,
false, &any_new);
false, &any_new, vars, vals);
if (init != NULL)
++pexpr;
}
@ -1652,6 +1656,7 @@ Parse::init_vars(const Typed_identifier_list* til, Type* type,
go_assert(pexpr == init->end());
if (is_coloneq && !any_new)
error_at(location, "variables redeclared but no variable is new");
this->finish_init_vars(vars, vals, location);
}
// See if we need to initialize a list of variables from a function
@ -1674,13 +1679,15 @@ Parse::init_vars_from_call(const Typed_identifier_list* vars, Type* type,
Named_object* first_var = NULL;
unsigned int index = 0;
bool any_new = false;
Expression_list* ivars = new Expression_list();
Expression_list* ivals = new Expression_list();
for (Typed_identifier_list::const_iterator pv = vars->begin();
pv != vars->end();
++pv, ++index)
{
Expression* init = Expression::make_call_result(call, index);
Named_object* no = this->init_var(*pv, type, init, is_coloneq, false,
&any_new);
&any_new, ivars, ivals);
if (this->gogo_->in_global_scope() && no->is_variable())
{
@ -1700,6 +1707,8 @@ Parse::init_vars_from_call(const Typed_identifier_list* vars, Type* type,
if (is_coloneq && !any_new)
error_at(location, "variables redeclared but no variable is new");
this->finish_init_vars(ivars, ivals, location);
return true;
}
@ -1725,7 +1734,7 @@ Parse::init_vars_from_map(const Typed_identifier_list* vars, Type* type,
Typed_identifier_list::const_iterator p = vars->begin();
Expression* init = type == NULL ? index : NULL;
Named_object* val_no = this->init_var(*p, type, init, is_coloneq,
type == NULL, &any_new);
type == NULL, &any_new, NULL, NULL);
if (type == NULL && any_new && val_no->is_variable())
val_no->var_value()->set_type_from_init_tuple();
Expression* val_var = Expression::make_var_reference(val_no, location);
@ -1735,7 +1744,7 @@ Parse::init_vars_from_map(const Typed_identifier_list* vars, Type* type,
if (var_type == NULL)
var_type = Type::lookup_bool_type();
Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false,
&any_new);
&any_new, NULL, NULL);
Expression* present_var = Expression::make_var_reference(no, location);
if (is_coloneq && !any_new)
@ -1790,7 +1799,7 @@ Parse::init_vars_from_receive(const Typed_identifier_list* vars, Type* type,
Typed_identifier_list::const_iterator p = vars->begin();
Expression* init = type == NULL ? receive : NULL;
Named_object* val_no = this->init_var(*p, type, init, is_coloneq,
type == NULL, &any_new);
type == NULL, &any_new, NULL, NULL);
if (type == NULL && any_new && val_no->is_variable())
val_no->var_value()->set_type_from_init_tuple();
Expression* val_var = Expression::make_var_reference(val_no, location);
@ -1800,7 +1809,7 @@ Parse::init_vars_from_receive(const Typed_identifier_list* vars, Type* type,
if (var_type == NULL)
var_type = Type::lookup_bool_type();
Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false,
&any_new);
&any_new, NULL, NULL);
Expression* received_var = Expression::make_var_reference(no, location);
if (is_coloneq && !any_new)
@ -1857,7 +1866,7 @@ Parse::init_vars_from_type_guard(const Typed_identifier_list* vars,
if (var_type == NULL)
var_type = type_guard->type();
Named_object* val_no = this->init_var(*p, var_type, NULL, is_coloneq, false,
&any_new);
&any_new, NULL, NULL);
Expression* val_var = Expression::make_var_reference(val_no, location);
++p;
@ -1865,7 +1874,7 @@ Parse::init_vars_from_type_guard(const Typed_identifier_list* vars,
if (var_type == NULL)
var_type = Type::lookup_bool_type();
Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false,
&any_new);
&any_new, NULL, NULL);
Expression* ok_var = Expression::make_var_reference(no, location);
Expression* texpr = type_guard->expr();
@ -1904,7 +1913,8 @@ Parse::init_vars_from_type_guard(const Typed_identifier_list* vars,
Named_object*
Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init,
bool is_coloneq, bool type_from_init, bool* is_new)
bool is_coloneq, bool type_from_init, bool* is_new,
Expression_list* vars, Expression_list* vals)
{
Location location = tid.location();
@ -1946,9 +1956,9 @@ Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init,
// like v, ok := x.(int).
if (!type_from_init && init != NULL)
{
Expression *v = Expression::make_var_reference(no, location);
Statement *s = Statement::make_assignment(v, init, location);
this->gogo_->add_statement(s);
go_assert(vars != NULL && vals != NULL);
vars->push_back(Expression::make_var_reference(no, location));
vals->push_back(init);
}
return no;
}
@ -1983,6 +1993,36 @@ Parse::create_dummy_global(Type* type, Expression* init,
return this->gogo_->add_variable(buf, var);
}
// Finish the variable initialization by executing any assignments to
// existing variables when using :=. These must be done as a tuple
// assignment in case of something like n, a, b := 1, b, a.
void
Parse::finish_init_vars(Expression_list* vars, Expression_list* vals,
Location location)
{
if (vars->empty())
{
delete vars;
delete vals;
}
else if (vars->size() == 1)
{
go_assert(!this->gogo_->in_global_scope());
this->gogo_->add_statement(Statement::make_assignment(vars->front(),
vals->front(),
location));
delete vars;
delete vals;
}
else
{
go_assert(!this->gogo_->in_global_scope());
this->gogo_->add_statement(Statement::make_tuple_assignment(vars, vals,
location));
}
}
// SimpleVarDecl = identifier ":=" Expression .
// We've already seen the identifier.
@ -5113,7 +5153,8 @@ Parse::range_clause_decl(const Typed_identifier_list* til,
bool any_new = false;
const Typed_identifier* pti = &til->front();
Named_object* no = this->init_var(*pti, NULL, expr, true, true, &any_new);
Named_object* no = this->init_var(*pti, NULL, expr, true, true, &any_new,
NULL, NULL);
if (any_new && no->is_variable())
no->var_value()->set_type_from_range_index();
p_range_clause->index = Expression::make_var_reference(no, location);
@ -5124,7 +5165,7 @@ Parse::range_clause_decl(const Typed_identifier_list* til,
{
pti = &til->back();
bool is_new = false;
no = this->init_var(*pti, NULL, expr, true, true, &is_new);
no = this->init_var(*pti, NULL, expr, true, true, &is_new, NULL, NULL);
if (is_new && no->is_variable())
no->var_value()->set_type_from_range_value();
if (is_new)

View File

@ -206,8 +206,11 @@ class Parse
Expression*, bool is_coloneq,
Location);
Named_object* init_var(const Typed_identifier&, Type*, Expression*,
bool is_coloneq, bool type_from_init, bool* is_new);
bool is_coloneq, bool type_from_init, bool* is_new,
Expression_list* vars, Expression_list* vals);
Named_object* create_dummy_global(Type*, Expression*, Location);
void finish_init_vars(Expression_list* vars, Expression_list* vals,
Location);
void simple_var_decl_or_assignment(const std::string&, Location,
bool may_be_composite_lit,
Range_clause*, Type_switch*);