From 27a19c584743458ee775ef5e0af5d0e32a465f06 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 24 Mar 2011 00:01:44 +0000 Subject: [PATCH] Change c <- v from an expression to a statement. Don't do anything special if we don't use the value of <-c. Fix sending an untyped constant in a select statement. From-SVN: r171371 --- gcc/go/gofrontend/expressions.cc | 97 ----------- gcc/go/gofrontend/expressions.h | 74 +-------- gcc/go/gofrontend/gogo.cc | 8 - gcc/go/gofrontend/parse.cc | 53 +++--- gcc/go/gofrontend/parse.h | 2 +- gcc/go/gofrontend/statements.cc | 97 ++++++++++- gcc/go/gofrontend/statements.h | 44 +++++ gcc/testsuite/go.test/test/chan/nonblock.go | 153 ++++++++++++------ gcc/testsuite/go.test/test/chan/perm.go | 59 ++++--- gcc/testsuite/go.test/test/closedchan.go | 92 +++++++++-- .../go.test/test/fixedbugs/bug069.go | 23 +-- .../go.test/test/fixedbugs/bug196.go | 7 +- .../go.test/test/fixedbugs/bug234.go | 25 +-- .../go.test/test/fixedbugs/bug242.go | 7 +- gcc/testsuite/go.test/test/named1.go | 9 +- 15 files changed, 420 insertions(+), 330 deletions(-) diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 8660c755abb..125715bb2de 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -12357,103 +12357,6 @@ Expression::make_receive(Expression* channel, source_location location) return new Receive_expression(channel, location); } -// Class Send_expression. - -// Traversal. - -int -Send_expression::do_traverse(Traverse* traverse) -{ - if (Expression::traverse(&this->channel_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return Expression::traverse(&this->val_, traverse); -} - -// Get the type. - -Type* -Send_expression::do_type() -{ - if (this->is_value_discarded_) - return Type::make_void_type(); - else - return Type::lookup_bool_type(); -} - -// Set types. - -void -Send_expression::do_determine_type(const Type_context*) -{ - this->channel_->determine_type_no_context(); - - Type* type = this->channel_->type(); - Type_context subcontext; - if (type->channel_type() != NULL) - subcontext.type = type->channel_type()->element_type(); - this->val_->determine_type(&subcontext); -} - -// Check types. - -void -Send_expression::do_check_types(Gogo*) -{ - Type* type = this->channel_->type(); - if (type->is_error_type()) - { - this->set_is_error(); - return; - } - Channel_type* channel_type = type->channel_type(); - if (channel_type == NULL) - { - error_at(this->location(), "left operand of %<<-%> must be channel"); - this->set_is_error(); - return; - } - Type* element_type = channel_type->element_type(); - if (element_type != NULL - && !Type::are_assignable(element_type, this->val_->type(), NULL)) - { - this->report_error(_("incompatible types in send")); - return; - } - if (!channel_type->may_send()) - { - this->report_error(_("invalid send on receive-only channel")); - return; - } -} - -// Get a tree for a send expression. - -tree -Send_expression::do_get_tree(Translate_context* context) -{ - tree channel = this->channel_->get_tree(context); - tree val = this->val_->get_tree(context); - if (channel == error_mark_node || val == error_mark_node) - return error_mark_node; - Channel_type* channel_type = this->channel_->type()->channel_type(); - val = Expression::convert_for_assignment(context, - channel_type->element_type(), - this->val_->type(), - val, - this->location()); - return Gogo::send_on_channel(channel, val, this->is_value_discarded_, - this->for_select_, this->location()); -} - -// Make a send expression - -Send_expression* -Expression::make_send(Expression* channel, Expression* val, - source_location location) -{ - return new Send_expression(channel, val, location); -} - // An expression which evaluates to a pointer to the type descriptor // of a type. diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 1dc408d557f..fa240a69b8c 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -36,7 +36,6 @@ class Field_reference_expression; class Interface_field_reference_expression; class Type_guard_expression; class Receive_expression; -class Send_expression; class Named_object; class Export; class Import; @@ -89,7 +88,6 @@ class Expression EXPRESSION_COMPOSITE_LITERAL, EXPRESSION_HEAP_COMPOSITE, EXPRESSION_RECEIVE, - EXPRESSION_SEND, EXPRESSION_TYPE_DESCRIPTOR, EXPRESSION_TYPE_INFO, EXPRESSION_STRUCT_FIELD_OFFSET, @@ -271,10 +269,6 @@ class Expression static Receive_expression* make_receive(Expression* channel, source_location); - // Make a send expression. - static Send_expression* - make_send(Expression* channel, Expression* val, source_location); - // Make an expression which evaluates to the type descriptor of a // type. static Expression* @@ -356,8 +350,7 @@ class Expression // This is called by the parser if the value of this expression is // being discarded. This issues warnings about computed values - // being unused, and handles send expressions which act differently - // depending upon whether the value is used. + // being unused. void discarding_value() { this->do_discarding_value(); } @@ -1807,7 +1800,7 @@ class Receive_expression : public Expression public: Receive_expression(Expression* channel, source_location location) : Expression(EXPRESSION_RECEIVE, location), - channel_(channel), is_value_discarded_(false), for_select_(false) + channel_(channel), for_select_(false) { } // Return the channel. @@ -1827,7 +1820,7 @@ class Receive_expression : public Expression void do_discarding_value() - { this->is_value_discarded_ = true; } + { } Type* do_type(); @@ -1855,67 +1848,6 @@ class Receive_expression : public Expression private: // The channel from which we are receiving. Expression* channel_; - // Whether the value is being discarded. - bool is_value_discarded_; - // Whether this is for a select statement. - bool for_select_; -}; - -// A send expression. - -class Send_expression : public Expression -{ - public: - Send_expression(Expression* channel, Expression* val, - source_location location) - : Expression(EXPRESSION_SEND, location), - channel_(channel), val_(val), is_value_discarded_(false), - for_select_(false) - { } - - // Note that this is for a select statement. - void - set_for_select() - { this->for_select_ = true; } - - protected: - int - do_traverse(Traverse* traverse); - - void - do_discarding_value() - { this->is_value_discarded_ = true; } - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return Expression::make_send(this->channel_->copy(), this->val_->copy(), - this->location()); - } - - bool - do_must_eval_in_order() const - { return true; } - - tree - do_get_tree(Translate_context*); - - private: - // The channel on which to send the value. - Expression* channel_; - // The value to send. - Expression* val_; - // Whether the value is being discarded. - bool is_value_discarded_; // Whether this is for a select statement. bool for_select_; }; diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index f8c143c9c29..f2476d549d1 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -1926,14 +1926,6 @@ Order_eval::statement(Block* block, size_t* pindex, Statement* s) { Expression** pexpr = *p; - // If the last expression is a send or receive expression, we - // may be ignoring the value; we don't want to evaluate it - // early. - if (p + 1 == find_eval_ordering.end() - && ((*pexpr)->classification() == Expression::EXPRESSION_SEND - || (*pexpr)->classification() == Expression::EXPRESSION_RECEIVE)) - break; - // The last expression in a thunk will be the call passed to go // or defer, which we must not evaluate early. if (is_thunk && p + 1 == find_eval_ordering.end()) diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index 7c03870e82e..2e591495684 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -2944,9 +2944,6 @@ Parse::expression(Precedence precedence, bool may_be_sink, case OPERATOR_ANDAND: right_precedence = PRECEDENCE_ANDAND; break; - case OPERATOR_CHANOP: - right_precedence = PRECEDENCE_CHANOP; - break; case OPERATOR_EQEQ: case OPERATOR_NOTEQ: case OPERATOR_LT: @@ -2997,10 +2994,7 @@ Parse::expression(Precedence precedence, bool may_be_sink, Expression* right = this->expression(right_precedence, false, may_be_composite_lit, NULL); - if (op == OPERATOR_CHANOP) - left = Expression::make_send(left, right, binop_location); - else - left = Expression::make_binary(op, left, right, binop_location); + left = Expression::make_binary(op, left, right, binop_location); } } @@ -3302,8 +3296,10 @@ Parse::labeled_stmt(const std::string& label_name, source_location location) this->statement(label); } -// SimpleStat = -// ExpressionStat | IncDecStat | Assignment | SimpleVarDecl . +// SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | +// Assignment | ShortVarDecl . + +// EmptyStmt was handled in Parse::statement. // In order to make this work for if and switch statements, if // RETURN_EXP is true, and we see an ExpressionStat, we return the @@ -3360,7 +3356,10 @@ Parse::simple_stat(bool may_be_composite_lit, bool return_exp, return NULL; } token = this->peek_token(); - if (token->is_op(OPERATOR_PLUSPLUS) || token->is_op(OPERATOR_MINUSMINUS)) + if (token->is_op(OPERATOR_CHANOP)) + this->send_stmt(this->verify_not_sink(exp)); + else if (token->is_op(OPERATOR_PLUSPLUS) + || token->is_op(OPERATOR_MINUSMINUS)) this->inc_dec_stat(this->verify_not_sink(exp)); else if (token->is_op(OPERATOR_COMMA) || token->is_op(OPERATOR_EQ)) @@ -3430,6 +3429,20 @@ Parse::expression_stat(Expression* exp) this->gogo_->add_statement(Statement::make_statement(exp)); } +// SendStmt = Channel "<-" Expression . +// Channel = Expression . + +void +Parse::send_stmt(Expression* channel) +{ + gcc_assert(this->peek_token()->is_op(OPERATOR_CHANOP)); + source_location loc = this->location(); + this->advance_token(); + Expression* val = this->expression(PRECEDENCE_NORMAL, false, true, NULL); + Statement* s = Statement::make_send_statement(channel, val, loc); + this->gogo_->add_statement(s); +} + // IncDecStat = Expression ( "++" | "--" ) . void @@ -4159,7 +4172,7 @@ Parse::select_stat(const Label* label) this->gogo_->add_statement(statement); } -// CommClause = CommCase [ StatementList ] . +// CommClause = CommCase ":" { Statement ";" } . void Parse::comm_clause(Select_clauses* clauses, bool* saw_default) @@ -4173,6 +4186,11 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default) bool got_case = this->comm_case(&is_send, &channel, &val, &varname, &is_default); + if (this->peek_token()->is_op(OPERATOR_COLON)) + this->advance_token(); + else + error_at(this->location(), "expected colon"); + Block* statements = NULL; Named_object* var = NULL; if (this->peek_token()->is_op(OPERATOR_SEMICOLON)) @@ -4214,7 +4232,7 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default) } } -// CommCase = ( "default" | ( "case" ( SendExpr | RecvExpr) ) ) ":" . +// CommCase = "case" ( SendStmt | RecvStmt ) | "default" . bool Parse::comm_case(bool* is_send, Expression** channel, Expression** val, @@ -4240,18 +4258,9 @@ Parse::comm_case(bool* is_send, Expression** channel, Expression** val, return false; } - if (!this->peek_token()->is_op(OPERATOR_COLON)) - { - error_at(this->location(), "expected colon"); - return false; - } - - this->advance_token(); - return true; } -// SendExpr = Expression "<-" Expression . // RecvExpr = [ Expression ( "=" | ":=" ) ] "<-" Expression . bool @@ -4291,7 +4300,7 @@ Parse::send_or_recv_expr(bool* is_send, Expression** channel, Expression** val, } else { - Expression* left = this->expression(PRECEDENCE_CHANOP, true, true, NULL); + Expression* left = this->expression(PRECEDENCE_NORMAL, true, true, NULL); if (this->peek_token()->is_op(OPERATOR_EQ)) { diff --git a/gcc/go/gofrontend/parse.h b/gcc/go/gofrontend/parse.h index 6f2ac64b1f7..04ae324f4d8 100644 --- a/gcc/go/gofrontend/parse.h +++ b/gcc/go/gofrontend/parse.h @@ -44,7 +44,6 @@ class Parse PRECEDENCE_NORMAL = 0, PRECEDENCE_OROR, PRECEDENCE_ANDAND, - PRECEDENCE_CHANOP, PRECEDENCE_RELOP, PRECEDENCE_ADDOP, PRECEDENCE_MULOP @@ -229,6 +228,7 @@ class Parse void statement_list(); bool statement_list_may_start_here(); void expression_stat(Expression*); + void send_stmt(Expression*); void inc_dec_stat(Expression*); void assignment(Expression*, Range_clause*); void tuple_assignment(Expression_list*, Range_clause*); diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index c443519b77d..5a4ad061329 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -3987,6 +3987,90 @@ Statement::make_type_switch_statement(Named_object* var, Expression* expr, return new Type_switch_statement(var, expr, location); } +// Class Send_statement. + +// Traversal. + +int +Send_statement::do_traverse(Traverse* traverse) +{ + if (this->traverse_expression(traverse, &this->channel_) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + return this->traverse_expression(traverse, &this->val_); +} + +// Determine types. + +void +Send_statement::do_determine_types() +{ + this->channel_->determine_type_no_context(); + Type* type = this->channel_->type(); + Type_context context; + if (type->channel_type() != NULL) + context.type = type->channel_type()->element_type(); + this->val_->determine_type(&context); +} + +// Check types. + +void +Send_statement::do_check_types(Gogo*) +{ + Type* type = this->channel_->type(); + if (type->is_error_type()) + { + this->set_is_error(); + return; + } + Channel_type* channel_type = type->channel_type(); + if (channel_type == NULL) + { + error_at(this->location(), "left operand of %<<-%> must be channel"); + this->set_is_error(); + return; + } + Type* element_type = channel_type->element_type(); + if (!Type::are_assignable(element_type, this->val_->type(), NULL)) + { + this->report_error(_("incompatible types in send")); + return; + } + if (!channel_type->may_send()) + { + this->report_error(_("invalid send on receive-only channel")); + return; + } +} + +// Get a tree for a send statement. + +tree +Send_statement::do_get_tree(Translate_context* context) +{ + tree channel = this->channel_->get_tree(context); + tree val = this->val_->get_tree(context); + if (channel == error_mark_node || val == error_mark_node) + return error_mark_node; + Channel_type* channel_type = this->channel_->type()->channel_type(); + val = Expression::convert_for_assignment(context, + channel_type->element_type(), + this->val_->type(), + val, + this->location()); + return Gogo::send_on_channel(channel, val, true, this->for_select_, + this->location()); +} + +// Make a send statement. + +Send_statement* +Statement::make_send_statement(Expression* channel, Expression* val, + source_location location) +{ + return new Send_statement(channel, val, location); +} + // Class Select_clauses::Select_clause. // Traversal. @@ -4043,7 +4127,7 @@ Select_clauses::Select_clause::lower(Block* b) // If this is a send clause, evaluate the value to send before the // select statement. Temporary_statement* val_temp = NULL; - if (this->is_send_) + if (this->is_send_ && !this->val_->is_constant()) { val_temp = Statement::make_temporary(NULL, this->val_, loc); b->add_statement(val_temp); @@ -4054,11 +4138,14 @@ Select_clauses::Select_clause::lower(Block* b) Expression* ref = Expression::make_temporary_reference(channel_temp, loc); if (this->is_send_) { - Expression* ref2 = Expression::make_temporary_reference(val_temp, loc); - Send_expression* send = Expression::make_send(ref, ref2, loc); - send->discarding_value(); + Expression* ref2; + if (val_temp == NULL) + ref2 = this->val_; + else + ref2 = Expression::make_temporary_reference(val_temp, loc); + Send_statement* send = Statement::make_send_statement(ref, ref2, loc); send->set_for_select(); - init->add_statement(Statement::make_statement(send)); + init->add_statement(send); } else { diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h index 80cdffe801e..83d5436ac74 100644 --- a/gcc/go/gofrontend/statements.h +++ b/gcc/go/gofrontend/statements.h @@ -23,6 +23,7 @@ class For_statement; class For_range_statement; class Switch_statement; class Type_switch_statement; +class Send_statement; class Select_statement; class Variable; class Named_object; @@ -99,6 +100,7 @@ class Statement STATEMENT_UNNAMED_LABEL, STATEMENT_IF, STATEMENT_CONSTANT_SWITCH, + STATEMENT_SEND, STATEMENT_SELECT, // These statements types are created by the parser, but they @@ -236,6 +238,10 @@ class Statement static Type_switch_statement* make_type_switch_statement(Named_object* var, Expression*, source_location); + // Make a send statement. + static Send_statement* + make_send_statement(Expression* channel, Expression* val, source_location); + // Make a select statement. static Select_statement* make_select_statement(source_location); @@ -592,6 +598,44 @@ class Return_statement : public Statement Expression_list* vals_; }; +// A send statement. + +class Send_statement : public Statement +{ + public: + Send_statement(Expression* channel, Expression* val, + source_location location) + : Statement(STATEMENT_SEND, location), + channel_(channel), val_(val), for_select_(false) + { } + + // Note that this is for a select statement. + void + set_for_select() + { this->for_select_ = true; } + + protected: + int + do_traverse(Traverse* traverse); + + void + do_determine_types(); + + void + do_check_types(Gogo*); + + tree + do_get_tree(Translate_context*); + + private: + // The channel on which to send the value. + Expression* channel_; + // The value to send. + Expression* val_; + // Whether this is for a select statement. + bool for_select_; +}; + // Select_clauses holds the clauses of a select statement. This is // built by the parser. diff --git a/gcc/testsuite/go.test/test/chan/nonblock.go b/gcc/testsuite/go.test/test/chan/nonblock.go index 52f04bfb12f..33afb329165 100644 --- a/gcc/testsuite/go.test/test/chan/nonblock.go +++ b/gcc/testsuite/go.test/test/chan/nonblock.go @@ -76,7 +76,6 @@ func main() { var i64 int64 var b bool var s string - var ok bool var sync = make(chan bool) @@ -86,35 +85,45 @@ func main() { cb := make(chan bool, buffer) cs := make(chan string, buffer) - i32, ok = <-c32 - if ok { + select { + case i32 = <-c32: panic("blocked i32sender") + default: } - i64, ok = <-c64 - if ok { + select { + case i64 = <-c64: panic("blocked i64sender") + default: } - b, ok = <-cb - if ok { + select { + case b = <-cb: panic("blocked bsender") + default: } - s, ok = <-cs - if ok { + select { + case s = <-cs: panic("blocked ssender") + default: } go i32receiver(c32, sync) try := 0 - for !(c32 <- 123) { - try++ - if try > maxTries { - println("i32receiver buffer=", buffer) - panic("fail") + Send32: + for { + select { + case c32 <- 123: + break Send32 + default: + try++ + if try > maxTries { + println("i32receiver buffer=", buffer) + panic("fail") + } + sleep() } - sleep() } <-sync @@ -123,13 +132,19 @@ func main() { <-sync } try = 0 - for i32, ok = <-c32; !ok; i32, ok = <-c32 { - try++ - if try > maxTries { - println("i32sender buffer=", buffer) - panic("fail") + Recv32: + for { + select { + case i32 = <-c32: + break Recv32 + default: + try++ + if try > maxTries { + println("i32sender buffer=", buffer) + panic("fail") + } + sleep() } - sleep() } if i32 != 234 { panic("i32sender value") @@ -140,12 +155,18 @@ func main() { go i64receiver(c64, sync) try = 0 - for !(c64 <- 123456) { - try++ - if try > maxTries { - panic("i64receiver") + Send64: + for { + select { + case c64 <- 123456: + break Send64 + default: + try++ + if try > maxTries { + panic("i64receiver") + } + sleep() } - sleep() } <-sync @@ -154,12 +175,18 @@ func main() { <-sync } try = 0 - for i64, ok = <-c64; !ok; i64, ok = <-c64 { - try++ - if try > maxTries { - panic("i64sender") + Recv64: + for { + select { + case i64 = <-c64: + break Recv64 + default: + try++ + if try > maxTries { + panic("i64sender") + } + sleep() } - sleep() } if i64 != 234567 { panic("i64sender value") @@ -170,12 +197,18 @@ func main() { go breceiver(cb, sync) try = 0 - for !(cb <- true) { - try++ - if try > maxTries { - panic("breceiver") + SendBool: + for { + select { + case cb <- true: + break SendBool + default: + try++ + if try > maxTries { + panic("breceiver") + } + sleep() } - sleep() } <-sync @@ -184,12 +217,18 @@ func main() { <-sync } try = 0 - for b, ok = <-cb; !ok; b, ok = <-cb { - try++ - if try > maxTries { - panic("bsender") + RecvBool: + for { + select { + case b = <-cb: + break RecvBool + default: + try++ + if try > maxTries { + panic("bsender") + } + sleep() } - sleep() } if !b { panic("bsender value") @@ -200,12 +239,18 @@ func main() { go sreceiver(cs, sync) try = 0 - for !(cs <- "hello") { - try++ - if try > maxTries { - panic("sreceiver") + SendString: + for { + select { + case cs <- "hello": + break SendString + default: + try++ + if try > maxTries { + panic("sreceiver") + } + sleep() } - sleep() } <-sync @@ -214,12 +259,18 @@ func main() { <-sync } try = 0 - for s, ok = <-cs; !ok; s, ok = <-cs { - try++ - if try > maxTries { - panic("ssender") + RecvString: + for { + select { + case s = <-cs: + break RecvString + default: + try++ + if try > maxTries { + panic("ssender") + } + sleep() } - sleep() } if s != "hello again" { panic("ssender value") diff --git a/gcc/testsuite/go.test/test/chan/perm.go b/gcc/testsuite/go.test/test/chan/perm.go index d08c035193d..c725829d132 100644 --- a/gcc/testsuite/go.test/test/chan/perm.go +++ b/gcc/testsuite/go.test/test/chan/perm.go @@ -9,49 +9,46 @@ package main var ( cr <-chan int cs chan<- int - c chan int + c chan int ) func main() { - cr = c // ok - cs = c // ok - c = cr // ERROR "illegal types|incompatible|cannot" - c = cs // ERROR "illegal types|incompatible|cannot" - cr = cs // ERROR "illegal types|incompatible|cannot" - cs = cr // ERROR "illegal types|incompatible|cannot" + cr = c // ok + cs = c // ok + c = cr // ERROR "illegal types|incompatible|cannot" + c = cs // ERROR "illegal types|incompatible|cannot" + cr = cs // ERROR "illegal types|incompatible|cannot" + cs = cr // ERROR "illegal types|incompatible|cannot" - c <- 0 // ok - ok := c <- 0 // ok - _ = ok - <-c // ok - x, ok := <-c // ok - _, _ = x, ok + c <- 0 // ok + <-c // ok + //TODO(rsc): uncomment when this syntax is valid for receive+check closed + // x, ok := <-c // ok + // _, _ = x, ok - cr <- 0 // ERROR "send" - ok = cr <- 0 // ERROR "send" - _ = ok - <-cr // ok - x, ok = <-cr // ok - _, _ = x, ok + cr <- 0 // ERROR "send" + <-cr // ok + //TODO(rsc): uncomment when this syntax is valid for receive+check closed + // x, ok = <-cr // ok + // _, _ = x, ok - cs <- 0 // ok - ok = cs <- 0 // ok - _ = ok - <-cs // ERROR "receive" - x, ok = <-cs // ERROR "receive" - _, _ = x, ok + cs <- 0 // ok + <-cs // ERROR "receive" + ////TODO(rsc): uncomment when this syntax is valid for receive+check closed + //// x, ok = <-cs // ERROR "receive" + //// _, _ = x, ok select { - case c <- 0: // ok - case x := <-c: // ok + case c <- 0: // ok + case x := <-c: // ok _ = x - case cr <- 0: // ERROR "send" - case x := <-cr: // ok + case cr <- 0: // ERROR "send" + case x := <-cr: // ok _ = x - case cs <- 0: // ok - case x := <-cs: // ERROR "receive" + case cs <- 0: // ok + case x := <-cs: // ERROR "receive" _ = x } } diff --git a/gcc/testsuite/go.test/test/closedchan.go b/gcc/testsuite/go.test/test/closedchan.go index 8126d5a4e4c..46d9d0f5d21 100644 --- a/gcc/testsuite/go.test/test/closedchan.go +++ b/gcc/testsuite/go.test/test/closedchan.go @@ -21,14 +21,21 @@ type Chan interface { Impl() string } -// direct channel operations +// direct channel operations when possible type XChan chan int + func (c XChan) Send(x int) { c <- x } func (c XChan) Nbsend(x int) bool { - return c <- x + select { + case c <- x: + return true + default: + return false + } + panic("nbsend") } func (c XChan) Recv() int { @@ -36,8 +43,13 @@ func (c XChan) Recv() int { } func (c XChan) Nbrecv() (int, bool) { - x, ok := <-c - return x, ok + select { + case x := <-c: + return x, true + default: + return 0, false + } + panic("nbrecv") } func (c XChan) Close() { @@ -54,6 +66,7 @@ func (c XChan) Impl() string { // indirect operations via select type SChan chan int + func (c SChan) Send(x int) { select { case c <- x: @@ -62,10 +75,10 @@ func (c SChan) Send(x int) { func (c SChan) Nbsend(x int) bool { select { - case c <- x: - return true default: return false + case c <- x: + return true } panic("nbsend") } @@ -80,10 +93,10 @@ func (c SChan) Recv() int { func (c SChan) Nbrecv() (int, bool) { select { - case x := <-c: - return x, true default: return 0, false + case x := <-c: + return x, true } panic("nbrecv") } @@ -100,6 +113,62 @@ func (c SChan) Impl() string { return "(select)" } +// indirect operations via larger selects +var dummy = make(chan bool) + +type SSChan chan int + +func (c SSChan) Send(x int) { + select { + case c <- x: + case <-dummy: + } +} + +func (c SSChan) Nbsend(x int) bool { + select { + default: + return false + case <-dummy: + case c <- x: + return true + } + panic("nbsend") +} + +func (c SSChan) Recv() int { + select { + case <-dummy: + case x := <-c: + return x + } + panic("recv") +} + +func (c SSChan) Nbrecv() (int, bool) { + select { + case <-dummy: + default: + return 0, false + case x := <-c: + return x, true + } + panic("nbrecv") +} + +func (c SSChan) Close() { + close(c) +} + +func (c SSChan) Closed() bool { + return closed(c) +} + +func (c SSChan) Impl() string { + return "(select)" +} + + func shouldPanic(f func()) { defer func() { if recover() == nil { @@ -137,7 +206,7 @@ func test1(c Chan) { } // send should work with ,ok too: sent a value without blocking, so ok == true. - shouldPanic(func(){c.Nbsend(1)}) + shouldPanic(func() { c.Nbsend(1) }) // the value should have been discarded. if x := c.Recv(); x != 0 { @@ -145,7 +214,7 @@ func test1(c Chan) { } // similarly Send. - shouldPanic(func(){c.Send(2)}) + shouldPanic(func() { c.Send(2) }) if x := c.Recv(); x != 0 { println("test1: recv on closed got non-zero after send on closed:", x, c.Impl()) } @@ -195,9 +264,12 @@ func closedasync() chan int { func main() { test1(XChan(closedsync())) test1(SChan(closedsync())) + test1(SSChan(closedsync())) testasync1(XChan(closedasync())) testasync1(SChan(closedasync())) + testasync1(SSChan(closedasync())) testasync2(XChan(closedasync())) testasync2(SChan(closedasync())) + testasync2(SSChan(closedasync())) } diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug069.go b/gcc/testsuite/go.test/test/fixedbugs/bug069.go index d6796cd72be..bf73163134d 100644 --- a/gcc/testsuite/go.test/test/fixedbugs/bug069.go +++ b/gcc/testsuite/go.test/test/fixedbugs/bug069.go @@ -6,15 +6,16 @@ package main -func main(){ - c := make(chan int); - ok := false; - var i int; - - i, ok = <-c; // works - _, _ = i, ok; - - ca := new([2]chan int); - i, ok = <-(ca[0]); // fails: c.go:11: bad shape across assignment - cr=1 cl=2 - _, _ = i, ok; +func main() { + //TODO(rsc): uncomment when this syntax is valid for receive+check closed + // c := make(chan int); + // ok := false; + // var i int; + // + // i, ok = <-c; // works + // _, _ = i, ok; + // + // ca := new([2]chan int); + // i, ok = <-(ca[0]); // fails: c.go:11: bad shape across assignment - cr=1 cl=2 + // _, _ = i, ok; } diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug196.go b/gcc/testsuite/go.test/test/fixedbugs/bug196.go index ea8ab0dc193..8cb9c9990d9 100644 --- a/gcc/testsuite/go.test/test/fixedbugs/bug196.go +++ b/gcc/testsuite/go.test/test/fixedbugs/bug196.go @@ -13,11 +13,12 @@ var i int func multi() (int, int) { return 1, 2 } func xxx() { - var c chan int - x, ok := <-c + //TODO(rsc): uncomment when this syntax is valid for receive+check closed + // var c chan int + // x, ok := <-c var m map[int]int - x, ok = m[1] + x, ok := m[1] var i interface{} var xx int diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug234.go b/gcc/testsuite/go.test/test/fixedbugs/bug234.go index b806ca64e98..9affad04302 100644 --- a/gcc/testsuite/go.test/test/fixedbugs/bug234.go +++ b/gcc/testsuite/go.test/test/fixedbugs/bug234.go @@ -7,16 +7,17 @@ package main func main() { - c := make(chan int, 1) - c <- 100 - x, ok := <-c - if x != 100 || !ok { - println("x=", x, " ok=", ok, " want 100, true") - panic("fail") - } - x, ok = <-c - if x != 0 || ok { - println("x=", x, " ok=", ok, " want 0, false") - panic("fail") - } + //TODO(rsc): uncomment when this syntax is valid for receive+check closed + // c := make(chan int, 1) + // c <- 100 + // x, ok := <-c + // if x != 100 || !ok { + // println("x=", x, " ok=", ok, " want 100, true") + // panic("fail") + // } + // x, ok = <-c + // if x != 0 || ok { + // println("x=", x, " ok=", ok, " want 0, false") + // panic("fail") + // } } diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug242.go b/gcc/testsuite/go.test/test/fixedbugs/bug242.go index 5c21eaaf008..ad1cef8df43 100644 --- a/gcc/testsuite/go.test/test/fixedbugs/bug242.go +++ b/gcc/testsuite/go.test/test/fixedbugs/bug242.go @@ -101,10 +101,13 @@ func main() { c := make(chan byte, 1) c <- 'C' + //TODO(rsc): uncomment when this syntax is valid for receive+check closed // 15 16 - *f(), p1 = <-e1(c, 16) + // *f(), p1 = <-e1(c, 16) + *f(), p1 = <-e1(c, 16), true // delete uncommenting above // 17 18 - *f(), p2 = <-e1(c, 18) + // *f(), p2 = <-e1(c, 18) + *f(), p2, _ = 0, false, e1(c, 18) // delete when uncommenting above a[17] += '0' if !p1 || p2 { println("bad chan check", i, p1, p2) diff --git a/gcc/testsuite/go.test/test/named1.go b/gcc/testsuite/go.test/test/named1.go index 600e502f9e8..1776313f05c 100644 --- a/gcc/testsuite/go.test/test/named1.go +++ b/gcc/testsuite/go.test/test/named1.go @@ -43,12 +43,9 @@ func main() { _, b = m[2] // ERROR "cannot .* bool.*type Bool" m[2] = 1, b // ERROR "cannot use.*type Bool.*as type bool" - b = c <- 1 // ERROR "cannot use.*type bool.*type Bool" - _ = b - asBool(c <- 1) // ERROR "cannot use.*type bool.*as type Bool" - - _, b = <-c // ERROR "cannot .* bool.*type Bool" - _ = b + ////TODO(rsc): uncomment when this syntax is valid for receive+check closed + //// _, b = <-c // ERROR "cannot .* bool.*type Bool" + //// _ = b var inter interface{} _, b = inter.(Map) // ERROR "cannot .* bool.*type Bool"