mirror of git://gcc.gnu.org/git/gcc.git
Tuple receives indicate whether channel is closed.
From-SVN: r171380
This commit is contained in:
parent
4908b0bf1c
commit
3137991dfc
|
|
@ -3057,7 +3057,7 @@ Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select,
|
||||||
location,
|
location,
|
||||||
"__go_receive_big",
|
"__go_receive_big",
|
||||||
3,
|
3,
|
||||||
void_type_node,
|
boolean_type_node,
|
||||||
ptr_type_node,
|
ptr_type_node,
|
||||||
channel,
|
channel,
|
||||||
ptr_type_node,
|
ptr_type_node,
|
||||||
|
|
|
||||||
|
|
@ -1257,7 +1257,7 @@ Lower_parse_tree::statement(Block* block, size_t* pindex, Statement* sorig)
|
||||||
Statement* s = sorig;
|
Statement* s = sorig;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
Statement* snew = s->lower(this->gogo_, block);
|
Statement* snew = s->lower(this->gogo_, this->function_, block);
|
||||||
if (snew == s)
|
if (snew == s)
|
||||||
break;
|
break;
|
||||||
s = snew;
|
s = snew;
|
||||||
|
|
@ -1305,6 +1305,15 @@ Gogo::lower_parse_tree()
|
||||||
this->traverse(&lower_parse_tree);
|
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.
|
// Lower an expression.
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -348,6 +348,10 @@ class Gogo
|
||||||
void
|
void
|
||||||
lower_parse_tree();
|
lower_parse_tree();
|
||||||
|
|
||||||
|
// Lower all the statements in a block.
|
||||||
|
void
|
||||||
|
lower_block(Named_object* function, Block*);
|
||||||
|
|
||||||
// Lower an expression.
|
// Lower an expression.
|
||||||
void
|
void
|
||||||
lower_expression(Named_object* function, Expression**);
|
lower_expression(Named_object* function, Expression**);
|
||||||
|
|
|
||||||
|
|
@ -4179,10 +4179,12 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default)
|
||||||
bool is_send = false;
|
bool is_send = false;
|
||||||
Expression* channel = NULL;
|
Expression* channel = NULL;
|
||||||
Expression* val = NULL;
|
Expression* val = NULL;
|
||||||
|
Expression* closed = NULL;
|
||||||
std::string varname;
|
std::string varname;
|
||||||
|
std::string closedname;
|
||||||
bool is_default = false;
|
bool is_default = false;
|
||||||
bool got_case = this->comm_case(&is_send, &channel, &val, &varname,
|
bool got_case = this->comm_case(&is_send, &channel, &val, &closed,
|
||||||
&is_default);
|
&varname, &closedname, &is_default);
|
||||||
|
|
||||||
if (this->peek_token()->is_op(OPERATOR_COLON))
|
if (this->peek_token()->is_op(OPERATOR_COLON))
|
||||||
this->advance_token();
|
this->advance_token();
|
||||||
|
|
@ -4191,6 +4193,7 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default)
|
||||||
|
|
||||||
Block* statements = NULL;
|
Block* statements = NULL;
|
||||||
Named_object* var = NULL;
|
Named_object* var = NULL;
|
||||||
|
Named_object* closedvar = NULL;
|
||||||
if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
|
if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
|
||||||
this->advance_token();
|
this->advance_token();
|
||||||
else if (this->statement_list_may_start_here())
|
else if (this->statement_list_may_start_here())
|
||||||
|
|
@ -4206,6 +4209,14 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default)
|
||||||
var = this->gogo_->add_variable(varname, v);
|
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();
|
this->statement_list();
|
||||||
statements = this->gogo_->finish_block(this->location());
|
statements = this->gogo_->finish_block(this->location());
|
||||||
}
|
}
|
||||||
|
|
@ -4221,7 +4232,8 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (got_case)
|
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)
|
else if (statements != NULL)
|
||||||
{
|
{
|
||||||
// Add the statements to make sure that any names they define
|
// Add the statements to make sure that any names they define
|
||||||
|
|
@ -4234,7 +4246,8 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default)
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Parse::comm_case(bool* is_send, Expression** channel, Expression** val,
|
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();
|
const Token* token = this->peek_token();
|
||||||
if (token->is_keyword(KEYWORD_DEFAULT))
|
if (token->is_keyword(KEYWORD_DEFAULT))
|
||||||
|
|
@ -4245,7 +4258,8 @@ Parse::comm_case(bool* is_send, Expression** channel, Expression** val,
|
||||||
else if (token->is_keyword(KEYWORD_CASE))
|
else if (token->is_keyword(KEYWORD_CASE))
|
||||||
{
|
{
|
||||||
this->advance_token();
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -4259,74 +4273,160 @@ Parse::comm_case(bool* is_send, Expression** channel, Expression** val,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// RecvExpr = [ Expression ( "=" | ":=" ) ] "<-" Expression .
|
// RecvStmt = [ Expression [ "," Expression ] ( "=" | ":=" ) ] RecvExpr .
|
||||||
|
// RecvExpr = Expression .
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Parse::send_or_recv_expr(bool* is_send, Expression** channel, Expression** val,
|
Parse::send_or_recv_stmt(bool* is_send, Expression** channel, Expression** val,
|
||||||
std::string* varname)
|
Expression** closed, std::string* varname,
|
||||||
|
std::string* closedname)
|
||||||
{
|
{
|
||||||
const Token* token = this->peek_token();
|
const Token* token = this->peek_token();
|
||||||
source_location location = token->location();
|
bool saw_comma = false;
|
||||||
|
bool closed_is_id = false;
|
||||||
if (token->is_identifier())
|
if (token->is_identifier())
|
||||||
{
|
{
|
||||||
|
Gogo* gogo = this->gogo_;
|
||||||
std::string recv_var = token->identifier();
|
std::string recv_var = token->identifier();
|
||||||
bool is_var_exported = token->is_identifier_exported();
|
bool is_rv_exported = token->is_identifier_exported();
|
||||||
if (!this->advance_token()->is_op(OPERATOR_COLONEQ))
|
source_location recv_var_loc = token->location();
|
||||||
this->unget_token(Token::make_identifier_token(recv_var,
|
token = this->advance_token();
|
||||||
is_var_exported,
|
if (token->is_op(OPERATOR_COLONEQ))
|
||||||
location));
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
// case rv := <-c:
|
||||||
if (!this->advance_token()->is_op(OPERATOR_CHANOP))
|
if (!this->advance_token()->is_op(OPERATOR_CHANOP))
|
||||||
{
|
{
|
||||||
error_at(this->location(), "expected %<<-%>");
|
error_at(this->location(), "expected %<<-%>");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (recv_var == "_")
|
||||||
|
{
|
||||||
|
error_at(recv_var_loc,
|
||||||
|
"no new variables on left side of %<:=%>");
|
||||||
|
recv_var = "blank";
|
||||||
|
}
|
||||||
*is_send = false;
|
*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();
|
this->advance_token();
|
||||||
*channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
|
*channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
|
||||||
return true;
|
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 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
error_at(this->location(), "missing %<<-%>");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*is_send = false;
|
||||||
|
this->advance_token();
|
||||||
|
*channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
|
||||||
|
if (saw_comma)
|
||||||
|
{
|
||||||
|
// case v, e = <-c:
|
||||||
|
// *VAL is already set.
|
||||||
|
if (!e->is_sink_expression())
|
||||||
|
*closed = e;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// case v = <-c:
|
||||||
|
if (!e->is_sink_expression())
|
||||||
|
*val = e;
|
||||||
|
}
|
||||||
|
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))
|
if (this->peek_token()->is_op(OPERATOR_CHANOP))
|
||||||
{
|
{
|
||||||
*is_send = false;
|
// case c <- v:
|
||||||
|
*is_send = true;
|
||||||
|
*channel = this->verify_not_sink(e);
|
||||||
this->advance_token();
|
this->advance_token();
|
||||||
*channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
|
*val = 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))
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
else if (this->peek_token()->is_op(OPERATOR_CHANOP))
|
|
||||||
{
|
|
||||||
*is_send = true;
|
|
||||||
*channel = this->verify_not_sink(left);
|
|
||||||
this->advance_token();
|
|
||||||
*val = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
error_at(this->location(), "expected %<<-%> or %<=%>");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
error_at(this->location(), "expected %<<-%> or %<=%>");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForStat = "for" [ Condition | ForClause | RangeClause ] Block .
|
// ForStat = "for" [ Condition | ForClause | RangeClause ] Block .
|
||||||
|
|
|
||||||
|
|
@ -246,8 +246,10 @@ class Parse
|
||||||
void type_switch_case(std::vector<Type*>*, bool*);
|
void type_switch_case(std::vector<Type*>*, bool*);
|
||||||
void select_stat(const Label*);
|
void select_stat(const Label*);
|
||||||
void comm_clause(Select_clauses*, bool* saw_default);
|
void comm_clause(Select_clauses*, bool* saw_default);
|
||||||
bool comm_case(bool*, Expression**, Expression**, std::string*, bool*);
|
bool comm_case(bool*, Expression**, Expression**, Expression**,
|
||||||
bool send_or_recv_expr(bool*, Expression**, Expression**, std::string*);
|
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_stat(const Label*);
|
||||||
void for_clause(Expression**, Block**);
|
void for_clause(Expression**, Block**);
|
||||||
void range_clause_decl(const Typed_identifier_list*, Range_clause*);
|
void range_clause_decl(const Typed_identifier_list*, Range_clause*);
|
||||||
|
|
|
||||||
|
|
@ -638,7 +638,7 @@ class Assignment_operation_statement : public Statement
|
||||||
{ gcc_unreachable(); }
|
{ gcc_unreachable(); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Block*);
|
do_lower(Gogo*, Named_object*, Block*);
|
||||||
|
|
||||||
tree
|
tree
|
||||||
do_get_tree(Translate_context*)
|
do_get_tree(Translate_context*)
|
||||||
|
|
@ -667,7 +667,8 @@ Assignment_operation_statement::do_traverse(Traverse* traverse)
|
||||||
// statement.
|
// statement.
|
||||||
|
|
||||||
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();
|
source_location loc = this->location();
|
||||||
|
|
||||||
|
|
@ -764,7 +765,7 @@ class Tuple_assignment_statement : public Statement
|
||||||
{ gcc_unreachable(); }
|
{ gcc_unreachable(); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Block*);
|
do_lower(Gogo*, Named_object*, Block*);
|
||||||
|
|
||||||
tree
|
tree
|
||||||
do_get_tree(Translate_context*)
|
do_get_tree(Translate_context*)
|
||||||
|
|
@ -791,7 +792,7 @@ Tuple_assignment_statement::do_traverse(Traverse* traverse)
|
||||||
// up into a set of single assignments.
|
// up into a set of single assignments.
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Tuple_assignment_statement::do_lower(Gogo*, Block* enclosing)
|
Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
|
||||||
{
|
{
|
||||||
source_location loc = this->location();
|
source_location loc = this->location();
|
||||||
|
|
||||||
|
|
@ -891,7 +892,7 @@ public:
|
||||||
{ gcc_unreachable(); }
|
{ gcc_unreachable(); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Block*);
|
do_lower(Gogo*, Named_object*, Block*);
|
||||||
|
|
||||||
tree
|
tree
|
||||||
do_get_tree(Translate_context*)
|
do_get_tree(Translate_context*)
|
||||||
|
|
@ -920,7 +921,8 @@ Tuple_map_assignment_statement::do_traverse(Traverse* traverse)
|
||||||
// Lower a tuple map assignment.
|
// Lower a tuple map assignment.
|
||||||
|
|
||||||
Statement*
|
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();
|
source_location loc = this->location();
|
||||||
|
|
||||||
|
|
@ -1037,7 +1039,7 @@ class Map_assignment_statement : public Statement
|
||||||
{ gcc_unreachable(); }
|
{ gcc_unreachable(); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Block*);
|
do_lower(Gogo*, Named_object*, Block*);
|
||||||
|
|
||||||
tree
|
tree
|
||||||
do_get_tree(Translate_context*)
|
do_get_tree(Translate_context*)
|
||||||
|
|
@ -1066,7 +1068,7 @@ Map_assignment_statement::do_traverse(Traverse* traverse)
|
||||||
// Lower a map assignment to a function call.
|
// Lower a map assignment to a function call.
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Map_assignment_statement::do_lower(Gogo*, Block* enclosing)
|
Map_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
|
||||||
{
|
{
|
||||||
source_location loc = this->location();
|
source_location loc = this->location();
|
||||||
|
|
||||||
|
|
@ -1145,11 +1147,11 @@ Statement::make_map_assignment(Expression* map_index,
|
||||||
class Tuple_receive_assignment_statement : public Statement
|
class Tuple_receive_assignment_statement : public Statement
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Tuple_receive_assignment_statement(Expression* val, Expression* success,
|
Tuple_receive_assignment_statement(Expression* val, Expression* closed,
|
||||||
Expression* channel,
|
Expression* channel,
|
||||||
source_location location)
|
source_location location)
|
||||||
: Statement(STATEMENT_TUPLE_RECEIVE_ASSIGNMENT, location),
|
: Statement(STATEMENT_TUPLE_RECEIVE_ASSIGNMENT, location),
|
||||||
val_(val), success_(success), channel_(channel)
|
val_(val), closed_(closed), channel_(channel)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -1161,7 +1163,7 @@ class Tuple_receive_assignment_statement : public Statement
|
||||||
{ gcc_unreachable(); }
|
{ gcc_unreachable(); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Block*);
|
do_lower(Gogo*, Named_object*, Block*);
|
||||||
|
|
||||||
tree
|
tree
|
||||||
do_get_tree(Translate_context*)
|
do_get_tree(Translate_context*)
|
||||||
|
|
@ -1170,8 +1172,8 @@ class Tuple_receive_assignment_statement : public Statement
|
||||||
private:
|
private:
|
||||||
// Lvalue which receives the value from the channel.
|
// Lvalue which receives the value from the channel.
|
||||||
Expression* val_;
|
Expression* val_;
|
||||||
// Lvalue which receives whether the read succeeded or failed.
|
// Lvalue which receives whether the channel is closed.
|
||||||
Expression* success_;
|
Expression* closed_;
|
||||||
// The channel on which we receive the value.
|
// The channel on which we receive the value.
|
||||||
Expression* channel_;
|
Expression* channel_;
|
||||||
};
|
};
|
||||||
|
|
@ -1182,7 +1184,7 @@ int
|
||||||
Tuple_receive_assignment_statement::do_traverse(Traverse* traverse)
|
Tuple_receive_assignment_statement::do_traverse(Traverse* traverse)
|
||||||
{
|
{
|
||||||
if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
|
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 TRAVERSE_EXIT;
|
||||||
return this->traverse_expression(traverse, &this->channel_);
|
return this->traverse_expression(traverse, &this->channel_);
|
||||||
}
|
}
|
||||||
|
|
@ -1190,7 +1192,8 @@ Tuple_receive_assignment_statement::do_traverse(Traverse* traverse)
|
||||||
// Lower to a function call.
|
// Lower to a function call.
|
||||||
|
|
||||||
Statement*
|
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();
|
source_location loc = this->location();
|
||||||
|
|
||||||
|
|
@ -1212,17 +1215,17 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Block* enclosing)
|
||||||
// evaluated in the right order.
|
// evaluated in the right order.
|
||||||
Move_ordered_evals moe(b);
|
Move_ordered_evals moe(b);
|
||||||
this->val_->traverse_subexpressions(&moe);
|
this->val_->traverse_subexpressions(&moe);
|
||||||
this->success_->traverse_subexpressions(&moe);
|
this->closed_->traverse_subexpressions(&moe);
|
||||||
|
|
||||||
// var val_temp ELEMENT_TYPE
|
// var val_temp ELEMENT_TYPE
|
||||||
Temporary_statement* val_temp =
|
Temporary_statement* val_temp =
|
||||||
Statement::make_temporary(channel_type->element_type(), NULL, loc);
|
Statement::make_temporary(channel_type->element_type(), NULL, loc);
|
||||||
b->add_statement(val_temp);
|
b->add_statement(val_temp);
|
||||||
|
|
||||||
// var success_temp bool
|
// var closed_temp bool
|
||||||
Temporary_statement* success_temp =
|
Temporary_statement* closed_temp =
|
||||||
Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
|
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
|
// func chanrecv2(c chan T, val *T) bool
|
||||||
source_location bloc = BUILTINS_LOCATION;
|
source_location bloc = BUILTINS_LOCATION;
|
||||||
|
|
@ -1240,14 +1243,14 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Block* enclosing)
|
||||||
Named_object::make_function_declaration("chanrecv2", NULL, fntype, bloc);
|
Named_object::make_function_declaration("chanrecv2", NULL, fntype, bloc);
|
||||||
chanrecv2->func_declaration_value()->set_asm_name("runtime.chanrecv2");
|
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* func = Expression::make_func_reference(chanrecv2, NULL, loc);
|
||||||
Expression_list* params = new Expression_list();
|
Expression_list* params = new Expression_list();
|
||||||
params->push_back(this->channel_);
|
params->push_back(this->channel_);
|
||||||
Expression* ref = Expression::make_temporary_reference(val_temp, loc);
|
Expression* ref = Expression::make_temporary_reference(val_temp, loc);
|
||||||
params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
|
params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
|
||||||
Expression* call = Expression::make_call(func, params, false, 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);
|
Statement* s = Statement::make_assignment(ref, call, loc);
|
||||||
b->add_statement(s);
|
b->add_statement(s);
|
||||||
|
|
||||||
|
|
@ -1256,9 +1259,9 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Block* enclosing)
|
||||||
s = Statement::make_assignment(this->val_, ref, loc);
|
s = Statement::make_assignment(this->val_, ref, loc);
|
||||||
b->add_statement(s);
|
b->add_statement(s);
|
||||||
|
|
||||||
// success = success_temp
|
// closed = closed_temp
|
||||||
ref = Expression::make_temporary_reference(success_temp, loc);
|
ref = Expression::make_temporary_reference(closed_temp, loc);
|
||||||
s = Statement::make_assignment(this->success_, ref, loc);
|
s = Statement::make_assignment(this->closed_, ref, loc);
|
||||||
b->add_statement(s);
|
b->add_statement(s);
|
||||||
|
|
||||||
return Statement::make_block_statement(b, loc);
|
return Statement::make_block_statement(b, loc);
|
||||||
|
|
@ -1267,11 +1270,11 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Block* enclosing)
|
||||||
// Make a nonblocking receive statement.
|
// Make a nonblocking receive statement.
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Statement::make_tuple_receive_assignment(Expression* val, Expression* success,
|
Statement::make_tuple_receive_assignment(Expression* val, Expression* closed,
|
||||||
Expression* channel,
|
Expression* channel,
|
||||||
source_location location)
|
source_location location)
|
||||||
{
|
{
|
||||||
return new Tuple_receive_assignment_statement(val, success, channel,
|
return new Tuple_receive_assignment_statement(val, closed, channel,
|
||||||
location);
|
location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1297,7 +1300,7 @@ class Tuple_type_guard_assignment_statement : public Statement
|
||||||
{ gcc_unreachable(); }
|
{ gcc_unreachable(); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Block*);
|
do_lower(Gogo*, Named_object*, Block*);
|
||||||
|
|
||||||
tree
|
tree
|
||||||
do_get_tree(Translate_context*)
|
do_get_tree(Translate_context*)
|
||||||
|
|
@ -1338,7 +1341,8 @@ Tuple_type_guard_assignment_statement::do_traverse(Traverse* traverse)
|
||||||
// Lower to a function call.
|
// Lower to a function call.
|
||||||
|
|
||||||
Statement*
|
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();
|
source_location loc = this->location();
|
||||||
|
|
||||||
|
|
@ -1643,7 +1647,7 @@ class Inc_dec_statement : public Statement
|
||||||
{ gcc_unreachable(); }
|
{ gcc_unreachable(); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Block*);
|
do_lower(Gogo*, Named_object*, Block*);
|
||||||
|
|
||||||
tree
|
tree
|
||||||
do_get_tree(Translate_context*)
|
do_get_tree(Translate_context*)
|
||||||
|
|
@ -1659,7 +1663,7 @@ class Inc_dec_statement : public Statement
|
||||||
// Lower to += or -=.
|
// Lower to += or -=.
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Inc_dec_statement::do_lower(Gogo*, Block*)
|
Inc_dec_statement::do_lower(Gogo*, Named_object*, Block*)
|
||||||
{
|
{
|
||||||
source_location loc = this->location();
|
source_location loc = this->location();
|
||||||
|
|
||||||
|
|
@ -2429,7 +2433,7 @@ Return_statement::do_traverse_assignments(Traverse_assignments* tassign)
|
||||||
// panic/recover work correctly.
|
// panic/recover work correctly.
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Return_statement::do_lower(Gogo*, Block* enclosing)
|
Return_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
|
||||||
{
|
{
|
||||||
if (this->vals_ == NULL)
|
if (this->vals_ == NULL)
|
||||||
return this;
|
return this;
|
||||||
|
|
@ -3530,7 +3534,7 @@ Switch_statement::do_traverse(Traverse* traverse)
|
||||||
// of if statements.
|
// of if statements.
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Switch_statement::do_lower(Gogo*, Block* enclosing)
|
Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
|
||||||
{
|
{
|
||||||
source_location loc = this->location();
|
source_location loc = this->location();
|
||||||
|
|
||||||
|
|
@ -3871,7 +3875,7 @@ Type_switch_statement::do_traverse(Traverse* traverse)
|
||||||
// equality testing.
|
// equality testing.
|
||||||
|
|
||||||
Statement*
|
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();
|
const source_location loc = this->location();
|
||||||
|
|
||||||
|
|
@ -4079,6 +4083,11 @@ Select_clauses::Select_clause::traverse(Traverse* traverse)
|
||||||
if (Expression::traverse(&this->val_, traverse) == TRAVERSE_EXIT)
|
if (Expression::traverse(&this->val_, traverse) == TRAVERSE_EXIT)
|
||||||
return TRAVERSE_EXIT;
|
return TRAVERSE_EXIT;
|
||||||
}
|
}
|
||||||
|
if (this->closed_ != NULL)
|
||||||
|
{
|
||||||
|
if (Expression::traverse(&this->closed_, traverse) == TRAVERSE_EXIT)
|
||||||
|
return TRAVERSE_EXIT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (this->statements_ != NULL)
|
if (this->statements_ != NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -4093,7 +4102,8 @@ Select_clauses::Select_clause::traverse(Traverse* traverse)
|
||||||
// receive statements to the clauses.
|
// receive statements to the clauses.
|
||||||
|
|
||||||
void
|
void
|
||||||
Select_clauses::Select_clause::lower(Block* b)
|
Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
|
||||||
|
Block* b)
|
||||||
{
|
{
|
||||||
if (this->is_default_)
|
if (this->is_default_)
|
||||||
{
|
{
|
||||||
|
|
@ -4134,6 +4144,30 @@ Select_clauses::Select_clause::lower(Block* b)
|
||||||
send->set_for_select();
|
send->set_for_select();
|
||||||
init->add_statement(send);
|
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
|
else
|
||||||
{
|
{
|
||||||
Receive_expression* recv = Expression::make_receive(ref, loc);
|
Receive_expression* recv = Expression::make_receive(ref, loc);
|
||||||
|
|
@ -4151,11 +4185,13 @@ Select_clauses::Select_clause::lower(Block* b)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
recv->discarding_value();
|
|
||||||
init->add_statement(Statement::make_statement(recv));
|
init->add_statement(Statement::make_statement(recv));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lower any statements we just created.
|
||||||
|
gogo->lower_block(function, init);
|
||||||
|
|
||||||
if (this->statements_ != NULL)
|
if (this->statements_ != NULL)
|
||||||
init->add_statement(Statement::make_block_statement(this->statements_,
|
init->add_statement(Statement::make_block_statement(this->statements_,
|
||||||
loc));
|
loc));
|
||||||
|
|
@ -4222,12 +4258,12 @@ Select_clauses::traverse(Traverse* traverse)
|
||||||
// receive statements to the clauses.
|
// receive statements to the clauses.
|
||||||
|
|
||||||
void
|
void
|
||||||
Select_clauses::lower(Block* b)
|
Select_clauses::lower(Gogo* gogo, Named_object* function, Block* b)
|
||||||
{
|
{
|
||||||
for (Clauses::iterator p = this->clauses_.begin();
|
for (Clauses::iterator p = this->clauses_.begin();
|
||||||
p != this->clauses_.end();
|
p != this->clauses_.end();
|
||||||
++p)
|
++p)
|
||||||
p->lower(b);
|
p->lower(gogo, function, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine types.
|
// Determine types.
|
||||||
|
|
@ -4464,12 +4500,13 @@ Select_statement::break_label()
|
||||||
// explicit statements in the clauses.
|
// explicit statements in the clauses.
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Select_statement::do_lower(Gogo*, Block* enclosing)
|
Select_statement::do_lower(Gogo* gogo, Named_object* function,
|
||||||
|
Block* enclosing)
|
||||||
{
|
{
|
||||||
if (this->is_lowered_)
|
if (this->is_lowered_)
|
||||||
return this;
|
return this;
|
||||||
Block* b = new Block(enclosing, this->location());
|
Block* b = new Block(enclosing, this->location());
|
||||||
this->clauses_->lower(b);
|
this->clauses_->lower(gogo, function, b);
|
||||||
this->is_lowered_ = true;
|
this->is_lowered_ = true;
|
||||||
b->add_statement(this);
|
b->add_statement(this);
|
||||||
return Statement::make_block_statement(b, this->location());
|
return Statement::make_block_statement(b, this->location());
|
||||||
|
|
@ -4521,7 +4558,7 @@ For_statement::do_traverse(Traverse* traverse)
|
||||||
// complex statements make it easier to handle garbage collection.
|
// complex statements make it easier to handle garbage collection.
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
For_statement::do_lower(Gogo*, Block* enclosing)
|
For_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
|
||||||
{
|
{
|
||||||
Statement* s;
|
Statement* s;
|
||||||
source_location loc = this->location();
|
source_location loc = this->location();
|
||||||
|
|
@ -4652,7 +4689,7 @@ For_range_statement::do_traverse(Traverse* traverse)
|
||||||
// statements.
|
// statements.
|
||||||
|
|
||||||
Statement*
|
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();
|
Type* range_type = this->range_->type();
|
||||||
if (range_type->points_to() != NULL
|
if (range_type->points_to() != NULL
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ class Statement
|
||||||
// Make an assignment from a nonblocking receive to a pair of
|
// Make an assignment from a nonblocking receive to a pair of
|
||||||
// variables.
|
// variables.
|
||||||
static Statement*
|
static Statement*
|
||||||
make_tuple_receive_assignment(Expression* val, Expression* success,
|
make_tuple_receive_assignment(Expression* val, Expression* closed,
|
||||||
Expression* channel, source_location);
|
Expression* channel, source_location);
|
||||||
|
|
||||||
// Make an assignment from a type guard to a pair of variables.
|
// Make an assignment from a type guard to a pair of variables.
|
||||||
|
|
@ -284,11 +284,11 @@ class Statement
|
||||||
|
|
||||||
// Lower a statement. This is called immediately after parsing to
|
// Lower a statement. This is called immediately after parsing to
|
||||||
// simplify statements for further processing. It returns the same
|
// simplify statements for further processing. It returns the same
|
||||||
// Statement or a new one. BLOCK is the block containing this
|
// Statement or a new one. FUNCTION is the function containing this
|
||||||
// statement.
|
// statement. BLOCK is the block containing this statement.
|
||||||
Statement*
|
Statement*
|
||||||
lower(Gogo* gogo, Block* block)
|
lower(Gogo* gogo, Named_object* function, Block* block)
|
||||||
{ return this->do_lower(gogo, block); }
|
{ return this->do_lower(gogo, function, block); }
|
||||||
|
|
||||||
// Set type information for unnamed constants.
|
// Set type information for unnamed constants.
|
||||||
void
|
void
|
||||||
|
|
@ -381,7 +381,7 @@ class Statement
|
||||||
// Implemented by the child class: lower this statement to a simpler
|
// Implemented by the child class: lower this statement to a simpler
|
||||||
// one.
|
// one.
|
||||||
virtual Statement*
|
virtual Statement*
|
||||||
do_lower(Gogo*, Block*)
|
do_lower(Gogo*, Named_object*, Block*)
|
||||||
{ return this; }
|
{ return this; }
|
||||||
|
|
||||||
// Implemented by child class: set type information for unnamed
|
// Implemented by child class: set type information for unnamed
|
||||||
|
|
@ -574,7 +574,7 @@ class Return_statement : public Statement
|
||||||
do_traverse_assignments(Traverse_assignments*);
|
do_traverse_assignments(Traverse_assignments*);
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Block*);
|
do_lower(Gogo*, Named_object*, Block*);
|
||||||
|
|
||||||
void
|
void
|
||||||
do_determine_types();
|
do_determine_types();
|
||||||
|
|
@ -649,17 +649,22 @@ class Select_clauses
|
||||||
// Add a new clause. IS_SEND is true if this is a send clause,
|
// 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
|
// 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 and VAL is the value to send. For a receive clause
|
||||||
// CHANNEL is the channel and VAL is either NULL or a Var_expression
|
// CHANNEL is the channel, VAL is either NULL or a Var_expression
|
||||||
// for the variable to set; if VAL is NULL, VAR may be a variable
|
// for the variable to set, and CLOSED is either NULL or a
|
||||||
// which is initialized with the received value. IS_DEFAULT is true
|
// Var_expression to set to whether the channel is closed. If VAL
|
||||||
// if this is the default clause. STATEMENTS is the list of
|
// is NULL, VAR may be a variable to be initialized with the
|
||||||
// statements to execute.
|
// 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
|
void
|
||||||
add(bool is_send, Expression* channel, Expression* val, Named_object* var,
|
add(bool is_send, Expression* channel, Expression* val, Expression* closed,
|
||||||
bool is_default, Block* statements, source_location location)
|
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,
|
this->clauses_.push_back(Select_clause(is_send, channel, val, closed, var,
|
||||||
is_default, statements, location));
|
closedvar, is_default, statements,
|
||||||
|
location));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Traverse the select clauses.
|
// Traverse the select clauses.
|
||||||
|
|
@ -668,7 +673,7 @@ class Select_clauses
|
||||||
|
|
||||||
// Lower statements.
|
// Lower statements.
|
||||||
void
|
void
|
||||||
lower(Block*);
|
lower(Gogo*, Named_object*, Block*);
|
||||||
|
|
||||||
// Determine types.
|
// Determine types.
|
||||||
void
|
void
|
||||||
|
|
@ -689,16 +694,18 @@ class Select_clauses
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Select_clause()
|
Select_clause()
|
||||||
: channel_(NULL), val_(NULL), var_(NULL), statements_(NULL),
|
: channel_(NULL), val_(NULL), closed_(NULL), var_(NULL),
|
||||||
is_send_(false), is_default_(false)
|
closedvar_(NULL), statements_(NULL), is_send_(false),
|
||||||
|
is_default_(false)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
Select_clause(bool is_send, Expression* channel, Expression* val,
|
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)
|
source_location location)
|
||||||
: channel_(channel), val_(val), var_(var), statements_(statements),
|
: channel_(channel), val_(val), closed_(closed), var_(var),
|
||||||
location_(location), is_send_(is_send), is_default_(is_default),
|
closedvar_(closedvar), statements_(statements), location_(location),
|
||||||
is_lowered_(false)
|
is_send_(is_send), is_default_(is_default), is_lowered_(false)
|
||||||
{ gcc_assert(is_default ? channel == NULL : channel != NULL); }
|
{ gcc_assert(is_default ? channel == NULL : channel != NULL); }
|
||||||
|
|
||||||
// Traverse the select clause.
|
// Traverse the select clause.
|
||||||
|
|
@ -707,7 +714,7 @@ class Select_clauses
|
||||||
|
|
||||||
// Lower statements.
|
// Lower statements.
|
||||||
void
|
void
|
||||||
lower(Block*);
|
lower(Gogo*, Named_object*, Block*);
|
||||||
|
|
||||||
// Determine types.
|
// Determine types.
|
||||||
void
|
void
|
||||||
|
|
@ -724,20 +731,6 @@ class Select_clauses
|
||||||
channel() const
|
channel() const
|
||||||
{ return this->channel_; }
|
{ 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.
|
// Return true for a send, false for a receive.
|
||||||
bool
|
bool
|
||||||
is_send() const
|
is_send() const
|
||||||
|
|
@ -768,10 +761,16 @@ class Select_clauses
|
||||||
private:
|
private:
|
||||||
// The channel.
|
// The channel.
|
||||||
Expression* channel_;
|
Expression* channel_;
|
||||||
// The value to send or the variable to set.
|
// The value to send or the lvalue to receive into.
|
||||||
Expression* val_;
|
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_;
|
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.
|
// The statements to execute.
|
||||||
Block* statements_;
|
Block* statements_;
|
||||||
// The location of this clause.
|
// The location of this clause.
|
||||||
|
|
@ -821,7 +820,7 @@ class Select_statement : public Statement
|
||||||
{ return this->clauses_->traverse(traverse); }
|
{ return this->clauses_->traverse(traverse); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Block*);
|
do_lower(Gogo*, Named_object*, Block*);
|
||||||
|
|
||||||
void
|
void
|
||||||
do_determine_types()
|
do_determine_types()
|
||||||
|
|
@ -1008,7 +1007,7 @@ class For_statement : public Statement
|
||||||
{ gcc_unreachable(); }
|
{ gcc_unreachable(); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Block*);
|
do_lower(Gogo*, Named_object*, Block*);
|
||||||
|
|
||||||
tree
|
tree
|
||||||
do_get_tree(Translate_context*)
|
do_get_tree(Translate_context*)
|
||||||
|
|
@ -1066,7 +1065,7 @@ class For_range_statement : public Statement
|
||||||
{ gcc_unreachable(); }
|
{ gcc_unreachable(); }
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Block*);
|
do_lower(Gogo*, Named_object*, Block*);
|
||||||
|
|
||||||
tree
|
tree
|
||||||
do_get_tree(Translate_context*)
|
do_get_tree(Translate_context*)
|
||||||
|
|
@ -1290,7 +1289,7 @@ class Switch_statement : public Statement
|
||||||
do_traverse(Traverse*);
|
do_traverse(Traverse*);
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Block*);
|
do_lower(Gogo*, Named_object*, Block*);
|
||||||
|
|
||||||
tree
|
tree
|
||||||
do_get_tree(Translate_context*)
|
do_get_tree(Translate_context*)
|
||||||
|
|
@ -1436,7 +1435,7 @@ class Type_switch_statement : public Statement
|
||||||
do_traverse(Traverse*);
|
do_traverse(Traverse*);
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
do_lower(Gogo*, Block*);
|
do_lower(Gogo*, Named_object*, Block*);
|
||||||
|
|
||||||
tree
|
tree
|
||||||
do_get_tree(Translate_context*)
|
do_get_tree(Translate_context*)
|
||||||
|
|
|
||||||
|
|
@ -12,28 +12,22 @@ typedef struct __go_channel chan;
|
||||||
|
|
||||||
/* Do a nonblocking channel receive. */
|
/* 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) {
|
if (c->element_size > 8) {
|
||||||
return __go_receive_nonblocking_big(c, val);
|
return __go_receive_big(c, val, 0);
|
||||||
} else {
|
} else {
|
||||||
struct __go_receive_nonblocking_small rs;
|
|
||||||
union {
|
union {
|
||||||
char b[8];
|
char b[8];
|
||||||
uint64_t v;
|
uint64_t v;
|
||||||
} u;
|
} u;
|
||||||
|
|
||||||
rs = __go_receive_nonblocking_small (c);
|
u.v = __go_receive_small_closed(c, 0, &received);
|
||||||
if (!rs.__success) {
|
|
||||||
__builtin_memset(val, 0, c->element_size);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
u.v = rs.__val;
|
|
||||||
#ifndef WORDS_BIGENDIAN
|
#ifndef WORDS_BIGENDIAN
|
||||||
__builtin_memcpy(val, u.b, c->element_size);
|
__builtin_memcpy(val, u.b, c->element_size);
|
||||||
#else
|
#else
|
||||||
__builtin_memcpy(val, u.b + 8 - c->element_size,
|
__builtin_memcpy(val, u.b + 8 - c->element_size,
|
||||||
c->element_size);
|
c->element_size);
|
||||||
#endif
|
#endif
|
||||||
return 1;
|
return received;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,9 @@ extern int __go_receive_nonblocking_acquire (struct __go_channel *);
|
||||||
|
|
||||||
extern uint64_t __go_receive_small (struct __go_channel *, _Bool);
|
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 *);
|
extern void __go_receive_release (struct __go_channel *);
|
||||||
|
|
||||||
struct __go_receive_nonblocking_small
|
struct __go_receive_nonblocking_small
|
||||||
|
|
@ -123,7 +126,7 @@ struct __go_receive_nonblocking_small
|
||||||
extern struct __go_receive_nonblocking_small
|
extern struct __go_receive_nonblocking_small
|
||||||
__go_receive_nonblocking_small (struct __go_channel *);
|
__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 *);
|
extern _Bool __go_receive_nonblocking_big (struct __go_channel *, void *);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
#include "go-panic.h"
|
#include "go-panic.h"
|
||||||
#include "channel.h"
|
#include "channel.h"
|
||||||
|
|
||||||
void
|
_Bool
|
||||||
__go_receive_big (struct __go_channel *channel, void *val, _Bool for_select)
|
__go_receive_big (struct __go_channel *channel, void *val, _Bool for_select)
|
||||||
{
|
{
|
||||||
size_t alloc_size;
|
size_t alloc_size;
|
||||||
|
|
@ -24,11 +24,13 @@ __go_receive_big (struct __go_channel *channel, void *val, _Bool for_select)
|
||||||
if (!__go_receive_acquire (channel, for_select))
|
if (!__go_receive_acquire (channel, for_select))
|
||||||
{
|
{
|
||||||
__builtin_memset (val, 0, channel->element_size);
|
__builtin_memset (val, 0, channel->element_size);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = channel->next_fetch * alloc_size;
|
offset = channel->next_fetch * alloc_size;
|
||||||
__builtin_memcpy (val, &channel->data[offset], channel->element_size);
|
__builtin_memcpy (val, &channel->data[offset], channel->element_size);
|
||||||
|
|
||||||
__go_receive_release (channel);
|
__go_receive_release (channel);
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -263,7 +263,8 @@ __go_unlock_and_notify_selects (struct __go_channel *channel)
|
||||||
/* Receive something 64 bits or smaller on a channel. */
|
/* Receive something 64 bits or smaller on a channel. */
|
||||||
|
|
||||||
uint64_t
|
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;
|
uint64_t ret;
|
||||||
|
|
||||||
|
|
@ -273,11 +274,26 @@ __go_receive_small (struct __go_channel *channel, _Bool for_select)
|
||||||
__go_assert (channel->element_size <= sizeof (uint64_t));
|
__go_assert (channel->element_size <= sizeof (uint64_t));
|
||||||
|
|
||||||
if (!__go_receive_acquire (channel, for_select))
|
if (!__go_receive_acquire (channel, for_select))
|
||||||
return 0;
|
{
|
||||||
|
if (received != NULL)
|
||||||
|
*received = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
ret = channel->data[channel->next_fetch];
|
ret = channel->data[channel->next_fetch];
|
||||||
|
|
||||||
__go_receive_release (channel);
|
__go_receive_release (channel);
|
||||||
|
|
||||||
|
if (received != NULL)
|
||||||
|
*received = 1;
|
||||||
|
|
||||||
return ret;
|
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);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue