Commit 3c365907 by Ian Lance Taylor

Emit compiler errors for unused values.

From-SVN: r179008
parent 0274cf27
...@@ -135,13 +135,13 @@ Expression::do_traverse(Traverse*) ...@@ -135,13 +135,13 @@ Expression::do_traverse(Traverse*)
} }
// This virtual function is called by the parser if the value of this // This virtual function is called by the parser if the value of this
// expression is being discarded. By default, we warn. Expressions // expression is being discarded. By default, we give an error.
// with side effects override. // Expressions with side effects override.
void void
Expression::do_discarding_value() Expression::do_discarding_value()
{ {
this->warn_about_unused_value(); this->unused_value_error();
} }
// This virtual function is called to export expressions. This will // This virtual function is called to export expressions. This will
...@@ -153,12 +153,12 @@ Expression::do_export(Export*) const ...@@ -153,12 +153,12 @@ Expression::do_export(Export*) const
go_unreachable(); go_unreachable();
} }
// Warn that the value of the expression is not used. // Give an error saying that the value of the expression is not used.
void void
Expression::warn_about_unused_value() Expression::unused_value_error()
{ {
warning_at(this->location(), OPT_Wunused_value, "value computed is not used"); error_at(this->location(), "value computed is not used");
} }
// Note that this expression is an error. This is called by children // Note that this expression is an error. This is called by children
...@@ -5832,7 +5832,7 @@ Binary_expression::do_discarding_value() ...@@ -5832,7 +5832,7 @@ Binary_expression::do_discarding_value()
if (this->op_ == OPERATOR_OROR || this->op_ == OPERATOR_ANDAND) if (this->op_ == OPERATOR_OROR || this->op_ == OPERATOR_ANDAND)
this->right_->discarding_value(); this->right_->discarding_value();
else else
this->warn_about_unused_value(); this->unused_value_error();
} }
// Get type. // Get type.
...@@ -6951,6 +6951,9 @@ class Builtin_call_expression : public Call_expression ...@@ -6951,6 +6951,9 @@ class Builtin_call_expression : public Call_expression
bool bool
do_complex_constant_value(mpfr_t, mpfr_t, Type**) const; do_complex_constant_value(mpfr_t, mpfr_t, Type**) const;
void
do_discarding_value();
Type* Type*
do_type(); do_type();
...@@ -7760,6 +7763,44 @@ Builtin_call_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag, ...@@ -7760,6 +7763,44 @@ Builtin_call_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
return false; return false;
} }
// Give an error if we are discarding the value of an expression which
// should not normally be discarded. We don't give an error for
// discarding the value of an ordinary function call, but we do for
// builtin functions, purely for consistency with the gc compiler.
void
Builtin_call_expression::do_discarding_value()
{
switch (this->code_)
{
case BUILTIN_INVALID:
default:
go_unreachable();
case BUILTIN_APPEND:
case BUILTIN_CAP:
case BUILTIN_COMPLEX:
case BUILTIN_IMAG:
case BUILTIN_LEN:
case BUILTIN_MAKE:
case BUILTIN_NEW:
case BUILTIN_REAL:
case BUILTIN_ALIGNOF:
case BUILTIN_OFFSETOF:
case BUILTIN_SIZEOF:
this->unused_value_error();
break;
case BUILTIN_CLOSE:
case BUILTIN_COPY:
case BUILTIN_PANIC:
case BUILTIN_PRINT:
case BUILTIN_PRINTLN:
case BUILTIN_RECOVER:
break;
}
}
// Return the type. // Return the type.
Type* Type*
...@@ -11241,7 +11282,7 @@ Selector_expression::lower_method_expression(Gogo* gogo) ...@@ -11241,7 +11282,7 @@ Selector_expression::lower_method_expression(Gogo* gogo)
size_t count = call->result_count(); size_t count = call->result_count();
Statement* s; Statement* s;
if (count == 0) if (count == 0)
s = Statement::make_statement(call); s = Statement::make_statement(call, true);
else else
{ {
Expression_list* retvals = new Expression_list(); Expression_list* retvals = new Expression_list();
......
...@@ -359,9 +359,9 @@ class Expression ...@@ -359,9 +359,9 @@ class Expression
string_constant_value(std::string* val) const string_constant_value(std::string* val) const
{ return this->do_string_constant_value(val); } { return this->do_string_constant_value(val); }
// This is called by the parser if the value of this expression is // This is called if the value of this expression is being
// being discarded. This issues warnings about computed values // discarded. This issues warnings about computed values being
// being unused. // unused.
void void
discarding_value() discarding_value()
{ this->do_discarding_value(); } { this->do_discarding_value(); }
...@@ -725,9 +725,9 @@ class Expression ...@@ -725,9 +725,9 @@ class Expression
virtual void virtual void
do_export(Export*) const; do_export(Export*) const;
// For children to call to warn about an unused value. // For children to call to give an error for an unused value.
void void
warn_about_unused_value(); unused_value_error();
// For children to call when they detect that they are in error. // For children to call when they detect that they are in error.
void void
......
...@@ -2017,7 +2017,7 @@ Order_eval::statement(Block* block, size_t* pindex, Statement* s) ...@@ -2017,7 +2017,7 @@ Order_eval::statement(Block* block, size_t* pindex, Statement* s)
// be handled specially. We can't create a temporary // be handled specially. We can't create a temporary
// because there is no type to give it. Any actual uses of // because there is no type to give it. Any actual uses of
// the values will be done via Call_result_expressions. // the values will be done via Call_result_expressions.
s = Statement::make_statement(*pexpr); s = Statement::make_statement(*pexpr, true);
} }
block->insert_statement_before(*pindex, s); block->insert_statement_before(*pindex, s);
...@@ -2072,7 +2072,7 @@ Order_eval::variable(Named_object* no) ...@@ -2072,7 +2072,7 @@ Order_eval::variable(Named_object* no)
{ {
// A call expression which returns multiple results needs to // A call expression which returns multiple results needs to
// be handled specially. // be handled specially.
s = Statement::make_statement(*pexpr); s = Statement::make_statement(*pexpr, true);
} }
var->add_preinit_statement(this->gogo_, s); var->add_preinit_statement(this->gogo_, s);
} }
...@@ -2266,7 +2266,7 @@ Build_recover_thunks::function(Named_object* orig_no) ...@@ -2266,7 +2266,7 @@ Build_recover_thunks::function(Named_object* orig_no)
Statement* s; Statement* s;
if (orig_fntype->results() == NULL || orig_fntype->results()->empty()) if (orig_fntype->results() == NULL || orig_fntype->results()->empty())
s = Statement::make_statement(call); s = Statement::make_statement(call, true);
else else
{ {
Expression_list* vals = new Expression_list(); Expression_list* vals = new Expression_list();
......
...@@ -1839,7 +1839,7 @@ Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init, ...@@ -1839,7 +1839,7 @@ Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init,
if (!type_from_init && init != NULL) if (!type_from_init && init != NULL)
{ {
if (!this->gogo_->in_global_scope()) if (!this->gogo_->in_global_scope())
this->gogo_->add_statement(Statement::make_statement(init)); this->gogo_->add_statement(Statement::make_statement(init, true));
else else
return this->create_dummy_global(type, init, location); return this->create_dummy_global(type, init, location);
} }
...@@ -3506,8 +3506,7 @@ Parse::statement_list_may_start_here() ...@@ -3506,8 +3506,7 @@ Parse::statement_list_may_start_here()
void void
Parse::expression_stat(Expression* exp) Parse::expression_stat(Expression* exp)
{ {
exp->discarding_value(); this->gogo_->add_statement(Statement::make_statement(exp, false));
this->gogo_->add_statement(Statement::make_statement(exp));
} }
// SendStmt = Channel "<-" Expression . // SendStmt = Channel "<-" Expression .
......
...@@ -924,7 +924,7 @@ Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing, ...@@ -924,7 +924,7 @@ Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
if ((*plhs)->is_sink_expression()) if ((*plhs)->is_sink_expression())
{ {
b->add_statement(Statement::make_statement(*prhs)); b->add_statement(Statement::make_statement(*prhs, true));
continue; continue;
} }
...@@ -1240,7 +1240,7 @@ Map_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing, ...@@ -1240,7 +1240,7 @@ Map_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
Expression* p4 = Expression::make_temporary_reference(insert_temp, loc); Expression* p4 = Expression::make_temporary_reference(insert_temp, loc);
Expression* call = Runtime::make_call(Runtime::MAPASSIGN2, loc, 4, Expression* call = Runtime::make_call(Runtime::MAPASSIGN2, loc, 4,
p1, p2, p3, p4); p1, p2, p3, p4);
Statement* s = Statement::make_statement(call); Statement* s = Statement::make_statement(call, true);
b->add_statement(s); b->add_statement(s);
return Statement::make_block_statement(b, loc); return Statement::make_block_statement(b, loc);
...@@ -1614,9 +1614,9 @@ Statement::make_tuple_type_guard_assignment(Expression* val, Expression* ok, ...@@ -1614,9 +1614,9 @@ Statement::make_tuple_type_guard_assignment(Expression* val, Expression* ok,
class Expression_statement : public Statement class Expression_statement : public Statement
{ {
public: public:
Expression_statement(Expression* expr) Expression_statement(Expression* expr, bool is_ignored)
: Statement(STATEMENT_EXPRESSION, expr->location()), : Statement(STATEMENT_EXPRESSION, expr->location()),
expr_(expr) expr_(expr), is_ignored_(is_ignored)
{ } { }
Expression* Expression*
...@@ -1632,6 +1632,9 @@ class Expression_statement : public Statement ...@@ -1632,6 +1632,9 @@ class Expression_statement : public Statement
do_determine_types() do_determine_types()
{ this->expr_->determine_type_no_context(); } { this->expr_->determine_type_no_context(); }
void
do_check_types(Gogo*);
bool bool
do_may_fall_through() const; do_may_fall_through() const;
...@@ -1643,8 +1646,21 @@ class Expression_statement : public Statement ...@@ -1643,8 +1646,21 @@ class Expression_statement : public Statement
private: private:
Expression* expr_; Expression* expr_;
// Whether the value of this expression is being explicitly ignored.
bool is_ignored_;
}; };
// Check the types of an expression statement. The only check we do
// is to possibly give an error about discarding the value of the
// expression.
void
Expression_statement::do_check_types(Gogo*)
{
if (!this->is_ignored_)
this->expr_->discarding_value();
}
// An expression statement may fall through unless it is a call to a // An expression statement may fall through unless it is a call to a
// function which does not return. // function which does not return.
...@@ -1699,9 +1715,9 @@ Expression_statement::do_dump_statement(Ast_dump_context* ast_dump_context) ...@@ -1699,9 +1715,9 @@ Expression_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
// Make an expression statement from an Expression. // Make an expression statement from an Expression.
Statement* Statement*
Statement::make_statement(Expression* expr) Statement::make_statement(Expression* expr, bool is_ignored)
{ {
return new Expression_statement(expr); return new Expression_statement(expr, is_ignored);
} }
// A block statement--a list of statements which may include variable // A block statement--a list of statements which may include variable
...@@ -2374,7 +2390,7 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name) ...@@ -2374,7 +2390,7 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
// receiver parameter. // receiver parameter.
call->set_varargs_are_lowered(); call->set_varargs_are_lowered();
Statement* call_statement = Statement::make_statement(call); Statement* call_statement = Statement::make_statement(call, true);
gogo->add_statement(call_statement); gogo->add_statement(call_statement);
...@@ -3791,7 +3807,7 @@ Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing, ...@@ -3791,7 +3807,7 @@ Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
Expression* val = this->val_; Expression* val = this->val_;
if (val == NULL) if (val == NULL)
val = Expression::make_boolean(true, loc); val = Expression::make_boolean(true, loc);
return Statement::make_statement(val); return Statement::make_statement(val, true);
} }
Temporary_statement* val_temp; Temporary_statement* val_temp;
...@@ -4516,7 +4532,7 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function, ...@@ -4516,7 +4532,7 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
} }
else else
{ {
init->add_statement(Statement::make_statement(recv)); init->add_statement(Statement::make_statement(recv, true));
} }
} }
...@@ -5593,7 +5609,7 @@ For_range_statement::lower_range_map(Gogo*, ...@@ -5593,7 +5609,7 @@ For_range_statement::lower_range_map(Gogo*,
Expression* ref = Expression::make_temporary_reference(hiter, loc); Expression* ref = Expression::make_temporary_reference(hiter, loc);
Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc); Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
Expression* call = Runtime::make_call(Runtime::MAPITERINIT, loc, 2, p1, p2); Expression* call = Runtime::make_call(Runtime::MAPITERINIT, loc, 2, p1, p2);
init->add_statement(Statement::make_statement(call)); init->add_statement(Statement::make_statement(call, true));
*pinit = init; *pinit = init;
...@@ -5634,7 +5650,7 @@ For_range_statement::lower_range_map(Gogo*, ...@@ -5634,7 +5650,7 @@ For_range_statement::lower_range_map(Gogo*,
Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc); Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
call = Runtime::make_call(Runtime::MAPITER2, loc, 3, p1, p2, p3); call = Runtime::make_call(Runtime::MAPITER2, loc, 3, p1, p2, p3);
} }
iter_init->add_statement(Statement::make_statement(call)); iter_init->add_statement(Statement::make_statement(call, true));
*piter_init = iter_init; *piter_init = iter_init;
...@@ -5646,7 +5662,7 @@ For_range_statement::lower_range_map(Gogo*, ...@@ -5646,7 +5662,7 @@ For_range_statement::lower_range_map(Gogo*,
ref = Expression::make_temporary_reference(hiter, loc); ref = Expression::make_temporary_reference(hiter, loc);
p1 = Expression::make_unary(OPERATOR_AND, ref, loc); p1 = Expression::make_unary(OPERATOR_AND, ref, loc);
call = Runtime::make_call(Runtime::MAPITERNEXT, loc, 1, p1); call = Runtime::make_call(Runtime::MAPITERNEXT, loc, 1, p1);
post->add_statement(Statement::make_statement(call)); post->add_statement(Statement::make_statement(call, true));
*ppost = post; *ppost = post;
} }
......
...@@ -178,9 +178,11 @@ class Statement ...@@ -178,9 +178,11 @@ class Statement
Expression* expr, Type* type, Expression* expr, Type* type,
source_location); source_location);
// Make an expression statement from an Expression. // Make an expression statement from an Expression. IS_IGNORED is
// true if the value is being explicitly ignored, as in an
// assignment to _.
static Statement* static Statement*
make_statement(Expression*); make_statement(Expression*, bool is_ignored);
// Make a block statement from a Block. This is an embedded list of // Make a block statement from a Block. This is an embedded list of
// statements which may also include variable definitions. // statements which may also include variable definitions.
......
...@@ -7432,7 +7432,7 @@ Type::build_one_stub_method(Gogo* gogo, Method* method, ...@@ -7432,7 +7432,7 @@ Type::build_one_stub_method(Gogo* gogo, Method* method,
call->set_hidden_fields_are_ok(); call->set_hidden_fields_are_ok();
size_t count = call->result_count(); size_t count = call->result_count();
if (count == 0) if (count == 0)
gogo->add_statement(Statement::make_statement(call)); gogo->add_statement(Statement::make_statement(call, true));
else else
{ {
Expression_list* retvals = new Expression_list(); Expression_list* retvals = new Expression_list();
......
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