// If we get here it means that a single nested function refers to
// two different variables defined in enclosing functions, and both
// variables have the same name. I think this is impossible.
- gcc_unreachable();
+ go_unreachable();
}
// Class Parse.
void
Parse::unget_token(const Token& token)
{
- gcc_assert(!this->unget_token_valid_);
+ go_assert(!this->unget_token_valid_);
this->unget_token_ = token;
this->unget_token_valid_ = true;
}
bool ok = true;
if (named_object == NULL)
{
- if (package != NULL)
- ok = false;
- else
+ if (package == NULL)
named_object = this->gogo_->add_unknown_name(name, location);
+ else
+ {
+ const std::string& packname(package->package_value()->name());
+ error_at(location, "reference to undefined identifier %<%s.%s%>",
+ Gogo::message_name(packname).c_str(),
+ Gogo::message_name(name).c_str());
+ issue_error = false;
+ ok = false;
+ }
}
else if (named_object->is_type())
{
else if (named_object->is_unknown() || named_object->is_type_declaration())
return Type::make_forward_declaration(named_object);
else
- gcc_unreachable();
+ go_unreachable();
}
// ArrayType = "[" [ ArrayLength ] "]" ElementType .
Type*
Parse::array_type(bool may_use_ellipsis)
{
- gcc_assert(this->peek_token()->is_op(OPERATOR_LSQUARE));
+ go_assert(this->peek_token()->is_op(OPERATOR_LSQUARE));
const Token* token = this->advance_token();
Expression* length = NULL;
Parse::map_type()
{
source_location location = this->location();
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_MAP));
+ go_assert(this->peek_token()->is_keyword(KEYWORD_MAP));
if (!this->advance_token()->is_op(OPERATOR_LSQUARE))
{
error_at(this->location(), "expected %<[%>");
Type*
Parse::struct_type()
{
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_STRUCT));
+ go_assert(this->peek_token()->is_keyword(KEYWORD_STRUCT));
source_location location = this->location();
if (!this->advance_token()->is_op(OPERATOR_LCURLY))
{
Type*
Parse::pointer_type()
{
- gcc_assert(this->peek_token()->is_op(OPERATOR_MULT));
+ go_assert(this->peek_token()->is_op(OPERATOR_MULT));
this->advance_token();
Type* type = this->type();
if (type->is_error_type())
}
else
{
- gcc_assert(token->is_keyword(KEYWORD_CHAN));
+ go_assert(token->is_keyword(KEYWORD_CHAN));
if (this->advance_token()->is_op(OPERATOR_CHANOP))
{
receive = false;
return Type::make_channel_type(send, receive, element_type);
}
+// Give an error for a duplicate parameter or receiver name.
+
+void
+Parse::check_signature_names(const Typed_identifier_list* params,
+ Parse::Names* names)
+{
+ for (Typed_identifier_list::const_iterator p = params->begin();
+ p != params->end();
+ ++p)
+ {
+ if (p->name().empty() || Gogo::is_sink_name(p->name()))
+ continue;
+ std::pair<std::string, const Typed_identifier*> val =
+ std::make_pair(p->name(), &*p);
+ std::pair<Parse::Names::iterator, bool> ins = names->insert(val);
+ if (!ins.second)
+ {
+ error_at(p->location(), "redefinition of %qs",
+ Gogo::message_name(p->name()).c_str());
+ inform(ins.first->second->location(),
+ "previous definition of %qs was here",
+ Gogo::message_name(p->name()).c_str());
+ }
+ }
+}
+
// Signature = Parameters [ Result ] .
// RECEIVER is the receiver if there is one, or NULL. LOCATION is the
Typed_identifier_list* params;
bool params_ok = this->parameters(¶ms, &is_varargs);
- Typed_identifier_list* result = NULL;
+ Typed_identifier_list* results = NULL;
if (this->peek_token()->is_op(OPERATOR_LPAREN)
|| this->type_may_start_here())
{
- if (!this->result(&result))
+ if (!this->result(&results))
return NULL;
}
if (!params_ok)
return NULL;
- Function_type* ret = Type::make_function_type(receiver, params, result,
+ Parse::Names names;
+ if (params != NULL)
+ this->check_signature_names(params, &names);
+ if (results != NULL)
+ this->check_signature_names(results, &names);
+
+ Function_type* ret = Type::make_function_type(receiver, params, results,
location);
if (is_varargs)
ret->set_is_varargs();
if (parameters_have_names)
{
- gcc_assert(!just_saw_comma);
+ go_assert(!just_saw_comma);
// We have just seen ID1, ID2 xxx.
Type* type;
if (!this->peek_token()->is_op(OPERATOR_ELLIPSIS))
Type*
Parse::interface_type()
{
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_INTERFACE));
+ go_assert(this->peek_token()->is_keyword(KEYWORD_INTERFACE));
source_location location = this->location();
if (!this->advance_token()->is_op(OPERATOR_LCURLY))
void
Parse::const_decl()
{
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_CONST));
+ go_assert(this->peek_token()->is_keyword(KEYWORD_CONST));
this->advance_token();
this->reset_iota();
void
Parse::type_decl()
{
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_TYPE));
+ go_assert(this->peek_token()->is_keyword(KEYWORD_TYPE));
this->advance_token();
this->decl(&Parse::type_spec, NULL);
}
this->gogo_->define_type(named_type,
Type::make_named_type(named_type, type,
location));
- gcc_assert(named_type->package() == NULL);
+ go_assert(named_type->package() == NULL);
}
else
{
void
Parse::var_decl()
{
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_VAR));
+ go_assert(this->peek_token()->is_keyword(KEYWORD_VAR));
this->advance_token();
this->decl(&Parse::var_spec, NULL);
}
++p)
{
if (init != NULL)
- gcc_assert(pexpr != init->end());
+ go_assert(pexpr != init->end());
this->init_var(*p, type, init == NULL ? NULL : *pexpr, is_coloneq,
false, &any_new);
if (init != NULL)
++pexpr;
}
if (init != NULL)
- gcc_assert(pexpr == init->end());
+ go_assert(pexpr == init->end());
if (is_coloneq && !any_new)
error_at(location, "variables redeclared but no variable is new");
}
if (!type_from_init && init != NULL)
{
if (!this->gogo_->in_global_scope())
- this->gogo_->add_statement(Statement::make_statement(init));
+ this->gogo_->add_statement(Statement::make_statement(init, true));
else
return this->create_dummy_global(type, init, location);
}
// "a, *p = 1, 2".
if (this->peek_token()->is_op(OPERATOR_COMMA))
{
- gcc_assert(p_type_switch == NULL);
+ go_assert(p_type_switch == NULL);
while (true)
{
const Token* token = this->advance_token();
}
}
- gcc_assert(this->peek_token()->is_op(OPERATOR_COLONEQ));
+ go_assert(this->peek_token()->is_op(OPERATOR_COLONEQ));
const Token* token = this->advance_token();
if (p_range_clause != NULL && token->is_keyword(KEYWORD_RANGE))
void
Parse::function_decl()
{
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_FUNC));
+ go_assert(this->peek_token()->is_keyword(KEYWORD_FUNC));
source_location location = this->location();
const Token* token = this->advance_token();
Typed_identifier*
Parse::receiver()
{
- gcc_assert(this->peek_token()->is_op(OPERATOR_LPAREN));
+ go_assert(this->peek_token()->is_op(OPERATOR_LPAREN));
std::string name;
const Token* token = this->advance_token();
packed = this->gogo_->pack_hidden_name(id, is_exported);
named_object = package->lookup(packed);
location = this->location();
- gcc_assert(in_function == NULL);
+ go_assert(in_function == NULL);
}
this->advance_token();
&& named_object->is_type()
&& !named_object->type_value()->is_visible())
{
- gcc_assert(package != NULL);
+ go_assert(package != NULL);
error_at(location, "invalid reference to hidden type %<%s.%s%>",
Gogo::message_name(package->name()).c_str(),
Gogo::message_name(id).c_str());
case Named_object::NAMED_OBJECT_UNKNOWN:
return Expression::make_unknown_reference(named_object, location);
default:
- gcc_unreachable();
+ go_unreachable();
}
}
- gcc_unreachable();
+ go_unreachable();
case Token::TOKEN_STRING:
ret = Expression::make_string(token->string_value(), token->location());
Parse::enclosing_var_reference(Named_object* in_function, Named_object* var,
source_location location)
{
- gcc_assert(var->is_variable() || var->is_result_variable());
+ go_assert(var->is_variable() || var->is_result_variable());
Named_object* this_function = this->gogo_->current_function();
Named_object* closure = this_function->func_value()->closure_var();
// LiteralValue = "{" [ ElementList [ "," ] ] "}" .
// ElementList = Element { "," Element } .
// Element = [ Key ":" ] Value .
-// Key = Expression .
+// Key = FieldName | ElementIndex .
+// FieldName = identifier .
+// ElementIndex = Expression .
// Value = Expression | LiteralValue .
// We have already seen the type if there is one, and we are now
Expression*
Parse::composite_lit(Type* type, int depth, source_location location)
{
- gcc_assert(this->peek_token()->is_op(OPERATOR_LCURLY));
+ go_assert(this->peek_token()->is_op(OPERATOR_LCURLY));
this->advance_token();
if (this->peek_token()->is_op(OPERATOR_RCURLY))
const Token* token = this->peek_token();
- if (!token->is_op(OPERATOR_LCURLY))
+ if (token->is_identifier())
+ {
+ std::string identifier = token->identifier();
+ bool is_exported = token->is_identifier_exported();
+ source_location location = token->location();
+
+ if (this->advance_token()->is_op(OPERATOR_COLON))
+ {
+ // This may be a field name. We don't know for sure--it
+ // could also be an expression for an array index. We
+ // don't want to parse it as an expression because may
+ // trigger various errors, e.g., if this identifier
+ // happens to be the name of a package.
+ Gogo* gogo = this->gogo_;
+ val = this->id_to_expression(gogo->pack_hidden_name(identifier,
+ is_exported),
+ location);
+ }
+ else
+ {
+ this->unget_token(Token::make_identifier_token(identifier,
+ is_exported,
+ location));
+ val = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ }
+ }
+ else if (!token->is_op(OPERATOR_LCURLY))
val = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
else
{
Parse::function_lit()
{
source_location location = this->location();
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_FUNC));
+ go_assert(this->peek_token()->is_keyword(KEYWORD_FUNC));
this->advance_token();
Enclosing_vars hold_enclosing_vars;
Expression_list* initializer = new Expression_list;
for (size_t i = 0; i < enclosing_var_count; ++i)
{
- gcc_assert(ev[i].index() == i);
+ go_assert(ev[i].index() == i);
Named_object* var = ev[i].var();
Expression* ref;
if (ev[i].in_function() == enclosing_function)
else
this->advance_token();
if (expr->is_error_expression())
- return expr;
- ret = Expression::make_cast(ret->type(), expr, loc);
+ ret = expr;
+ else
+ {
+ Type* t = ret->type();
+ if (t->classification() == Type::TYPE_ARRAY
+ && t->array_type()->length() != NULL
+ && t->array_type()->length()->is_nil_expression())
+ {
+ error_at(ret->location(),
+ "invalid use of %<...%> in type conversion");
+ ret = Expression::make_error(loc);
+ }
+ else
+ ret = Expression::make_cast(t, expr, loc);
+ }
}
}
Expression*
Parse::selector(Expression* left, bool* is_type_switch)
{
- gcc_assert(this->peek_token()->is_op(OPERATOR_DOT));
+ go_assert(this->peek_token()->is_op(OPERATOR_DOT));
source_location location = this->location();
const Token* token = this->advance_token();
Parse::index(Expression* expr)
{
source_location location = this->location();
- gcc_assert(this->peek_token()->is_op(OPERATOR_LSQUARE));
+ go_assert(this->peek_token()->is_op(OPERATOR_LSQUARE));
this->advance_token();
Expression* start;
Expression*
Parse::call(Expression* func)
{
- gcc_assert(this->peek_token()->is_op(OPERATOR_LPAREN));
+ go_assert(this->peek_token()->is_op(OPERATOR_LPAREN));
Expression_list* args = NULL;
bool is_varargs = false;
const Token* token = this->advance_token();
return Expression::make_func_reference(named_object, NULL, location);
case Named_object::NAMED_OBJECT_UNKNOWN:
return Expression::make_unknown_reference(named_object, location);
+ case Named_object::NAMED_OBJECT_PACKAGE:
+ case Named_object::NAMED_OBJECT_TYPE:
+ case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
+ // These cases can arise for a field name in a composite
+ // literal.
+ return Expression::make_unknown_reference(named_object, location);
default:
error_at(this->location(), "unexpected type of identifier");
return Expression::make_error(location);
case Token::TOKEN_IMAGINARY:
return true;
default:
- gcc_unreachable();
+ go_unreachable();
}
}
void
Parse::expression_stat(Expression* exp)
{
- exp->discarding_value();
- this->gogo_->add_statement(Statement::make_statement(exp));
+ this->gogo_->add_statement(Statement::make_statement(exp, false));
}
// SendStmt = Channel "<-" Expression .
void
Parse::send_stmt(Expression* channel)
{
- gcc_assert(this->peek_token()->is_op(OPERATOR_CHANOP));
+ go_assert(this->peek_token()->is_op(OPERATOR_CHANOP));
source_location loc = this->location();
this->advance_token();
Expression* val = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
else if (token->is_op(OPERATOR_MINUSMINUS))
this->gogo_->add_statement(Statement::make_dec_statement(exp));
else
- gcc_unreachable();
+ go_unreachable();
this->advance_token();
}
void
Parse::go_or_defer_stat()
{
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_GO)
+ go_assert(this->peek_token()->is_keyword(KEYWORD_GO)
|| this->peek_token()->is_keyword(KEYWORD_DEFER));
bool is_go = this->peek_token()->is_keyword(KEYWORD_GO);
source_location stat_location = this->location();
void
Parse::return_stat()
{
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_RETURN));
+ go_assert(this->peek_token()->is_keyword(KEYWORD_RETURN));
source_location location = this->location();
this->advance_token();
Expression_list* vals = NULL;
if (this->expression_may_start_here())
vals = this->expression_list(NULL, false);
- const Function* function = this->gogo_->current_function()->func_value();
- const Typed_identifier_list* results = function->type()->results();
- this->gogo_->add_statement(Statement::make_return_statement(results, vals,
- location));
+ this->gogo_->add_statement(Statement::make_return_statement(vals, location));
}
-// IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" Statement ] .
+// IfStmt = "if" [ SimpleStmt ";" ] Expression Block
+// [ "else" ( IfStmt | Block ) ] .
void
Parse::if_stat()
{
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_IF));
+ go_assert(this->peek_token()->is_keyword(KEYWORD_IF));
source_location location = this->location();
this->advance_token();
Block* else_block = NULL;
if (this->peek_token()->is_keyword(KEYWORD_ELSE))
{
- this->advance_token();
- // We create a block to gather the statement.
this->gogo_->start_block(this->location());
- this->statement(NULL);
+ const Token* token = this->advance_token();
+ if (token->is_keyword(KEYWORD_IF))
+ this->if_stat();
+ else if (token->is_op(OPERATOR_LCURLY))
+ this->block();
+ else
+ {
+ error_at(this->location(), "expected %<if%> or %<{%>");
+ this->statement(NULL);
+ }
else_block = this->gogo_->finish_block(this->location());
}
void
Parse::switch_stat(Label* label)
{
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_SWITCH));
+ go_assert(this->peek_token()->is_keyword(KEYWORD_SWITCH));
source_location location = this->location();
this->advance_token();
if (this->peek_token()->is_op(OPERATOR_SEMICOLON)
&& this->advance_token()->is_op(OPERATOR_LCURLY))
error_at(token_loc, "unexpected semicolon or newline before %<{%>");
+ else if (this->peek_token()->is_op(OPERATOR_COLONEQ))
+ {
+ error_at(token_loc, "invalid variable name");
+ this->advance_token();
+ this->expression(PRECEDENCE_NORMAL, false, false,
+ &type_switch.found);
+ if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
+ this->advance_token();
+ if (!this->peek_token()->is_op(OPERATOR_LCURLY))
+ return;
+ if (type_switch.found)
+ type_switch.expr = Expression::make_error(location);
+ }
else
{
error_at(this->location(), "expected %<{%>");
if (is_default)
{
- gcc_assert(types.empty());
+ go_assert(types.empty());
if (*saw_default)
{
error_at(location, "multiple defaults in type switch");
void
Parse::select_stat(Label* label)
{
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_SELECT));
+ go_assert(this->peek_token()->is_keyword(KEYWORD_SELECT));
source_location location = this->location();
const Token* token = this->advance_token();
bool got_case = this->comm_case(&is_send, &channel, &val, &closed,
&varname, &closedname, &is_default);
+ if (!is_send
+ && varname.empty()
+ && closedname.empty()
+ && val != NULL
+ && val->index_expression() != NULL)
+ val->index_expression()->set_is_lvalue();
+
if (this->peek_token()->is_op(OPERATOR_COLON))
this->advance_token();
else
error_at(this->location(), "expected colon");
- Block* statements = NULL;
+ this->gogo_->start_block(this->location());
+
Named_object* var = NULL;
- Named_object* closedvar = NULL;
- if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
- this->advance_token();
- else if (this->statement_list_may_start_here())
+ if (!varname.empty())
{
- this->gogo_->start_block(this->location());
+ // FIXME: LOCATION is slightly wrong here.
+ Variable* v = new Variable(NULL, channel, false, false, false,
+ location);
+ v->set_type_from_chan_element();
+ var = this->gogo_->add_variable(varname, v);
+ }
- if (!varname.empty())
- {
- // FIXME: LOCATION is slightly wrong here.
- Variable* v = new Variable(NULL, channel, false, false, false,
- location);
- v->set_type_from_chan_element();
- var = this->gogo_->add_variable(varname, v);
- }
+ Named_object* closedvar = NULL;
+ if (!closedname.empty())
+ {
+ // FIXME: LOCATION is slightly wrong here.
+ Variable* v = new Variable(Type::lookup_bool_type(), NULL,
+ false, false, false, location);
+ closedvar = this->gogo_->add_variable(closedname, v);
+ }
- if (!closedname.empty())
- {
- // FIXME: LOCATION is slightly wrong here.
- Variable* v = new Variable(Type::lookup_bool_type(), NULL,
- false, false, false, location);
- closedvar = this->gogo_->add_variable(closedname, v);
- }
+ this->statement_list();
- this->statement_list();
- statements = this->gogo_->finish_block(this->location());
- }
+ Block* statements = this->gogo_->finish_block(this->location());
if (is_default)
{
void
Parse::for_stat(Label* label)
{
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_FOR));
+ go_assert(this->peek_token()->is_keyword(KEYWORD_FOR));
source_location location = this->location();
const Token* token = this->advance_token();
void
Parse::for_clause(Expression** cond, Block** post)
{
- gcc_assert(this->peek_token()->is_op(OPERATOR_SEMICOLON));
+ go_assert(this->peek_token()->is_op(OPERATOR_SEMICOLON));
this->advance_token();
if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
*cond = NULL;
Parse::range_clause_decl(const Typed_identifier_list* til,
Range_clause* p_range_clause)
{
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_RANGE));
+ go_assert(this->peek_token()->is_keyword(KEYWORD_RANGE));
source_location location = this->location();
p_range_clause->found = true;
- gcc_assert(til->size() >= 1);
+ go_assert(til->size() >= 1);
if (til->size() > 2)
error_at(this->location(), "too many variables for range clause");
Parse::range_clause_expr(const Expression_list* vals,
Range_clause* p_range_clause)
{
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_RANGE));
+ go_assert(this->peek_token()->is_keyword(KEYWORD_RANGE));
p_range_clause->found = true;
- gcc_assert(vals->size() >= 1);
+ go_assert(vals->size() >= 1);
if (vals->size() > 2)
error_at(this->location(), "too many variables for range clause");
void
Parse::break_stat()
{
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_BREAK));
+ go_assert(this->peek_token()->is_keyword(KEYWORD_BREAK));
source_location location = this->location();
const Token* token = this->advance_token();
{
// If there is a label with this name, mark it as used to
// avoid a useless error about an unused label.
- this->gogo_->add_label_reference(token->identifier());
+ this->gogo_->add_label_reference(token->identifier(), 0, false);
error_at(token->location(), "invalid break label %qs",
Gogo::message_name(token->identifier()).c_str());
else if (enclosing->classification() == Statement::STATEMENT_SELECT)
label = enclosing->select_statement()->break_label();
else
- gcc_unreachable();
+ go_unreachable();
this->gogo_->add_statement(Statement::make_break_statement(label,
location));
void
Parse::continue_stat()
{
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_CONTINUE));
+ go_assert(this->peek_token()->is_keyword(KEYWORD_CONTINUE));
source_location location = this->location();
const Token* token = this->advance_token();
{
// If there is a label with this name, mark it as used to
// avoid a useless error about an unused label.
- this->gogo_->add_label_reference(token->identifier());
+ this->gogo_->add_label_reference(token->identifier(), 0, false);
error_at(token->location(), "invalid continue label %qs",
Gogo::message_name(token->identifier()).c_str());
else if (enclosing->classification() == Statement::STATEMENT_FOR_RANGE)
label = enclosing->for_range_statement()->continue_label();
else
- gcc_unreachable();
+ go_unreachable();
this->gogo_->add_statement(Statement::make_continue_statement(label,
location));
void
Parse::goto_stat()
{
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_GOTO));
+ go_assert(this->peek_token()->is_keyword(KEYWORD_GOTO));
source_location location = this->location();
const Token* token = this->advance_token();
if (!token->is_identifier())
error_at(this->location(), "expected label for goto");
else
{
- Label* label = this->gogo_->add_label_reference(token->identifier());
+ Label* label = this->gogo_->add_label_reference(token->identifier(),
+ location, true);
Statement* s = Statement::make_goto_statement(label, location);
this->gogo_->add_statement(s);
this->advance_token();
void
Parse::import_decl()
{
- gcc_assert(this->peek_token()->is_keyword(KEYWORD_IMPORT));
+ go_assert(this->peek_token()->is_keyword(KEYWORD_IMPORT));
this->advance_token();
this->decl(&Parse::import_spec, NULL);
}