From: Ian Lance Taylor Date: Thu, 24 Mar 2011 06:01:27 +0000 (+0000) Subject: Tuple receives indicate whether channel is closed. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3137991dfc4e0b6023c4b75b2ae1eb86bea32241;p=gcc.git Tuple receives indicate whether channel is closed. From-SVN: r171380 --- diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc index 562a5afa984..238a0d72487 100644 --- a/gcc/go/gofrontend/gogo-tree.cc +++ b/gcc/go/gofrontend/gogo-tree.cc @@ -3057,7 +3057,7 @@ Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select, location, "__go_receive_big", 3, - void_type_node, + boolean_type_node, ptr_type_node, channel, ptr_type_node, diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index f2476d549d1..f39124c1643 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -1257,7 +1257,7 @@ Lower_parse_tree::statement(Block* block, size_t* pindex, Statement* sorig) 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; @@ -1305,6 +1305,15 @@ Gogo::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. void diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 7a52a51a2c6..7a887a54296 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -348,6 +348,10 @@ class Gogo 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**); diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index e6588997f53..1f6e687ec82 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -4179,10 +4179,12 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default) 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(); @@ -4191,6 +4193,7 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default) 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()) @@ -4206,6 +4209,14 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default) 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()); } @@ -4221,7 +4232,8 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default) } 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 @@ -4234,7 +4246,8 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default) 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)) @@ -4245,7 +4258,8 @@ Parse::comm_case(bool* is_send, Expression** channel, Expression** val, 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 @@ -4259,74 +4273,160 @@ Parse::comm_case(bool* is_send, Expression** channel, Expression** val, 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 . diff --git a/gcc/go/gofrontend/parse.h b/gcc/go/gofrontend/parse.h index 04ae324f4d8..d164414df7b 100644 --- a/gcc/go/gofrontend/parse.h +++ b/gcc/go/gofrontend/parse.h @@ -246,8 +246,10 @@ class Parse void type_switch_case(std::vector*, 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*); diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 0a6ef8cea95..f9b0853e2ea 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -638,7 +638,7 @@ class Assignment_operation_statement : public Statement { gcc_unreachable(); } Statement* - do_lower(Gogo*, Block*); + do_lower(Gogo*, Named_object*, Block*); tree do_get_tree(Translate_context*) @@ -667,7 +667,8 @@ Assignment_operation_statement::do_traverse(Traverse* traverse) // 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(); @@ -764,7 +765,7 @@ class Tuple_assignment_statement : public Statement { gcc_unreachable(); } Statement* - do_lower(Gogo*, Block*); + do_lower(Gogo*, Named_object*, Block*); tree do_get_tree(Translate_context*) @@ -791,7 +792,7 @@ Tuple_assignment_statement::do_traverse(Traverse* traverse) // 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(); @@ -891,7 +892,7 @@ public: { gcc_unreachable(); } Statement* - do_lower(Gogo*, Block*); + do_lower(Gogo*, Named_object*, Block*); tree do_get_tree(Translate_context*) @@ -920,7 +921,8 @@ Tuple_map_assignment_statement::do_traverse(Traverse* traverse) // 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(); @@ -1037,7 +1039,7 @@ class Map_assignment_statement : public Statement { gcc_unreachable(); } Statement* - do_lower(Gogo*, Block*); + do_lower(Gogo*, Named_object*, Block*); tree do_get_tree(Translate_context*) @@ -1066,7 +1068,7 @@ Map_assignment_statement::do_traverse(Traverse* traverse) // 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(); @@ -1145,11 +1147,11 @@ Statement::make_map_assignment(Expression* map_index, 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: @@ -1161,7 +1163,7 @@ class Tuple_receive_assignment_statement : public Statement { gcc_unreachable(); } Statement* - do_lower(Gogo*, Block*); + do_lower(Gogo*, Named_object*, Block*); tree do_get_tree(Translate_context*) @@ -1170,8 +1172,8 @@ class Tuple_receive_assignment_statement : public Statement 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_; }; @@ -1182,7 +1184,7 @@ int 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_); } @@ -1190,7 +1192,8 @@ Tuple_receive_assignment_statement::do_traverse(Traverse* traverse) // 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(); @@ -1212,17 +1215,17 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Block* enclosing) // 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; @@ -1240,14 +1243,14 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Block* enclosing) 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); @@ -1256,9 +1259,9 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Block* enclosing) 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); @@ -1267,11 +1270,11 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Block* enclosing) // 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); } @@ -1297,7 +1300,7 @@ class Tuple_type_guard_assignment_statement : public Statement { gcc_unreachable(); } Statement* - do_lower(Gogo*, Block*); + do_lower(Gogo*, Named_object*, Block*); tree do_get_tree(Translate_context*) @@ -1338,7 +1341,8 @@ Tuple_type_guard_assignment_statement::do_traverse(Traverse* traverse) // 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(); @@ -1643,7 +1647,7 @@ class Inc_dec_statement : public Statement { gcc_unreachable(); } Statement* - do_lower(Gogo*, Block*); + do_lower(Gogo*, Named_object*, Block*); tree do_get_tree(Translate_context*) @@ -1659,7 +1663,7 @@ class Inc_dec_statement : public Statement // 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(); @@ -2429,7 +2433,7 @@ Return_statement::do_traverse_assignments(Traverse_assignments* tassign) // 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; @@ -3530,7 +3534,7 @@ Switch_statement::do_traverse(Traverse* traverse) // 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(); @@ -3871,7 +3875,7 @@ Type_switch_statement::do_traverse(Traverse* traverse) // 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(); @@ -4079,6 +4083,11 @@ Select_clauses::Select_clause::traverse(Traverse* traverse) 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) { @@ -4093,7 +4102,8 @@ Select_clauses::Select_clause::traverse(Traverse* traverse) // 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_) { @@ -4134,6 +4144,30 @@ Select_clauses::Select_clause::lower(Block* b) 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); @@ -4151,11 +4185,13 @@ Select_clauses::Select_clause::lower(Block* b) } 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)); @@ -4222,12 +4258,12 @@ Select_clauses::traverse(Traverse* traverse) // 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. @@ -4464,12 +4500,13 @@ Select_statement::break_label() // 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()); @@ -4521,7 +4558,7 @@ For_statement::do_traverse(Traverse* traverse) // 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(); @@ -4652,7 +4689,7 @@ For_range_statement::do_traverse(Traverse* traverse) // 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 diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h index 83d5436ac74..bb2922f180f 100644 --- a/gcc/go/gofrontend/statements.h +++ b/gcc/go/gofrontend/statements.h @@ -162,7 +162,7 @@ class Statement // 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. @@ -284,11 +284,11 @@ class Statement // 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 @@ -381,7 +381,7 @@ class Statement // 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 @@ -574,7 +574,7 @@ class Return_statement : public Statement do_traverse_assignments(Traverse_assignments*); Statement* - do_lower(Gogo*, Block*); + do_lower(Gogo*, Named_object*, Block*); void do_determine_types(); @@ -649,17 +649,22 @@ class Select_clauses // 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. @@ -668,7 +673,7 @@ class Select_clauses // Lower statements. void - lower(Block*); + lower(Gogo*, Named_object*, Block*); // Determine types. void @@ -689,16 +694,18 @@ class Select_clauses { 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. @@ -707,7 +714,7 @@ class Select_clauses // Lower statements. void - lower(Block*); + lower(Gogo*, Named_object*, Block*); // Determine types. void @@ -724,20 +731,6 @@ class Select_clauses 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 @@ -768,10 +761,16 @@ class Select_clauses 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. @@ -821,7 +820,7 @@ class Select_statement : public Statement { return this->clauses_->traverse(traverse); } Statement* - do_lower(Gogo*, Block*); + do_lower(Gogo*, Named_object*, Block*); void do_determine_types() @@ -1008,7 +1007,7 @@ class For_statement : public Statement { gcc_unreachable(); } Statement* - do_lower(Gogo*, Block*); + do_lower(Gogo*, Named_object*, Block*); tree do_get_tree(Translate_context*) @@ -1066,7 +1065,7 @@ class For_range_statement : public Statement { gcc_unreachable(); } Statement* - do_lower(Gogo*, Block*); + do_lower(Gogo*, Named_object*, Block*); tree do_get_tree(Translate_context*) @@ -1290,7 +1289,7 @@ class Switch_statement : public Statement do_traverse(Traverse*); Statement* - do_lower(Gogo*, Block*); + do_lower(Gogo*, Named_object*, Block*); tree do_get_tree(Translate_context*) @@ -1436,7 +1435,7 @@ class Type_switch_statement : public Statement do_traverse(Traverse*); Statement* - do_lower(Gogo*, Block*); + do_lower(Gogo*, Named_object*, Block*); tree do_get_tree(Translate_context*) diff --git a/libgo/runtime/chan.goc b/libgo/runtime/chan.goc index da0bbfccb10..c9de71f8d5e 100644 --- a/libgo/runtime/chan.goc +++ b/libgo/runtime/chan.goc @@ -12,28 +12,22 @@ typedef struct __go_channel chan; /* 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; } } diff --git a/libgo/runtime/channel.h b/libgo/runtime/channel.h index 5d2f49f1ee8..ea108289bf3 100644 --- a/libgo/runtime/channel.h +++ b/libgo/runtime/channel.h @@ -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_closed (struct __go_channel *, _Bool, + _Bool *); + extern void __go_receive_release (struct __go_channel *); struct __go_receive_nonblocking_small @@ -123,7 +126,7 @@ 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 *); diff --git a/libgo/runtime/go-rec-big.c b/libgo/runtime/go-rec-big.c index 23d65296aa9..a584fe7a273 100644 --- a/libgo/runtime/go-rec-big.c +++ b/libgo/runtime/go-rec-big.c @@ -9,7 +9,7 @@ #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; @@ -24,11 +24,13 @@ __go_receive_big (struct __go_channel *channel, void *val, _Bool for_select) 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; } diff --git a/libgo/runtime/go-rec-small.c b/libgo/runtime/go-rec-small.c index c4dc8b6e892..87aed3cd552 100644 --- a/libgo/runtime/go-rec-small.c +++ b/libgo/runtime/go-rec-small.c @@ -263,7 +263,8 @@ __go_unlock_and_notify_selects (struct __go_channel *channel) /* 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; @@ -273,11 +274,26 @@ __go_receive_small (struct __go_channel *channel, _Bool for_select) __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); +}