OSDN Git Service

Tuple receives indicate whether channel is closed.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 24 Mar 2011 06:01:27 +0000 (06:01 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 24 Mar 2011 06:01:27 +0000 (06:01 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@171380 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/go/gofrontend/gogo-tree.cc
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/parse.cc
gcc/go/gofrontend/parse.h
gcc/go/gofrontend/statements.cc
gcc/go/gofrontend/statements.h
libgo/runtime/chan.goc
libgo/runtime/channel.h
libgo/runtime/go-rec-big.c
libgo/runtime/go-rec-small.c

index 562a5af..238a0d7 100644 (file)
@@ -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,
index f2476d5..f39124c 100644 (file)
@@ -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
index 7a52a51..7a887a5 100644 (file)
@@ -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**);
index e658899..1f6e687 100644 (file)
@@ -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 .
index 04ae324..d164414 100644 (file)
@@ -246,8 +246,10 @@ class Parse
   void type_switch_case(std::vector<Type*>*, bool*);
   void select_stat(const Label*);
   void comm_clause(Select_clauses*, bool* saw_default);
-  bool comm_case(bool*, Expression**, Expression**, std::string*, bool*);
-  bool send_or_recv_expr(bool*, Expression**, Expression**, std::string*);
+  bool comm_case(bool*, Expression**, Expression**, Expression**,
+                std::string*, std::string*, bool*);
+  bool send_or_recv_stmt(bool*, Expression**, Expression**, Expression**,
+                        std::string*, std::string*);
   void for_stat(const Label*);
   void for_clause(Expression**, Block**);
   void range_clause_decl(const Typed_identifier_list*, Range_clause*);
index 0a6ef8c..f9b0853 100644 (file)
@@ -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
index 83d5436..bb2922f 100644 (file)
@@ -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*)
index da0bbfc..c9de71f 100644 (file)
@@ -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;
        }
 }
index 5d2f49f..ea10828 100644 (file)
@@ -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 *);
 
index 23d6529..a584fe7 100644 (file)
@@ -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;
 }
index c4dc8b6..87aed3c 100644 (file)
@@ -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);
+}