location,
"__go_receive_big",
3,
- void_type_node,
+ boolean_type_node,
ptr_type_node,
channel,
ptr_type_node,
Statement* s = sorig;
while (true)
{
- Statement* snew = s->lower(this->gogo_, block);
+ Statement* snew = s->lower(this->gogo_, this->function_, block);
if (snew == s)
break;
s = snew;
this->traverse(&lower_parse_tree);
}
+// Lower a block.
+
+void
+Gogo::lower_block(Named_object* function, Block* block)
+{
+ Lower_parse_tree lower_parse_tree(this, function);
+ block->traverse(&lower_parse_tree);
+}
+
// Lower an expression.
void
void
lower_parse_tree();
+ // Lower all the statements in a block.
+ void
+ lower_block(Named_object* function, Block*);
+
// Lower an expression.
void
lower_expression(Named_object* function, Expression**);
bool is_send = false;
Expression* channel = NULL;
Expression* val = NULL;
+ Expression* closed = NULL;
std::string varname;
+ std::string closedname;
bool is_default = false;
- bool got_case = this->comm_case(&is_send, &channel, &val, &varname,
- &is_default);
+ bool got_case = this->comm_case(&is_send, &channel, &val, &closed,
+ &varname, &closedname, &is_default);
if (this->peek_token()->is_op(OPERATOR_COLON))
this->advance_token();
Block* statements = NULL;
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())
var = this->gogo_->add_variable(varname, 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();
statements = this->gogo_->finish_block(this->location());
}
}
if (got_case)
- clauses->add(is_send, channel, val, var, is_default, statements, location);
+ clauses->add(is_send, channel, val, closed, var, closedvar, is_default,
+ statements, location);
else if (statements != NULL)
{
// Add the statements to make sure that any names they define
bool
Parse::comm_case(bool* is_send, Expression** channel, Expression** val,
- std::string* varname, bool* is_default)
+ Expression** closed, std::string* varname,
+ std::string* closedname, bool* is_default)
{
const Token* token = this->peek_token();
if (token->is_keyword(KEYWORD_DEFAULT))
else if (token->is_keyword(KEYWORD_CASE))
{
this->advance_token();
- if (!this->send_or_recv_expr(is_send, channel, val, varname))
+ if (!this->send_or_recv_stmt(is_send, channel, val, closed, varname,
+ closedname))
return false;
}
else
return true;
}
-// RecvExpr = [ Expression ( "=" | ":=" ) ] "<-" Expression .
+// RecvStmt = [ Expression [ "," Expression ] ( "=" | ":=" ) ] RecvExpr .
+// RecvExpr = Expression .
bool
-Parse::send_or_recv_expr(bool* is_send, Expression** channel, Expression** val,
- std::string* varname)
+Parse::send_or_recv_stmt(bool* is_send, Expression** channel, Expression** val,
+ Expression** closed, std::string* varname,
+ std::string* closedname)
{
const Token* token = this->peek_token();
- source_location location = token->location();
+ bool saw_comma = false;
+ bool closed_is_id = false;
if (token->is_identifier())
{
+ Gogo* gogo = this->gogo_;
std::string recv_var = token->identifier();
- bool is_var_exported = token->is_identifier_exported();
- if (!this->advance_token()->is_op(OPERATOR_COLONEQ))
- this->unget_token(Token::make_identifier_token(recv_var,
- is_var_exported,
- location));
- else
+ bool is_rv_exported = token->is_identifier_exported();
+ source_location recv_var_loc = token->location();
+ token = this->advance_token();
+ if (token->is_op(OPERATOR_COLONEQ))
{
+ // case rv := <-c:
if (!this->advance_token()->is_op(OPERATOR_CHANOP))
{
error_at(this->location(), "expected %<<-%>");
return false;
}
+ if (recv_var == "_")
+ {
+ error_at(recv_var_loc,
+ "no new variables on left side of %<:=%>");
+ recv_var = "blank";
+ }
*is_send = false;
- *varname = this->gogo_->pack_hidden_name(recv_var, is_var_exported);
+ *varname = gogo->pack_hidden_name(recv_var, is_rv_exported);
this->advance_token();
*channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
return true;
}
+ else if (token->is_op(OPERATOR_COMMA))
+ {
+ token = this->advance_token();
+ if (token->is_identifier())
+ {
+ std::string recv_closed = token->identifier();
+ bool is_rc_exported = token->is_identifier_exported();
+ source_location recv_closed_loc = token->location();
+ closed_is_id = true;
+
+ token = this->advance_token();
+ if (token->is_op(OPERATOR_COLONEQ))
+ {
+ // case rv, rc := <-c:
+ if (!this->advance_token()->is_op(OPERATOR_CHANOP))
+ {
+ error_at(this->location(), "expected %<<-%>");
+ return false;
+ }
+ if (recv_var == "_" && recv_closed == "_")
+ {
+ error_at(recv_var_loc,
+ "no new variables on left side of %<:=%>");
+ recv_var = "blank";
+ }
+ *is_send = false;
+ if (recv_var != "_")
+ *varname = gogo->pack_hidden_name(recv_var,
+ is_rv_exported);
+ if (recv_closed != "_")
+ *closedname = gogo->pack_hidden_name(recv_closed,
+ is_rc_exported);
+ this->advance_token();
+ *channel = this->expression(PRECEDENCE_NORMAL, false, true,
+ NULL);
+ return true;
+ }
+
+ this->unget_token(Token::make_identifier_token(recv_closed,
+ is_rc_exported,
+ recv_closed_loc));
+ }
+
+ *val = this->id_to_expression(gogo->pack_hidden_name(recv_var,
+ is_rv_exported),
+ recv_var_loc);
+ saw_comma = true;
+ }
+ else
+ this->unget_token(Token::make_identifier_token(recv_var,
+ is_rv_exported,
+ recv_var_loc));
}
- if (this->peek_token()->is_op(OPERATOR_CHANOP))
+ // If SAW_COMMA is false, then we are looking at the start of the
+ // send or receive expression. If SAW_COMMA is true, then *VAL is
+ // set and we just read a comma.
+
+ if (!saw_comma && this->peek_token()->is_op(OPERATOR_CHANOP))
{
+ // case <-c:
*is_send = false;
this->advance_token();
*channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ return true;
}
- else
- {
- Expression* left = this->expression(PRECEDENCE_NORMAL, true, true, NULL);
- if (this->peek_token()->is_op(OPERATOR_EQ))
+ Expression* e = this->expression(PRECEDENCE_NORMAL, true, true, NULL);
+
+ if (this->peek_token()->is_op(OPERATOR_EQ))
+ {
+ if (!this->advance_token()->is_op(OPERATOR_CHANOP))
{
- if (!this->advance_token()->is_op(OPERATOR_CHANOP))
- {
- error_at(this->location(), "missing %<<-%>");
- return false;
- }
- *is_send = false;
- *val = left;
- this->advance_token();
- *channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ error_at(this->location(), "missing %<<-%>");
+ return false;
}
- else if (this->peek_token()->is_op(OPERATOR_CHANOP))
+ *is_send = false;
+ this->advance_token();
+ *channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ if (saw_comma)
{
- *is_send = true;
- *channel = this->verify_not_sink(left);
- this->advance_token();
- *val = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ // case v, e = <-c:
+ // *VAL is already set.
+ if (!e->is_sink_expression())
+ *closed = e;
}
else
{
- error_at(this->location(), "expected %<<-%> or %<=%>");
- return false;
+ // case v = <-c:
+ if (!e->is_sink_expression())
+ *val = e;
}
+ return true;
}
- return true;
+ if (saw_comma)
+ {
+ if (closed_is_id)
+ error_at(this->location(), "expected %<=%> or %<:=%>");
+ else
+ error_at(this->location(), "expected %<=%>");
+ return false;
+ }
+
+ if (this->peek_token()->is_op(OPERATOR_CHANOP))
+ {
+ // case c <- v:
+ *is_send = true;
+ *channel = this->verify_not_sink(e);
+ this->advance_token();
+ *val = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ return true;
+ }
+
+ error_at(this->location(), "expected %<<-%> or %<=%>");
+ return false;
}
// ForStat = "for" [ Condition | ForClause | RangeClause ] Block .
void type_switch_case(std::vector<Type*>*, bool*);
void select_stat(const Label*);
void comm_clause(Select_clauses*, bool* saw_default);
- bool comm_case(bool*, Expression**, Expression**, std::string*, bool*);
- bool send_or_recv_expr(bool*, Expression**, Expression**, std::string*);
+ bool comm_case(bool*, Expression**, Expression**, Expression**,
+ std::string*, std::string*, bool*);
+ bool send_or_recv_stmt(bool*, Expression**, Expression**, Expression**,
+ std::string*, std::string*);
void for_stat(const Label*);
void for_clause(Expression**, Block**);
void range_clause_decl(const Typed_identifier_list*, Range_clause*);
{ gcc_unreachable(); }
Statement*
- do_lower(Gogo*, Block*);
+ do_lower(Gogo*, Named_object*, Block*);
tree
do_get_tree(Translate_context*)
// statement.
Statement*
-Assignment_operation_statement::do_lower(Gogo*, Block* enclosing)
+Assignment_operation_statement::do_lower(Gogo*, Named_object*,
+ Block* enclosing)
{
source_location loc = this->location();
{ gcc_unreachable(); }
Statement*
- do_lower(Gogo*, Block*);
+ do_lower(Gogo*, Named_object*, Block*);
tree
do_get_tree(Translate_context*)
// up into a set of single assignments.
Statement*
-Tuple_assignment_statement::do_lower(Gogo*, Block* enclosing)
+Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
{
source_location loc = this->location();
{ gcc_unreachable(); }
Statement*
- do_lower(Gogo*, Block*);
+ do_lower(Gogo*, Named_object*, Block*);
tree
do_get_tree(Translate_context*)
// Lower a tuple map assignment.
Statement*
-Tuple_map_assignment_statement::do_lower(Gogo*, Block* enclosing)
+Tuple_map_assignment_statement::do_lower(Gogo*, Named_object*,
+ Block* enclosing)
{
source_location loc = this->location();
{ gcc_unreachable(); }
Statement*
- do_lower(Gogo*, Block*);
+ do_lower(Gogo*, Named_object*, Block*);
tree
do_get_tree(Translate_context*)
// Lower a map assignment to a function call.
Statement*
-Map_assignment_statement::do_lower(Gogo*, Block* enclosing)
+Map_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
{
source_location loc = this->location();
class Tuple_receive_assignment_statement : public Statement
{
public:
- Tuple_receive_assignment_statement(Expression* val, Expression* success,
+ Tuple_receive_assignment_statement(Expression* val, Expression* closed,
Expression* channel,
source_location location)
: Statement(STATEMENT_TUPLE_RECEIVE_ASSIGNMENT, location),
- val_(val), success_(success), channel_(channel)
+ val_(val), closed_(closed), channel_(channel)
{ }
protected:
{ gcc_unreachable(); }
Statement*
- do_lower(Gogo*, Block*);
+ do_lower(Gogo*, Named_object*, Block*);
tree
do_get_tree(Translate_context*)
private:
// Lvalue which receives the value from the channel.
Expression* val_;
- // Lvalue which receives whether the read succeeded or failed.
- Expression* success_;
+ // Lvalue which receives whether the channel is closed.
+ Expression* closed_;
// The channel on which we receive the value.
Expression* channel_;
};
Tuple_receive_assignment_statement::do_traverse(Traverse* traverse)
{
if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
- || this->traverse_expression(traverse, &this->success_) == TRAVERSE_EXIT)
+ || this->traverse_expression(traverse, &this->closed_) == TRAVERSE_EXIT)
return TRAVERSE_EXIT;
return this->traverse_expression(traverse, &this->channel_);
}
// Lower to a function call.
Statement*
-Tuple_receive_assignment_statement::do_lower(Gogo*, Block* enclosing)
+Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
+ Block* enclosing)
{
source_location loc = this->location();
// evaluated in the right order.
Move_ordered_evals moe(b);
this->val_->traverse_subexpressions(&moe);
- this->success_->traverse_subexpressions(&moe);
+ this->closed_->traverse_subexpressions(&moe);
// var val_temp ELEMENT_TYPE
Temporary_statement* val_temp =
Statement::make_temporary(channel_type->element_type(), NULL, loc);
b->add_statement(val_temp);
- // var success_temp bool
- Temporary_statement* success_temp =
+ // var closed_temp bool
+ Temporary_statement* closed_temp =
Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
- b->add_statement(success_temp);
+ b->add_statement(closed_temp);
// func chanrecv2(c chan T, val *T) bool
source_location bloc = BUILTINS_LOCATION;
Named_object::make_function_declaration("chanrecv2", NULL, fntype, bloc);
chanrecv2->func_declaration_value()->set_asm_name("runtime.chanrecv2");
- // success_temp = chanrecv2(channel, &val_temp)
+ // closed_temp = chanrecv2(channel, &val_temp)
Expression* func = Expression::make_func_reference(chanrecv2, NULL, loc);
Expression_list* params = new Expression_list();
params->push_back(this->channel_);
Expression* ref = Expression::make_temporary_reference(val_temp, loc);
params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
Expression* call = Expression::make_call(func, params, false, loc);
- ref = Expression::make_temporary_reference(success_temp, loc);
+ ref = Expression::make_temporary_reference(closed_temp, loc);
Statement* s = Statement::make_assignment(ref, call, loc);
b->add_statement(s);
s = Statement::make_assignment(this->val_, ref, loc);
b->add_statement(s);
- // success = success_temp
- ref = Expression::make_temporary_reference(success_temp, loc);
- s = Statement::make_assignment(this->success_, ref, loc);
+ // closed = closed_temp
+ ref = Expression::make_temporary_reference(closed_temp, loc);
+ s = Statement::make_assignment(this->closed_, ref, loc);
b->add_statement(s);
return Statement::make_block_statement(b, loc);
// Make a nonblocking receive statement.
Statement*
-Statement::make_tuple_receive_assignment(Expression* val, Expression* success,
+Statement::make_tuple_receive_assignment(Expression* val, Expression* closed,
Expression* channel,
source_location location)
{
- return new Tuple_receive_assignment_statement(val, success, channel,
+ return new Tuple_receive_assignment_statement(val, closed, channel,
location);
}
{ gcc_unreachable(); }
Statement*
- do_lower(Gogo*, Block*);
+ do_lower(Gogo*, Named_object*, Block*);
tree
do_get_tree(Translate_context*)
// Lower to a function call.
Statement*
-Tuple_type_guard_assignment_statement::do_lower(Gogo*, Block* enclosing)
+Tuple_type_guard_assignment_statement::do_lower(Gogo*, Named_object*,
+ Block* enclosing)
{
source_location loc = this->location();
{ gcc_unreachable(); }
Statement*
- do_lower(Gogo*, Block*);
+ do_lower(Gogo*, Named_object*, Block*);
tree
do_get_tree(Translate_context*)
// Lower to += or -=.
Statement*
-Inc_dec_statement::do_lower(Gogo*, Block*)
+Inc_dec_statement::do_lower(Gogo*, Named_object*, Block*)
{
source_location loc = this->location();
// panic/recover work correctly.
Statement*
-Return_statement::do_lower(Gogo*, Block* enclosing)
+Return_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
{
if (this->vals_ == NULL)
return this;
// of if statements.
Statement*
-Switch_statement::do_lower(Gogo*, Block* enclosing)
+Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
{
source_location loc = this->location();
// equality testing.
Statement*
-Type_switch_statement::do_lower(Gogo*, Block* enclosing)
+Type_switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
{
const source_location loc = this->location();
if (Expression::traverse(&this->val_, traverse) == TRAVERSE_EXIT)
return TRAVERSE_EXIT;
}
+ if (this->closed_ != NULL)
+ {
+ if (Expression::traverse(&this->closed_, traverse) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+ }
}
if (this->statements_ != NULL)
{
// receive statements to the clauses.
void
-Select_clauses::Select_clause::lower(Block* b)
+Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
+ Block* b)
{
if (this->is_default_)
{
send->set_for_select();
init->add_statement(send);
}
+ else if (this->closed_ != NULL && !this->closed_->is_sink_expression())
+ {
+ gcc_assert(this->var_ == NULL && this->closedvar_ == NULL);
+ if (this->val_ == NULL)
+ this->val_ = Expression::make_sink(loc);
+ Statement* s = Statement::make_tuple_receive_assignment(this->val_,
+ this->closed_,
+ ref, loc);
+ init->add_statement(s);
+ }
+ else if (this->closedvar_ != NULL)
+ {
+ gcc_assert(this->val_ == NULL);
+ Expression* val;
+ if (this->var_ == NULL)
+ val = Expression::make_sink(loc);
+ else
+ val = Expression::make_var_reference(this->var_, loc);
+ Expression* closed = Expression::make_var_reference(this->closedvar_,
+ loc);
+ Statement* s = Statement::make_tuple_receive_assignment(val, closed, ref,
+ loc);
+ init->add_statement(s);
+ }
else
{
Receive_expression* recv = Expression::make_receive(ref, loc);
}
else
{
- recv->discarding_value();
init->add_statement(Statement::make_statement(recv));
}
}
+ // Lower any statements we just created.
+ gogo->lower_block(function, init);
+
if (this->statements_ != NULL)
init->add_statement(Statement::make_block_statement(this->statements_,
loc));
// receive statements to the clauses.
void
-Select_clauses::lower(Block* b)
+Select_clauses::lower(Gogo* gogo, Named_object* function, Block* b)
{
for (Clauses::iterator p = this->clauses_.begin();
p != this->clauses_.end();
++p)
- p->lower(b);
+ p->lower(gogo, function, b);
}
// Determine types.
// explicit statements in the clauses.
Statement*
-Select_statement::do_lower(Gogo*, Block* enclosing)
+Select_statement::do_lower(Gogo* gogo, Named_object* function,
+ Block* enclosing)
{
if (this->is_lowered_)
return this;
Block* b = new Block(enclosing, this->location());
- this->clauses_->lower(b);
+ this->clauses_->lower(gogo, function, b);
this->is_lowered_ = true;
b->add_statement(this);
return Statement::make_block_statement(b, this->location());
// complex statements make it easier to handle garbage collection.
Statement*
-For_statement::do_lower(Gogo*, Block* enclosing)
+For_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
{
Statement* s;
source_location loc = this->location();
// statements.
Statement*
-For_range_statement::do_lower(Gogo* gogo, Block* enclosing)
+For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing)
{
Type* range_type = this->range_->type();
if (range_type->points_to() != NULL
// Make an assignment from a nonblocking receive to a pair of
// variables.
static Statement*
- make_tuple_receive_assignment(Expression* val, Expression* success,
+ make_tuple_receive_assignment(Expression* val, Expression* closed,
Expression* channel, source_location);
// Make an assignment from a type guard to a pair of variables.
// Lower a statement. This is called immediately after parsing to
// simplify statements for further processing. It returns the same
- // Statement or a new one. BLOCK is the block containing this
- // statement.
+ // Statement or a new one. FUNCTION is the function containing this
+ // statement. BLOCK is the block containing this statement.
Statement*
- lower(Gogo* gogo, Block* block)
- { return this->do_lower(gogo, block); }
+ lower(Gogo* gogo, Named_object* function, Block* block)
+ { return this->do_lower(gogo, function, block); }
// Set type information for unnamed constants.
void
// Implemented by the child class: lower this statement to a simpler
// one.
virtual Statement*
- do_lower(Gogo*, Block*)
+ do_lower(Gogo*, Named_object*, Block*)
{ return this; }
// Implemented by child class: set type information for unnamed
do_traverse_assignments(Traverse_assignments*);
Statement*
- do_lower(Gogo*, Block*);
+ do_lower(Gogo*, Named_object*, Block*);
void
do_determine_types();
// Add a new clause. IS_SEND is true if this is a send clause,
// false for a receive clause. For a send clause CHANNEL is the
// channel and VAL is the value to send. For a receive clause
- // CHANNEL is the channel and VAL is either NULL or a Var_expression
- // for the variable to set; if VAL is NULL, VAR may be a variable
- // which is initialized with the received value. IS_DEFAULT is true
- // if this is the default clause. STATEMENTS is the list of
- // statements to execute.
+ // CHANNEL is the channel, VAL is either NULL or a Var_expression
+ // for the variable to set, and CLOSED is either NULL or a
+ // Var_expression to set to whether the channel is closed. If VAL
+ // is NULL, VAR may be a variable to be initialized with the
+ // received value, and CLOSEDVAR ma be a variable to be initialized
+ // with whether the channel is closed. IS_DEFAULT is true if this
+ // is the default clause. STATEMENTS is the list of statements to
+ // execute.
void
- add(bool is_send, Expression* channel, Expression* val, Named_object* var,
- bool is_default, Block* statements, source_location location)
+ add(bool is_send, Expression* channel, Expression* val, Expression* closed,
+ Named_object* var, Named_object* closedvar, bool is_default,
+ Block* statements, source_location location)
{
- this->clauses_.push_back(Select_clause(is_send, channel, val, var,
- is_default, statements, location));
+ this->clauses_.push_back(Select_clause(is_send, channel, val, closed, var,
+ closedvar, is_default, statements,
+ location));
}
// Traverse the select clauses.
// Lower statements.
void
- lower(Block*);
+ lower(Gogo*, Named_object*, Block*);
// Determine types.
void
{
public:
Select_clause()
- : channel_(NULL), val_(NULL), var_(NULL), statements_(NULL),
- is_send_(false), is_default_(false)
+ : channel_(NULL), val_(NULL), closed_(NULL), var_(NULL),
+ closedvar_(NULL), statements_(NULL), is_send_(false),
+ is_default_(false)
{ }
Select_clause(bool is_send, Expression* channel, Expression* val,
- Named_object* var, bool is_default, Block* statements,
+ Expression* closed, Named_object* var,
+ Named_object* closedvar, bool is_default, Block* statements,
source_location location)
- : channel_(channel), val_(val), var_(var), statements_(statements),
- location_(location), is_send_(is_send), is_default_(is_default),
- is_lowered_(false)
+ : channel_(channel), val_(val), closed_(closed), var_(var),
+ closedvar_(closedvar), statements_(statements), location_(location),
+ is_send_(is_send), is_default_(is_default), is_lowered_(false)
{ gcc_assert(is_default ? channel == NULL : channel != NULL); }
// Traverse the select clause.
// Lower statements.
void
- lower(Block*);
+ lower(Gogo*, Named_object*, Block*);
// Determine types.
void
channel() const
{ return this->channel_; }
- // Return the value. This will return NULL for the default
- // clause, or for a receive clause for which no value was given.
- Expression*
- val() const
- { return this->val_; }
-
- // Return the variable to set when a receive clause is also a
- // variable definition (v := <- ch). This will return NULL for
- // the default case, or for a send clause, or for a receive clause
- // which does not define a variable.
- Named_object*
- var() const
- { return this->var_; }
-
// Return true for a send, false for a receive.
bool
is_send() const
private:
// The channel.
Expression* channel_;
- // The value to send or the variable to set.
+ // The value to send or the lvalue to receive into.
Expression* val_;
- // The variable to initialize, for "case a := <- ch".
+ // The lvalue to set to whether the channel is closed on a
+ // receive.
+ Expression* closed_;
+ // The variable to initialize, for "case a := <-ch".
Named_object* var_;
+ // The variable to initialize to whether the channel is closed,
+ // for "case a, c := <-ch".
+ Named_object* closedvar_;
// The statements to execute.
Block* statements_;
// The location of this clause.
{ return this->clauses_->traverse(traverse); }
Statement*
- do_lower(Gogo*, Block*);
+ do_lower(Gogo*, Named_object*, Block*);
void
do_determine_types()
{ gcc_unreachable(); }
Statement*
- do_lower(Gogo*, Block*);
+ do_lower(Gogo*, Named_object*, Block*);
tree
do_get_tree(Translate_context*)
{ gcc_unreachable(); }
Statement*
- do_lower(Gogo*, Block*);
+ do_lower(Gogo*, Named_object*, Block*);
tree
do_get_tree(Translate_context*)
do_traverse(Traverse*);
Statement*
- do_lower(Gogo*, Block*);
+ do_lower(Gogo*, Named_object*, Block*);
tree
do_get_tree(Translate_context*)
do_traverse(Traverse*);
Statement*
- do_lower(Gogo*, Block*);
+ do_lower(Gogo*, Named_object*, Block*);
tree
do_get_tree(Translate_context*)
/* Do a nonblocking channel receive. */
-func chanrecv2(c *chan, val *byte) (pres bool) {
+func chanrecv2(c *chan, val *byte) (received bool) {
if (c->element_size > 8) {
- return __go_receive_nonblocking_big(c, val);
+ return __go_receive_big(c, val, 0);
} else {
- struct __go_receive_nonblocking_small rs;
union {
char b[8];
uint64_t v;
} u;
- rs = __go_receive_nonblocking_small (c);
- if (!rs.__success) {
- __builtin_memset(val, 0, c->element_size);
- return 0;
- }
- u.v = rs.__val;
+ u.v = __go_receive_small_closed(c, 0, &received);
#ifndef WORDS_BIGENDIAN
__builtin_memcpy(val, u.b, c->element_size);
#else
__builtin_memcpy(val, u.b + 8 - c->element_size,
c->element_size);
#endif
- return 1;
+ return received;
}
}
extern uint64_t __go_receive_small (struct __go_channel *, _Bool);
+extern uint64_t __go_receive_small_closed (struct __go_channel *, _Bool,
+ _Bool *);
+
extern void __go_receive_release (struct __go_channel *);
struct __go_receive_nonblocking_small
extern struct __go_receive_nonblocking_small
__go_receive_nonblocking_small (struct __go_channel *);
-extern void __go_receive_big (struct __go_channel *, void *, _Bool);
+extern _Bool __go_receive_big (struct __go_channel *, void *, _Bool);
extern _Bool __go_receive_nonblocking_big (struct __go_channel *, void *);
#include "go-panic.h"
#include "channel.h"
-void
+_Bool
__go_receive_big (struct __go_channel *channel, void *val, _Bool for_select)
{
size_t alloc_size;
if (!__go_receive_acquire (channel, for_select))
{
__builtin_memset (val, 0, channel->element_size);
- return;
+ return 0;
}
offset = channel->next_fetch * alloc_size;
__builtin_memcpy (val, &channel->data[offset], channel->element_size);
__go_receive_release (channel);
+
+ return 1;
}
/* Receive something 64 bits or smaller on a channel. */
uint64_t
-__go_receive_small (struct __go_channel *channel, _Bool for_select)
+__go_receive_small_closed (struct __go_channel *channel, _Bool for_select,
+ _Bool *received)
{
uint64_t ret;
__go_assert (channel->element_size <= sizeof (uint64_t));
if (!__go_receive_acquire (channel, for_select))
- return 0;
+ {
+ if (received != NULL)
+ *received = 0;
+ return 0;
+ }
ret = channel->data[channel->next_fetch];
__go_receive_release (channel);
+ if (received != NULL)
+ *received = 1;
+
return ret;
}
+
+/* Called by the compiler. */
+
+uint64_t
+__go_receive_small (struct __go_channel *channel, _Bool for_select)
+{
+ return __go_receive_small_closed (channel, for_select, NULL);
+}