Commit b1b3aec1 by Ian Lance Taylor

compiler: Give an error if a variable is defined but not used.

From-SVN: r183458
parent 8bae34da
...@@ -1472,6 +1472,7 @@ Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) ...@@ -1472,6 +1472,7 @@ Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
real->message_name().c_str()); real->message_name().c_str());
return Expression::make_error(location); return Expression::make_error(location);
case Named_object::NAMED_OBJECT_VAR: case Named_object::NAMED_OBJECT_VAR:
real->var_value()->set_is_used();
return Expression::make_var_reference(real, location); return Expression::make_var_reference(real, location);
case Named_object::NAMED_OBJECT_FUNC: case Named_object::NAMED_OBJECT_FUNC:
case Named_object::NAMED_OBJECT_FUNC_DECLARATION: case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
......
...@@ -1036,6 +1036,23 @@ Gogo::add_named_object(Named_object* no) ...@@ -1036,6 +1036,23 @@ Gogo::add_named_object(Named_object* no)
this->current_bindings()->add_named_object(no); this->current_bindings()->add_named_object(no);
} }
// Mark all local variables used. This is used when some types of
// parse error occur.
void
Gogo::mark_locals_used()
{
for (Open_functions::iterator pf = this->functions_.begin();
pf != this->functions_.end();
++pf)
{
for (std::vector<Block*>::iterator pb = pf->blocks.begin();
pb != pf->blocks.end();
++pb)
(*pb)->bindings()->mark_locals_used();
}
}
// Record that we've seen an interface type. // Record that we've seen an interface type.
void void
...@@ -1731,6 +1748,15 @@ Check_types_traverse::variable(Named_object* named_object) ...@@ -1731,6 +1748,15 @@ Check_types_traverse::variable(Named_object* named_object)
reason.c_str()); reason.c_str());
var->clear_init(); var->clear_init();
} }
else if (!var->is_used()
&& !var->is_global()
&& !var->is_parameter()
&& !var->is_receiver()
&& !var->type()->is_error()
&& (init == NULL || !init->is_error_expression())
&& !Lex::is_invalid_identifier(named_object->name()))
error_at(var->location(), "%qs declared and not used",
named_object->message_name().c_str());
} }
return TRAVERSE_CONTINUE; return TRAVERSE_CONTINUE;
} }
...@@ -2973,6 +2999,7 @@ Function::closure_var() ...@@ -2973,6 +2999,7 @@ Function::closure_var()
Type* struct_type = Type::make_struct_type(sfl, loc); Type* struct_type = Type::make_struct_type(sfl, loc);
Variable* var = new Variable(Type::make_pointer_type(struct_type), Variable* var = new Variable(Type::make_pointer_type(struct_type),
NULL, false, true, false, loc); NULL, false, true, false, loc);
var->set_is_used();
this->closure_var_ = Named_object::make_variable("closure", NULL, var); this->closure_var_ = Named_object::make_variable("closure", NULL, var);
// Note that the new variable is not in any binding contour. // Note that the new variable is not in any binding contour.
} }
...@@ -3693,7 +3720,7 @@ Variable::Variable(Type* type, Expression* init, bool is_global, ...@@ -3693,7 +3720,7 @@ Variable::Variable(Type* type, Expression* init, bool is_global,
Location location) Location location)
: type_(type), init_(init), preinit_(NULL), location_(location), : type_(type), init_(init), preinit_(NULL), location_(location),
backend_(NULL), is_global_(is_global), is_parameter_(is_parameter), backend_(NULL), is_global_(is_global), is_parameter_(is_parameter),
is_receiver_(is_receiver), is_varargs_parameter_(false), is_receiver_(is_receiver), is_varargs_parameter_(false), is_used_(false),
is_address_taken_(false), is_non_escaping_address_taken_(false), is_address_taken_(false), is_non_escaping_address_taken_(false),
seen_(false), init_is_lowered_(false), type_from_init_tuple_(false), seen_(false), init_is_lowered_(false), type_from_init_tuple_(false),
type_from_range_index_(false), type_from_range_value_(false), type_from_range_index_(false), type_from_range_value_(false),
...@@ -4877,6 +4904,19 @@ Bindings::define_type(Named_object* no, Named_type* type) ...@@ -4877,6 +4904,19 @@ Bindings::define_type(Named_object* no, Named_type* type)
this->named_objects_.push_back(no); this->named_objects_.push_back(no);
} }
// Mark all local variables as used. This is used for some types of
// parse error.
void
Bindings::mark_locals_used()
{
for (std::vector<Named_object*>::iterator p = this->named_objects_.begin();
p != this->named_objects_.end();
++p)
if ((*p)->is_variable())
(*p)->var_value()->set_is_used();
}
// Traverse bindings. // Traverse bindings.
int int
......
...@@ -344,6 +344,11 @@ class Gogo ...@@ -344,6 +344,11 @@ class Gogo
void void
add_named_object(Named_object*); add_named_object(Named_object*);
// Mark all local variables in current bindings as used. This is
// used when there is a parse error to avoid useless errors.
void
mark_locals_used();
// Return a name to use for a thunk function. A thunk function is // Return a name to use for a thunk function. A thunk function is
// one we create during the compilation, for a go statement or a // one we create during the compilation, for a go statement or a
// defer statement or a method expression. // defer statement or a method expression.
...@@ -1232,6 +1237,16 @@ class Variable ...@@ -1232,6 +1237,16 @@ class Variable
this->is_varargs_parameter_ = true; this->is_varargs_parameter_ = true;
} }
// Return whether the variable has been used.
bool
is_used() const
{ return this->is_used_; }
// Mark that the variable has been used.
void
set_is_used()
{ this->is_used_ = true; }
// Clear the initial value; used for error handling. // Clear the initial value; used for error handling.
void void
clear_init() clear_init()
...@@ -1368,6 +1383,8 @@ class Variable ...@@ -1368,6 +1383,8 @@ class Variable
bool is_receiver_ : 1; bool is_receiver_ : 1;
// Whether this is the varargs parameter of a function. // Whether this is the varargs parameter of a function.
bool is_varargs_parameter_ : 1; bool is_varargs_parameter_ : 1;
// Whether this variable is ever referenced.
bool is_used_ : 1;
// Whether something takes the address of this variable. For a // Whether something takes the address of this variable. For a
// local variable this implies that the variable has to be on the // local variable this implies that the variable has to be on the
// heap. // heap.
...@@ -2124,6 +2141,11 @@ class Bindings ...@@ -2124,6 +2141,11 @@ class Bindings
void void
remove_binding(Named_object*); remove_binding(Named_object*);
// Mark all variables as used. This is used for some types of parse
// error.
void
mark_locals_used();
// Traverse the tree. See the Traverse class. // Traverse the tree. See the Traverse class.
int int
traverse(Traverse*, bool is_global); traverse(Traverse*, bool is_global);
......
...@@ -866,6 +866,7 @@ Lex::gather_identifier() ...@@ -866,6 +866,7 @@ Lex::gather_identifier()
this->lineoff_ = p - this->linebuf_; this->lineoff_ = p - this->linebuf_;
const char* pnext = this->advance_one_utf8_char(p, &ci, const char* pnext = this->advance_one_utf8_char(p, &ci,
&issued_error); &issued_error);
bool is_invalid = false;
if (!Lex::is_unicode_letter(ci) && !Lex::is_unicode_digit(ci)) if (!Lex::is_unicode_letter(ci) && !Lex::is_unicode_digit(ci))
{ {
// There is no valid place for a non-ASCII character // There is no valid place for a non-ASCII character
...@@ -876,6 +877,7 @@ Lex::gather_identifier() ...@@ -876,6 +877,7 @@ Lex::gather_identifier()
error_at(this->location(), error_at(this->location(),
"invalid character 0x%x in identifier", "invalid character 0x%x in identifier",
ci); ci);
is_invalid = true;
} }
if (is_first) if (is_first)
{ {
...@@ -887,6 +889,8 @@ Lex::gather_identifier() ...@@ -887,6 +889,8 @@ Lex::gather_identifier()
buf.assign(pstart, p - pstart); buf.assign(pstart, p - pstart);
has_non_ascii_char = true; has_non_ascii_char = true;
} }
if (is_invalid && !Lex::is_invalid_identifier(buf))
buf.append("$INVALID$");
p = pnext; p = pnext;
char ubuf[50]; char ubuf[50];
// This assumes that all assemblers can handle an identifier // This assumes that all assemblers can handle an identifier
...@@ -2312,3 +2316,13 @@ Lex::is_exported_name(const std::string& name) ...@@ -2312,3 +2316,13 @@ Lex::is_exported_name(const std::string& name)
return Lex::is_unicode_uppercase(ci); return Lex::is_unicode_uppercase(ci);
} }
} }
// Return whether the identifier NAME contains an invalid character.
// This is based on how we handle invalid characters in
// gather_identifier.
bool
Lex::is_invalid_identifier(const std::string& name)
{
return name.find("$INVALID$") != std::string::npos;
}
...@@ -349,6 +349,13 @@ class Lex ...@@ -349,6 +349,13 @@ class Lex
static bool static bool
is_exported_name(const std::string& name); is_exported_name(const std::string& name);
// Return whether the identifier NAME is invalid. When we see an
// invalid character we still build an identifier, but we use a
// magic string to indicate that the identifier is invalid. We then
// use this to avoid knockon errors.
static bool
is_invalid_identifier(const std::string& name);
// A helper function. Append V to STR. IS_CHARACTER is true if V // A helper function. Append V to STR. IS_CHARACTER is true if V
// is a Unicode character which should be converted into UTF-8, // is a Unicode character which should be converted into UTF-8,
// false if it is a byte value to be appended directly. The // false if it is a byte value to be appended directly. The
......
...@@ -49,7 +49,8 @@ Parse::Parse(Lex* lex, Gogo* gogo) ...@@ -49,7 +49,8 @@ Parse::Parse(Lex* lex, Gogo* gogo)
break_stack_(NULL), break_stack_(NULL),
continue_stack_(NULL), continue_stack_(NULL),
iota_(0), iota_(0),
enclosing_vars_() enclosing_vars_(),
type_switch_vars_()
{ {
} }
...@@ -539,6 +540,7 @@ Parse::field_decl(Struct_field_list* sfl) ...@@ -539,6 +540,7 @@ Parse::field_decl(Struct_field_list* sfl)
else else
{ {
error_at(this->location(), "expected field name"); error_at(this->location(), "expected field name");
this->gogo_->mark_locals_used();
while (!token->is_op(OPERATOR_SEMICOLON) while (!token->is_op(OPERATOR_SEMICOLON)
&& !token->is_op(OPERATOR_RCURLY) && !token->is_op(OPERATOR_RCURLY)
&& !token->is_eof()) && !token->is_eof())
...@@ -554,6 +556,7 @@ Parse::field_decl(Struct_field_list* sfl) ...@@ -554,6 +556,7 @@ Parse::field_decl(Struct_field_list* sfl)
if (!this->peek_token()->is_identifier()) if (!this->peek_token()->is_identifier())
{ {
error_at(this->location(), "expected field name"); error_at(this->location(), "expected field name");
this->gogo_->mark_locals_used();
while (!token->is_op(OPERATOR_SEMICOLON) while (!token->is_op(OPERATOR_SEMICOLON)
&& !token->is_op(OPERATOR_RCURLY) && !token->is_op(OPERATOR_RCURLY)
&& !token->is_eof()) && !token->is_eof())
...@@ -1123,6 +1126,8 @@ Parse::block() ...@@ -1123,6 +1126,8 @@ Parse::block()
if (!token->is_eof() || !saw_errors()) if (!token->is_eof() || !saw_errors())
error_at(this->location(), "expected %<}%>"); error_at(this->location(), "expected %<}%>");
this->gogo_->mark_locals_used();
// Skip ahead to the end of the block, in hopes of avoiding // Skip ahead to the end of the block, in hopes of avoiding
// lots of meaningless errors. // lots of meaningless errors.
Location ret = token->location(); Location ret = token->location();
...@@ -1249,6 +1254,7 @@ Parse::method_spec(Typed_identifier_list* methods) ...@@ -1249,6 +1254,7 @@ Parse::method_spec(Typed_identifier_list* methods)
"name list not allowed in interface type"); "name list not allowed in interface type");
else else
error_at(location, "expected signature or type name"); error_at(location, "expected signature or type name");
this->gogo_->mark_locals_used();
token = this->peek_token(); token = this->peek_token();
while (!token->is_eof() while (!token->is_eof()
&& !token->is_op(OPERATOR_SEMICOLON) && !token->is_op(OPERATOR_SEMICOLON)
...@@ -1498,6 +1504,7 @@ Parse::type_spec(void*) ...@@ -1498,6 +1504,7 @@ Parse::type_spec(void*)
if (type->is_error_type()) if (type->is_error_type())
{ {
this->gogo_->mark_locals_used();
while (!this->peek_token()->is_op(OPERATOR_SEMICOLON) while (!this->peek_token()->is_op(OPERATOR_SEMICOLON)
&& !this->peek_token()->is_eof()) && !this->peek_token()->is_eof())
this->advance_token(); this->advance_token();
...@@ -1558,6 +1565,7 @@ Parse::var_spec(void*) ...@@ -1558,6 +1565,7 @@ Parse::var_spec(void*)
type = this->type(); type = this->type();
if (type->is_error_type()) if (type->is_error_type())
{ {
this->gogo_->mark_locals_used();
while (!this->peek_token()->is_op(OPERATOR_EQ) while (!this->peek_token()->is_op(OPERATOR_EQ)
&& !this->peek_token()->is_op(OPERATOR_SEMICOLON) && !this->peek_token()->is_op(OPERATOR_SEMICOLON)
&& !this->peek_token()->is_eof()) && !this->peek_token()->is_eof())
...@@ -1894,6 +1902,7 @@ Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init, ...@@ -1894,6 +1902,7 @@ Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init,
// initializer can be assigned to the type. // initializer can be assigned to the type.
Variable* var = new Variable(type, init, false, false, false, Variable* var = new Variable(type, init, false, false, false,
location); location);
var->set_is_used();
static int count; static int count;
char buf[30]; char buf[30];
snprintf(buf, sizeof buf, "sink$%d", count); snprintf(buf, sizeof buf, "sink$%d", count);
...@@ -2188,6 +2197,7 @@ Parse::receiver() ...@@ -2188,6 +2197,7 @@ Parse::receiver()
if (!token->is_identifier()) if (!token->is_identifier())
{ {
error_at(this->location(), "method has no receiver"); error_at(this->location(), "method has no receiver");
this->gogo_->mark_locals_used();
while (!token->is_eof() && !token->is_op(OPERATOR_RPAREN)) while (!token->is_eof() && !token->is_op(OPERATOR_RPAREN))
token = this->advance_token(); token = this->advance_token();
if (!token->is_eof()) if (!token->is_eof())
...@@ -2227,6 +2237,7 @@ Parse::receiver() ...@@ -2227,6 +2237,7 @@ Parse::receiver()
if (!token->is_identifier()) if (!token->is_identifier())
{ {
error_at(this->location(), "expected receiver name or type"); error_at(this->location(), "expected receiver name or type");
this->gogo_->mark_locals_used();
int c = token->is_op(OPERATOR_LPAREN) ? 1 : 0; int c = token->is_op(OPERATOR_LPAREN) ? 1 : 0;
while (!token->is_eof()) while (!token->is_eof())
{ {
...@@ -2258,6 +2269,7 @@ Parse::receiver() ...@@ -2258,6 +2269,7 @@ Parse::receiver()
error_at(this->location(), "method has multiple receivers"); error_at(this->location(), "method has multiple receivers");
else else
error_at(this->location(), "expected %<)%>"); error_at(this->location(), "expected %<)%>");
this->gogo_->mark_locals_used();
while (!token->is_eof() && !token->is_op(OPERATOR_RPAREN)) while (!token->is_eof() && !token->is_op(OPERATOR_RPAREN))
token = this->advance_token(); token = this->advance_token();
if (!token->is_eof()) if (!token->is_eof())
...@@ -2365,6 +2377,7 @@ Parse::operand(bool may_be_sink) ...@@ -2365,6 +2377,7 @@ Parse::operand(bool may_be_sink)
} }
case Named_object::NAMED_OBJECT_VAR: case Named_object::NAMED_OBJECT_VAR:
case Named_object::NAMED_OBJECT_RESULT_VAR: case Named_object::NAMED_OBJECT_RESULT_VAR:
this->mark_var_used(named_object);
return Expression::make_var_reference(named_object, location); return Expression::make_var_reference(named_object, location);
case Named_object::NAMED_OBJECT_SINK: case Named_object::NAMED_OBJECT_SINK:
if (may_be_sink) if (may_be_sink)
...@@ -2477,6 +2490,8 @@ Parse::enclosing_var_reference(Named_object* in_function, Named_object* var, ...@@ -2477,6 +2490,8 @@ Parse::enclosing_var_reference(Named_object* in_function, Named_object* var,
{ {
go_assert(var->is_variable() || var->is_result_variable()); go_assert(var->is_variable() || var->is_result_variable());
this->mark_var_used(var);
Named_object* this_function = this->gogo_->current_function(); Named_object* this_function = this->gogo_->current_function();
Named_object* closure = this_function->func_value()->closure_var(); Named_object* closure = this_function->func_value()->closure_var();
...@@ -2648,6 +2663,7 @@ Parse::composite_lit(Type* type, int depth, Location location) ...@@ -2648,6 +2663,7 @@ Parse::composite_lit(Type* type, int depth, Location location)
{ {
error_at(this->location(), "expected %<,%> or %<}%>"); error_at(this->location(), "expected %<,%> or %<}%>");
this->gogo_->mark_locals_used();
int depth = 0; int depth = 0;
while (!token->is_eof() while (!token->is_eof()
&& (depth > 0 || !token->is_op(OPERATOR_RCURLY))) && (depth > 0 || !token->is_op(OPERATOR_RCURLY)))
...@@ -3019,6 +3035,7 @@ Parse::id_to_expression(const std::string& name, Location location) ...@@ -3019,6 +3035,7 @@ Parse::id_to_expression(const std::string& name, Location location)
return Expression::make_const_reference(named_object, location); return Expression::make_const_reference(named_object, location);
case Named_object::NAMED_OBJECT_VAR: case Named_object::NAMED_OBJECT_VAR:
case Named_object::NAMED_OBJECT_RESULT_VAR: case Named_object::NAMED_OBJECT_RESULT_VAR:
this->mark_var_used(named_object);
return Expression::make_var_reference(named_object, location); return Expression::make_var_reference(named_object, location);
case Named_object::NAMED_OBJECT_SINK: case Named_object::NAMED_OBJECT_SINK:
return Expression::make_sink(location); return Expression::make_sink(location);
...@@ -3534,6 +3551,7 @@ Parse::simple_stat(bool may_be_composite_lit, bool* return_exp, ...@@ -3534,6 +3551,7 @@ Parse::simple_stat(bool may_be_composite_lit, bool* return_exp,
{ {
if (!exp->is_error_expression()) if (!exp->is_error_expression())
error_at(token->location(), "non-name on left side of %<:=%>"); error_at(token->location(), "non-name on left side of %<:=%>");
this->gogo_->mark_locals_used();
while (!token->is_op(OPERATOR_SEMICOLON) while (!token->is_op(OPERATOR_SEMICOLON)
&& !token->is_eof()) && !token->is_eof())
token = this->advance_token(); token = this->advance_token();
...@@ -4287,7 +4305,15 @@ Parse::type_case_clause(Named_object* switch_no, Type_case_clauses* clauses, ...@@ -4287,7 +4305,15 @@ Parse::type_case_clause(Named_object* switch_no, Type_case_clauses* clauses,
Variable* v = new Variable(type, init, false, false, false, Variable* v = new Variable(type, init, false, false, false,
location); location);
v->set_is_type_switch_var(); v->set_is_type_switch_var();
this->gogo_->add_variable(switch_no->name(), v); Named_object* no = this->gogo_->add_variable(switch_no->name(), v);
// We don't want to issue an error if the compiler
// introduced special variable is not used. Instead we want
// to issue an error if the variable defined by the switch
// is not used. That is handled via type_switch_vars_ and
// Parse::mark_var_used.
v->set_is_used();
this->type_switch_vars_[no] = switch_no;
} }
this->statement_list(); this->statement_list();
statements = this->gogo_->finish_block(this->location()); statements = this->gogo_->finish_block(this->location());
...@@ -4343,6 +4369,7 @@ Parse::type_switch_case(std::vector<Type*>* types, bool* is_default) ...@@ -4343,6 +4369,7 @@ Parse::type_switch_case(std::vector<Type*>* types, bool* is_default)
types->push_back(t); types->push_back(t);
else else
{ {
this->gogo_->mark_locals_used();
token = this->peek_token(); token = this->peek_token();
while (!token->is_op(OPERATOR_COLON) while (!token->is_op(OPERATOR_COLON)
&& !token->is_op(OPERATOR_COMMA) && !token->is_op(OPERATOR_COMMA)
...@@ -5209,6 +5236,7 @@ Parse::program() ...@@ -5209,6 +5236,7 @@ Parse::program()
else else
{ {
error_at(this->location(), "expected declaration"); error_at(this->location(), "expected declaration");
this->gogo_->mark_locals_used();
do do
this->advance_token(); this->advance_token();
while (!this->peek_token()->is_eof() while (!this->peek_token()->is_eof()
...@@ -5267,6 +5295,7 @@ Parse::increment_iota() ...@@ -5267,6 +5295,7 @@ Parse::increment_iota()
bool bool
Parse::skip_past_error(Operator op) Parse::skip_past_error(Operator op)
{ {
this->gogo_->mark_locals_used();
const Token* token = this->peek_token(); const Token* token = this->peek_token();
while (!token->is_op(op)) while (!token->is_op(op))
{ {
...@@ -5294,3 +5323,22 @@ Parse::verify_not_sink(Expression* expr) ...@@ -5294,3 +5323,22 @@ Parse::verify_not_sink(Expression* expr)
} }
return expr; return expr;
} }
// Mark a variable as used.
void
Parse::mark_var_used(Named_object* no)
{
if (no->is_variable())
{
no->var_value()->set_is_used();
// When a type switch uses := to define a variable, then for
// each case with a single type we introduce a new variable with
// the appropriate type. When we do, if the newly introduced
// variable is used, then the type switch variable is used.
Type_switch_vars::iterator p = this->type_switch_vars_.find(no);
if (p != this->type_switch_vars_.end())
p->second->var_value()->set_is_used();
}
}
...@@ -155,6 +155,11 @@ class Parse ...@@ -155,6 +155,11 @@ class Parse
// break or continue statement with no label. // break or continue statement with no label.
typedef std::vector<std::pair<Statement*, Label*> > Bc_stack; typedef std::vector<std::pair<Statement*, Label*> > Bc_stack;
// Map from type switch variables to the variables they mask, so
// that a use of the type switch variable can become a use of the
// real variable.
typedef Unordered_map(Named_object*, Named_object*) Type_switch_vars;
// Parser nonterminals. // Parser nonterminals.
void identifier_list(Typed_identifier_list*); void identifier_list(Typed_identifier_list*);
Expression_list* expression_list(Expression*, bool may_be_sink); Expression_list* expression_list(Expression*, bool may_be_sink);
...@@ -288,6 +293,10 @@ class Parse ...@@ -288,6 +293,10 @@ class Parse
Statement* Statement*
find_bc_statement(const Bc_stack*, const std::string&) const; find_bc_statement(const Bc_stack*, const std::string&) const;
// Mark a variable as used.
void
mark_var_used(Named_object*);
// The lexer output we are parsing. // The lexer output we are parsing.
Lex* lex_; Lex* lex_;
// The current token. // The current token.
...@@ -307,6 +316,8 @@ class Parse ...@@ -307,6 +316,8 @@ class Parse
// References from the local function to variables defined in // References from the local function to variables defined in
// enclosing functions. // enclosing functions.
Enclosing_vars enclosing_vars_; Enclosing_vars enclosing_vars_;
// Map from type switch variables to real variables.
Type_switch_vars type_switch_vars_;
}; };
......
...@@ -9,4 +9,5 @@ package _ // ERROR "invalid package name _" ...@@ -9,4 +9,5 @@ package _ // ERROR "invalid package name _"
func main() { func main() {
_() // ERROR "cannot use _ as value" _() // ERROR "cannot use _ as value"
x := _+1 // ERROR "cannot use _ as value" x := _+1 // ERROR "cannot use _ as value"
_ = x
} }
...@@ -11,4 +11,5 @@ func main() { ...@@ -11,4 +11,5 @@ func main() {
var c01 uint8 = '\07'; // ERROR "oct|char" var c01 uint8 = '\07'; // ERROR "oct|char"
var cx0 uint8 = '\x0'; // ERROR "hex|char" var cx0 uint8 = '\x0'; // ERROR "hex|char"
var cx1 uint8 = '\x'; // ERROR "hex|char" var cx1 uint8 = '\x'; // ERROR "hex|char"
_, _, _, _ = c00, c01, cx0, cx1
} }
...@@ -7,4 +7,5 @@ ...@@ -7,4 +7,5 @@
package main package main
func f() { func f() {
v := 1 << 1025; // ERROR "overflow|stupid shift" v := 1 << 1025; // ERROR "overflow|stupid shift"
_ = v
} }
...@@ -20,7 +20,7 @@ type Getter interface { ...@@ -20,7 +20,7 @@ type Getter interface {
func f1(p Empty) { func f1(p Empty) {
switch x := p.(type) { switch x := p.(type) {
default: println("failed to match interface"); os.Exit(1); default: println("failed to match interface", x); os.Exit(1);
case Getter: break; case Getter: break;
} }
......
...@@ -10,5 +10,5 @@ func f() (int, bool) { return 0, true } ...@@ -10,5 +10,5 @@ func f() (int, bool) { return 0, true }
func main() { func main() {
x, y := f(), 2; // ERROR "multi" x, y := f(), 2; // ERROR "multi"
_, _ = x, y
} }
...@@ -12,7 +12,7 @@ func main() { ...@@ -12,7 +12,7 @@ func main() {
// and worse, compiled the wrong code // and worse, compiled the wrong code
// for one of them. // for one of them.
var x interface{}; var x interface{};
switch v := x.(type) { switch x.(type) {
case func(int): case func(int):
case func(f int): // ERROR "duplicate" case func(f int): // ERROR "duplicate"
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
package main package main
func main() { func main() {
var v interface{} = 0; var v interface{} = 0;
switch x := v.(type) { switch v.(type) {
case int: case int:
fallthrough; // ERROR "fallthrough" fallthrough; // ERROR "fallthrough"
default: default:
......
...@@ -80,7 +80,7 @@ func main() { ...@@ -80,7 +80,7 @@ func main() {
case 2: case 2:
i = 3.14 i = 3.14
} }
switch k := i.(type) { switch i.(type) {
case p0.T: case p0.T:
if j != 0 { if j != 0 {
println("type switch p0.T") println("type switch p0.T")
......
...@@ -15,5 +15,7 @@ func foo(t interface{}, c chan int) { ...@@ -15,5 +15,7 @@ func foo(t interface{}, c chan int) {
case <-c: case <-c:
// bug was: internal compiler error: var without type, init: v // bug was: internal compiler error: var without type, init: v
} }
default:
_ = v
} }
} }
...@@ -17,5 +17,5 @@ func main() { ...@@ -17,5 +17,5 @@ func main() {
println(b) println(b)
var c int64 = (1<<i) + 4.0 // ok - it's all int64 var c int64 = (1<<i) + 4.0 // ok - it's all int64
println(b) println(c)
} }
...@@ -11,4 +11,5 @@ var notmain func() ...@@ -11,4 +11,5 @@ var notmain func()
func main() { func main() {
var x = &main // ERROR "address of|invalid" var x = &main // ERROR "address of|invalid"
main = notmain // ERROR "assign to|invalid" main = notmain // ERROR "assign to|invalid"
_ = x
} }
...@@ -65,4 +65,5 @@ func f() { ...@@ -65,4 +65,5 @@ func f() {
cap(b2)+ // ERROR "illegal|invalid|must be" cap(b2)+ // ERROR "illegal|invalid|must be"
cap(b3)+ cap(b3)+
cap(b4) // ERROR "illegal|invalid|must be" cap(b4) // ERROR "illegal|invalid|must be"
_ = x
} }
...@@ -71,13 +71,13 @@ func TestReadDir(t *testing.T) { ...@@ -71,13 +71,13 @@ func TestReadDir(t *testing.T) {
t.Fatalf("ReadDir %s: error expected, none found", dirname) t.Fatalf("ReadDir %s: error expected, none found", dirname)
} }
/* Does not work in gccgo testing environment.
dirname = ".." dirname = ".."
list, err := ReadDir(dirname) list, err := ReadDir(dirname)
if err != nil { if err != nil {
t.Fatalf("ReadDir %s: %v", dirname, err) t.Fatalf("ReadDir %s: %v", dirname, err)
} }
/* Does not work in gccgo testing environment.
foundFile := false foundFile := false
foundSubDir := false foundSubDir := false
for _, dir := range list { for _, dir := range list {
...@@ -94,5 +94,5 @@ func TestReadDir(t *testing.T) { ...@@ -94,5 +94,5 @@ func TestReadDir(t *testing.T) {
if !foundSubDir { if !foundSubDir {
t.Fatalf("ReadDir %s: ioutil directory not found", dirname) t.Fatalf("ReadDir %s: ioutil directory not found", dirname)
} }
*/ */
} }
...@@ -243,7 +243,7 @@ type commonType struct { ...@@ -243,7 +243,7 @@ type commonType struct {
align int8 align int8
fieldAlign uint8 fieldAlign uint8
size uintptr size uintptr
hash uint32 hash uint32
hashfn func(unsafe.Pointer, uintptr) hashfn func(unsafe.Pointer, uintptr)
equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr)
string *string string *string
...@@ -464,7 +464,7 @@ func (t *uncommonType) Method(i int) (m Method) { ...@@ -464,7 +464,7 @@ func (t *uncommonType) Method(i int) (m Method) {
m.Type = mt.toType() m.Type = mt.toType()
x := new(unsafe.Pointer) x := new(unsafe.Pointer)
*x = p.tfn *x = p.tfn
m.Func = Value{mt, unsafe.Pointer(x), fl|flagIndir} m.Func = Value{mt, unsafe.Pointer(x), fl | flagIndir}
m.Index = i m.Index = i
return return
} }
...@@ -999,10 +999,8 @@ func (ct *commonType) ptrTo() *commonType { ...@@ -999,10 +999,8 @@ func (ct *commonType) ptrTo() *commonType {
return &p.commonType return &p.commonType
} }
rt := (*runtime.Type)(unsafe.Pointer(ct))
rp := new(runtime.PtrType) rp := new(runtime.PtrType)
// initialize p using *byte's ptrType as a prototype. // initialize p using *byte's ptrType as a prototype.
// have to do assignment as ptrType, not runtime.PtrType, // have to do assignment as ptrType, not runtime.PtrType,
// in order to write to unexported fields. // in order to write to unexported fields.
......
...@@ -215,8 +215,8 @@ type emptyInterface struct { ...@@ -215,8 +215,8 @@ type emptyInterface struct {
type nonEmptyInterface struct { type nonEmptyInterface struct {
// see ../runtime/iface.c:/Itab // see ../runtime/iface.c:/Itab
itab *struct { itab *struct {
typ *runtime.Type // dynamic concrete type typ *runtime.Type // dynamic concrete type
fun [100000]unsafe.Pointer // method table fun [100000]unsafe.Pointer // method table
} }
word iword word iword
} }
...@@ -448,7 +448,6 @@ func (v Value) call(method string, in []Value) []Value { ...@@ -448,7 +448,6 @@ func (v Value) call(method string, in []Value) []Value {
nin++ nin++
} }
params := make([]unsafe.Pointer, nin) params := make([]unsafe.Pointer, nin)
delta := 0
off := 0 off := 0
if v.flag&flagMethod != 0 { if v.flag&flagMethod != 0 {
// Hard-wired first argument. // Hard-wired first argument.
...@@ -517,7 +516,7 @@ func isMethod(t *commonType) bool { ...@@ -517,7 +516,7 @@ func isMethod(t *commonType) bool {
params++ params++
} else if c == ')' { } else if c == ')' {
parens-- parens--
} else if parens == 0 && c == ' ' && s[i + 1] != '(' && !sawRet { } else if parens == 0 && c == ' ' && s[i+1] != '(' && !sawRet {
params++ params++
sawRet = true sawRet = true
} }
...@@ -1627,7 +1626,7 @@ func MakeChan(typ Type, buffer int) Value { ...@@ -1627,7 +1626,7 @@ func MakeChan(typ Type, buffer int) Value {
panic("reflect.MakeChan: unidirectional channel type") panic("reflect.MakeChan: unidirectional channel type")
} }
ch := makechan(typ.runtimeType(), uint32(buffer)) ch := makechan(typ.runtimeType(), uint32(buffer))
return Value{typ.common(), unsafe.Pointer(ch), flagIndir | (flag(Chan)<<flagKindShift)} return Value{typ.common(), unsafe.Pointer(ch), flagIndir | (flag(Chan) << flagKindShift)}
} }
// MakeMap creates a new map of the specified type. // MakeMap creates a new map of the specified type.
...@@ -1636,7 +1635,7 @@ func MakeMap(typ Type) Value { ...@@ -1636,7 +1635,7 @@ func MakeMap(typ Type) Value {
panic("reflect.MakeMap of non-map type") panic("reflect.MakeMap of non-map type")
} }
m := makemap(typ.runtimeType()) m := makemap(typ.runtimeType())
return Value{typ.common(), unsafe.Pointer(m), flagIndir | (flag(Map)<<flagKindShift)} return Value{typ.common(), unsafe.Pointer(m), flagIndir | (flag(Map) << flagKindShift)}
} }
// Indirect returns the value that v points to. // Indirect returns the value that v points to.
......
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