This patch improves the Go frontend to give an error for any variables that are set but not used. This matches the behaviour of the gc Go compiler. This Go language spec does not require this, but it is permitted as an implementation restriction, and it seems like a good idea to make the compilers compatible. This required changing one test in the testsuite; I've sent a patch to the master testsuite with this change (https://codereview.appspot.com/116050043). Bootstrapped and ran updated Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline.
Ian
Index: gcc/go/gofrontend/parse.cc =================================================================== --- gcc/go/gofrontend/parse.cc (revision 212872) +++ gcc/go/gofrontend/parse.cc (working copy) @@ -2115,8 +2115,8 @@ Parse::simple_var_decl_or_assignment(con for (Typed_identifier_list::const_iterator p = til.begin(); p != til.end(); ++p) - exprs->push_back(this->id_to_expression(p->name(), - p->location())); + exprs->push_back(this->id_to_expression(p->name(), p->location(), + true)); Expression_list* more_exprs = this->expression_list(NULL, true, may_be_composite_lit); @@ -2509,7 +2509,10 @@ Parse::operand(bool may_be_sink, bool* i } case Named_object::NAMED_OBJECT_VAR: case Named_object::NAMED_OBJECT_RESULT_VAR: - this->mark_var_used(named_object); + // Any left-hand-side can be a sink, so if this can not be + // a sink, then it must be a use of the variable. + if (!may_be_sink) + this->mark_var_used(named_object); return Expression::make_var_reference(named_object, location); case Named_object::NAMED_OBJECT_SINK: if (may_be_sink) @@ -2724,7 +2727,7 @@ Parse::composite_lit(Type* type, int dep Gogo* gogo = this->gogo_; val = this->id_to_expression(gogo->pack_hidden_name(identifier, is_exported), - location); + location, false); is_name = true; } else @@ -3241,7 +3244,8 @@ Parse::call(Expression* func) // Return an expression for a single unqualified identifier. Expression* -Parse::id_to_expression(const std::string& name, Location location) +Parse::id_to_expression(const std::string& name, Location location, + bool is_lhs) { Named_object* in_function; Named_object* named_object = this->gogo_->lookup(name, &in_function); @@ -3260,7 +3264,8 @@ Parse::id_to_expression(const std::strin return Expression::make_const_reference(named_object, location); case Named_object::NAMED_OBJECT_VAR: case Named_object::NAMED_OBJECT_RESULT_VAR: - this->mark_var_used(named_object); + if (!is_lhs) + this->mark_var_used(named_object); return Expression::make_var_reference(named_object, location); case Named_object::NAMED_OBJECT_SINK: return Expression::make_sink(location); @@ -5025,7 +5030,7 @@ Parse::send_or_recv_stmt(bool* is_send, *val = this->id_to_expression(gogo->pack_hidden_name(recv_var, is_rv_exported), - recv_var_loc); + recv_var_loc, true); saw_comma = true; } else @@ -5727,6 +5732,13 @@ Parse::verify_not_sink(Expression* expr) error_at(expr->location(), "cannot use _ as value"); expr = Expression::make_error(expr->location()); } + + // If this can not be a sink, and it is a variable, then we are + // using the variable, not just assigning to it. + Var_expression* ve = expr->var_expression(); + if (ve != NULL) + this->mark_var_used(ve->named_object()); + return expr; } Index: gcc/go/gofrontend/parse.h =================================================================== --- gcc/go/gofrontend/parse.h (revision 212872) +++ gcc/go/gofrontend/parse.h (working copy) @@ -236,7 +236,7 @@ class Parse bool* is_type_switch, bool* is_parenthesized); Type* reassociate_chan_direction(Channel_type*, Location); Expression* qualified_expr(Expression*, Location); - Expression* id_to_expression(const std::string&, Location); + Expression* id_to_expression(const std::string&, Location, bool); void statement(Label*); bool statement_may_start_here(); void labeled_stmt(const std::string&, Location); Index: gcc/testsuite/go.test/test/shift1.go =================================================================== --- gcc/testsuite/go.test/test/shift1.go (revision 212872) +++ gcc/testsuite/go.test/test/shift1.go (working copy) @@ -238,4 +238,6 @@ func _() { z = (1. << s) << (1 << s) // ERROR "non-integer|type complex128" z = (1. << s) << (1. << s) // ERROR "non-integer|type complex128" z = (1.1 << s) << (1.1 << s) // ERROR "invalid|truncated|complex128" + + _, _, _ = x, y, z }