Commit bed6238c by Ian Lance Taylor

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

From-SVN: r192022
parent e1d90a81
...@@ -1631,12 +1631,16 @@ Parse::init_vars(const Typed_identifier_list* til, Type* type, ...@@ -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 // 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 // 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; Expression_list::const_iterator pexpr;
if (init != NULL) if (init != NULL)
pexpr = init->begin(); pexpr = init->begin();
bool any_new = false; 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(); for (Typed_identifier_list::const_iterator p = til->begin();
p != til->end(); p != til->end();
++p) ++p)
...@@ -1644,7 +1648,7 @@ Parse::init_vars(const Typed_identifier_list* til, Type* type, ...@@ -1644,7 +1648,7 @@ Parse::init_vars(const Typed_identifier_list* til, Type* type,
if (init != NULL) if (init != NULL)
go_assert(pexpr != init->end()); go_assert(pexpr != init->end());
this->init_var(*p, type, init == NULL ? NULL : *pexpr, is_coloneq, this->init_var(*p, type, init == NULL ? NULL : *pexpr, is_coloneq,
false, &any_new); false, &any_new, vars, vals);
if (init != NULL) if (init != NULL)
++pexpr; ++pexpr;
} }
...@@ -1652,6 +1656,7 @@ Parse::init_vars(const Typed_identifier_list* til, Type* type, ...@@ -1652,6 +1656,7 @@ Parse::init_vars(const Typed_identifier_list* til, Type* type,
go_assert(pexpr == init->end()); go_assert(pexpr == init->end());
if (is_coloneq && !any_new) if (is_coloneq && !any_new)
error_at(location, "variables redeclared but no variable is 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 // 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, ...@@ -1674,13 +1679,15 @@ Parse::init_vars_from_call(const Typed_identifier_list* vars, Type* type,
Named_object* first_var = NULL; Named_object* first_var = NULL;
unsigned int index = 0; unsigned int index = 0;
bool any_new = false; 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(); for (Typed_identifier_list::const_iterator pv = vars->begin();
pv != vars->end(); pv != vars->end();
++pv, ++index) ++pv, ++index)
{ {
Expression* init = Expression::make_call_result(call, index); Expression* init = Expression::make_call_result(call, index);
Named_object* no = this->init_var(*pv, type, init, is_coloneq, false, 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()) 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, ...@@ -1700,6 +1707,8 @@ Parse::init_vars_from_call(const Typed_identifier_list* vars, Type* type,
if (is_coloneq && !any_new) if (is_coloneq && !any_new)
error_at(location, "variables redeclared but no variable is new"); error_at(location, "variables redeclared but no variable is new");
this->finish_init_vars(ivars, ivals, location);
return true; return true;
} }
...@@ -1725,7 +1734,7 @@ Parse::init_vars_from_map(const Typed_identifier_list* vars, Type* type, ...@@ -1725,7 +1734,7 @@ Parse::init_vars_from_map(const Typed_identifier_list* vars, Type* type,
Typed_identifier_list::const_iterator p = vars->begin(); Typed_identifier_list::const_iterator p = vars->begin();
Expression* init = type == NULL ? index : NULL; Expression* init = type == NULL ? index : NULL;
Named_object* val_no = this->init_var(*p, type, init, is_coloneq, 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()) if (type == NULL && any_new && val_no->is_variable())
val_no->var_value()->set_type_from_init_tuple(); val_no->var_value()->set_type_from_init_tuple();
Expression* val_var = Expression::make_var_reference(val_no, location); 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, ...@@ -1735,7 +1744,7 @@ Parse::init_vars_from_map(const Typed_identifier_list* vars, Type* type,
if (var_type == NULL) if (var_type == NULL)
var_type = Type::lookup_bool_type(); var_type = Type::lookup_bool_type();
Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false, 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); Expression* present_var = Expression::make_var_reference(no, location);
if (is_coloneq && !any_new) if (is_coloneq && !any_new)
...@@ -1790,7 +1799,7 @@ Parse::init_vars_from_receive(const Typed_identifier_list* vars, Type* type, ...@@ -1790,7 +1799,7 @@ Parse::init_vars_from_receive(const Typed_identifier_list* vars, Type* type,
Typed_identifier_list::const_iterator p = vars->begin(); Typed_identifier_list::const_iterator p = vars->begin();
Expression* init = type == NULL ? receive : NULL; Expression* init = type == NULL ? receive : NULL;
Named_object* val_no = this->init_var(*p, type, init, is_coloneq, 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()) if (type == NULL && any_new && val_no->is_variable())
val_no->var_value()->set_type_from_init_tuple(); val_no->var_value()->set_type_from_init_tuple();
Expression* val_var = Expression::make_var_reference(val_no, location); 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, ...@@ -1800,7 +1809,7 @@ Parse::init_vars_from_receive(const Typed_identifier_list* vars, Type* type,
if (var_type == NULL) if (var_type == NULL)
var_type = Type::lookup_bool_type(); var_type = Type::lookup_bool_type();
Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false, 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); Expression* received_var = Expression::make_var_reference(no, location);
if (is_coloneq && !any_new) if (is_coloneq && !any_new)
...@@ -1857,7 +1866,7 @@ Parse::init_vars_from_type_guard(const Typed_identifier_list* vars, ...@@ -1857,7 +1866,7 @@ Parse::init_vars_from_type_guard(const Typed_identifier_list* vars,
if (var_type == NULL) if (var_type == NULL)
var_type = type_guard->type(); var_type = type_guard->type();
Named_object* val_no = this->init_var(*p, var_type, NULL, is_coloneq, false, 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); Expression* val_var = Expression::make_var_reference(val_no, location);
++p; ++p;
...@@ -1865,7 +1874,7 @@ Parse::init_vars_from_type_guard(const Typed_identifier_list* vars, ...@@ -1865,7 +1874,7 @@ Parse::init_vars_from_type_guard(const Typed_identifier_list* vars,
if (var_type == NULL) if (var_type == NULL)
var_type = Type::lookup_bool_type(); var_type = Type::lookup_bool_type();
Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false, 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* ok_var = Expression::make_var_reference(no, location);
Expression* texpr = type_guard->expr(); Expression* texpr = type_guard->expr();
...@@ -1904,7 +1913,8 @@ Parse::init_vars_from_type_guard(const Typed_identifier_list* vars, ...@@ -1904,7 +1913,8 @@ Parse::init_vars_from_type_guard(const Typed_identifier_list* vars,
Named_object* Named_object*
Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init, 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(); Location location = tid.location();
...@@ -1946,9 +1956,9 @@ Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init, ...@@ -1946,9 +1956,9 @@ Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init,
// like v, ok := x.(int). // like v, ok := x.(int).
if (!type_from_init && init != NULL) if (!type_from_init && init != NULL)
{ {
Expression *v = Expression::make_var_reference(no, location); go_assert(vars != NULL && vals != NULL);
Statement *s = Statement::make_assignment(v, init, location); vars->push_back(Expression::make_var_reference(no, location));
this->gogo_->add_statement(s); vals->push_back(init);
} }
return no; return no;
} }
...@@ -1983,6 +1993,36 @@ Parse::create_dummy_global(Type* type, Expression* init, ...@@ -1983,6 +1993,36 @@ Parse::create_dummy_global(Type* type, Expression* init,
return this->gogo_->add_variable(buf, var); 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 . // SimpleVarDecl = identifier ":=" Expression .
// We've already seen the identifier. // We've already seen the identifier.
...@@ -5113,7 +5153,8 @@ Parse::range_clause_decl(const Typed_identifier_list* til, ...@@ -5113,7 +5153,8 @@ Parse::range_clause_decl(const Typed_identifier_list* til,
bool any_new = false; bool any_new = false;
const Typed_identifier* pti = &til->front(); 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()) if (any_new && no->is_variable())
no->var_value()->set_type_from_range_index(); no->var_value()->set_type_from_range_index();
p_range_clause->index = Expression::make_var_reference(no, location); p_range_clause->index = Expression::make_var_reference(no, location);
...@@ -5124,7 +5165,7 @@ Parse::range_clause_decl(const Typed_identifier_list* til, ...@@ -5124,7 +5165,7 @@ Parse::range_clause_decl(const Typed_identifier_list* til,
{ {
pti = &til->back(); pti = &til->back();
bool is_new = false; 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()) if (is_new && no->is_variable())
no->var_value()->set_type_from_range_value(); no->var_value()->set_type_from_range_value();
if (is_new) if (is_new)
......
...@@ -206,8 +206,11 @@ class Parse ...@@ -206,8 +206,11 @@ class Parse
Expression*, bool is_coloneq, Expression*, bool is_coloneq,
Location); Location);
Named_object* init_var(const Typed_identifier&, Type*, Expression*, 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); 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, void simple_var_decl_or_assignment(const std::string&, Location,
bool may_be_composite_lit, bool may_be_composite_lit,
Range_clause*, Type_switch*); Range_clause*, Type_switch*);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment