Better error message for old syntax of send expression as value.
authorIan Lance Taylor <ian@gcc.gnu.org>
Mon, 28 Mar 2011 22:49:09 +0000 (22:49 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Mon, 28 Mar 2011 22:49:09 +0000 (22:49 +0000)
From-SVN: r171637

gcc/go/gofrontend/parse.cc
gcc/go/gofrontend/parse.h

index 3f783b127c10cce43919881139f6830765c9a7ec..1120c1e48274ce3f13a78349398bc4b5adf2d71e 100644 (file)
@@ -3153,7 +3153,7 @@ Parse::statement(Label* label)
          case KEYWORD_MAP:
          case KEYWORD_STRUCT:
          case KEYWORD_INTERFACE:
-           this->simple_stat(true, false, NULL, NULL);
+           this->simple_stat(true, NULL, NULL, NULL);
            break;
          case KEYWORD_GO:
          case KEYWORD_DEFER:
@@ -3206,7 +3206,7 @@ Parse::statement(Label* label)
            this->unget_token(Token::make_identifier_token(identifier,
                                                           is_exported,
                                                           location));
-           this->simple_stat(true, false, NULL, NULL);
+           this->simple_stat(true, NULL, NULL, NULL);
          }
       }
       break;
@@ -3221,14 +3221,14 @@ Parse::statement(Label* label)
                                 location);
        }
       else if (!token->is_op(OPERATOR_SEMICOLON))
-       this->simple_stat(true, false, NULL, NULL);
+       this->simple_stat(true, NULL, NULL, NULL);
       break;
 
     case Token::TOKEN_STRING:
     case Token::TOKEN_INTEGER:
     case Token::TOKEN_FLOAT:
     case Token::TOKEN_IMAGINARY:
-      this->simple_stat(true, false, NULL, NULL);
+      this->simple_stat(true, NULL, NULL, NULL);
       break;
 
     default:
@@ -3330,10 +3330,12 @@ Parse::labeled_stmt(const std::string& label_name, source_location location)
 // 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
+// RETURN_EXP is not NULL, and we see an ExpressionStat, we return the
 // expression rather than adding an expression statement to the
 // current block.  If we see something other than an ExpressionStat,
-// we add the statement and return NULL.
+// we add the statement, set *RETURN_EXP to true if we saw a send
+// statement, and return NULL.  The handling of send statements is for
+// better error messages.
 
 // If P_RANGE_CLAUSE is not NULL, then this will recognize a
 // RangeClause.
@@ -3342,7 +3344,7 @@ Parse::labeled_stmt(const std::string& label_name, source_location location)
 // guard (var := expr.("type") using the literal keyword "type").
 
 Expression*
-Parse::simple_stat(bool may_be_composite_lit, bool return_exp,
+Parse::simple_stat(bool may_be_composite_lit, bool* return_exp,
                   Range_clause* p_range_clause, Type_switch* p_type_switch)
 {
   const Token* token = this->peek_token();
@@ -3385,7 +3387,11 @@ Parse::simple_stat(bool may_be_composite_lit, bool return_exp,
     }
   token = this->peek_token();
   if (token->is_op(OPERATOR_CHANOP))
-    this->send_stmt(this->verify_not_sink(exp));
+    {
+      this->send_stmt(this->verify_not_sink(exp));
+      if (return_exp != NULL)
+       *return_exp = true;
+    }
   else if (token->is_op(OPERATOR_PLUSPLUS)
           || token->is_op(OPERATOR_MINUSMINUS))
     this->inc_dec_stat(this->verify_not_sink(exp));
@@ -3404,7 +3410,7 @@ Parse::simple_stat(bool may_be_composite_lit, bool return_exp,
           || token->is_op(OPERATOR_ANDEQ)
           || token->is_op(OPERATOR_BITCLEAREQ))
     this->assignment(this->verify_not_sink(exp), p_range_clause);
-  else if (return_exp)
+  else if (return_exp != NULL)
     return this->verify_not_sink(exp);
   else
     this->expression_stat(this->verify_not_sink(exp));
@@ -3743,9 +3749,14 @@ Parse::if_stat()
 
   this->gogo_->start_block(location);
 
+  bool saw_simple_stat = false;
   Expression* cond = NULL;
+  bool saw_send_stmt;
   if (this->simple_stat_may_start_here())
-    cond = this->simple_stat(false, true, NULL, NULL);
+    {
+      cond = this->simple_stat(false, &saw_send_stmt, NULL, NULL);
+      saw_simple_stat = true;
+    }
   if (cond != NULL && this->peek_token()->is_op(OPERATOR_SEMICOLON))
     {
       // The SimpleStat is an expression statement.
@@ -3756,7 +3767,20 @@ Parse::if_stat()
     {
       if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
        this->advance_token();
-      cond = this->expression(PRECEDENCE_NORMAL, false, false, NULL);
+      else if (saw_simple_stat)
+       {
+         if (saw_send_stmt)
+           error_at(this->location(),
+                    ("send statement used as value; "
+                     "use select for non-blocking send"));
+         else
+           error_at(this->location(),
+                    "expected %<;%> after statement in if expression");
+         if (!this->expression_may_start_here())
+           cond = Expression::make_error(this->location());
+       }
+      if (cond == NULL)
+       cond = this->expression(PRECEDENCE_NORMAL, false, false, NULL);
     }
 
   this->gogo_->start_block(this->location());
@@ -3809,10 +3833,16 @@ Parse::switch_stat(Label* label)
 
   this->gogo_->start_block(location);
 
+  bool saw_simple_stat = false;
   Expression* switch_val = NULL;
+  bool saw_send_stmt;
   Type_switch type_switch;
   if (this->simple_stat_may_start_here())
-    switch_val = this->simple_stat(false, true, NULL, &type_switch);
+    {
+      switch_val = this->simple_stat(false, &saw_send_stmt, NULL,
+                                    &type_switch);
+      saw_simple_stat = true;
+    }
   if (switch_val != NULL && this->peek_token()->is_op(OPERATOR_SEMICOLON))
     {
       // The SimpleStat is an expression statement.
@@ -3823,6 +3853,16 @@ Parse::switch_stat(Label* label)
     {
       if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
        this->advance_token();
+      else if (saw_simple_stat)
+       {
+         if (saw_send_stmt)
+           error_at(this->location(),
+                    ("send statement used as value; "
+                     "use select for non-blocking send"));
+         else
+           error_at(this->location(),
+                    "expected %<;%> after statement in switch expression");
+       }
       if (!this->peek_token()->is_op(OPERATOR_LCURLY))
        {
          if (this->peek_token()->is_identifier())
@@ -3840,7 +3880,7 @@ Parse::switch_stat(Label* label)
              if (is_coloneq)
                {
                  // This must be a TypeSwitchGuard.
-                 switch_val = this->simple_stat(false, true, NULL,
+                 switch_val = this->simple_stat(false, &saw_send_stmt, NULL,
                                                 &type_switch);
                  if (!type_switch.found)
                    {
@@ -4500,11 +4540,19 @@ Parse::for_stat(Label* label)
        {
          // We might be looking at a Condition, an InitStat, or a
          // RangeClause.
-         cond = this->simple_stat(false, true, &range_clause, NULL);
+         bool saw_send_stmt;
+         cond = this->simple_stat(false, &saw_send_stmt, &range_clause, NULL);
          if (!this->peek_token()->is_op(OPERATOR_SEMICOLON))
            {
              if (cond == NULL && !range_clause.found)
-               error_at(this->location(), "parse error in for statement");
+               {
+                 if (saw_send_stmt)
+                   error_at(this->location(),
+                            ("send statement used as value; "
+                             "use select for non-blocking send"));
+                 else
+                   error_at(this->location(), "parse error in for statement");
+               }
            }
          else
            {
@@ -4608,7 +4656,7 @@ Parse::for_clause(Expression** cond, Block** post)
   else
     {
       this->gogo_->start_block(this->location());
-      this->simple_stat(false, false, NULL, NULL);
+      this->simple_stat(false, NULL, NULL, NULL);
       *post = this->gogo_->finish_block(this->location());
     }
 }
@@ -4992,8 +5040,13 @@ Parse::program()
        token = this->advance_token();
       else if (!token->is_eof() || !saw_errors())
        {
-         error_at(this->location(),
-                  "expected %<;%> or newline after top level declaration");
+         if (token->is_op(OPERATOR_CHANOP))
+           error_at(this->location(),
+                    ("send statement used as value; "
+                     "use select for non-blocking send"));
+         else
+           error_at(this->location(),
+                    "expected %<;%> or newline after top level declaration");
          this->skip_past_error(OPERATOR_INVALID);
        }
     }
index a9f6455a6f1ca202d9ff7879d5c0a81f2c6d247e..f072fd35932dee6cd6d05111a459bb2d9b5fbf10 100644 (file)
@@ -223,7 +223,7 @@ class Parse
   void statement(Label*);
   bool statement_may_start_here();
   void labeled_stmt(const std::string&, source_location);
-  Expression* simple_stat(bool, bool, Range_clause*, Type_switch*);
+  Expression* simple_stat(bool, bool*, Range_clause*, Type_switch*);
   bool simple_stat_may_start_here();
   void statement_list();
   bool statement_list_may_start_here();