Patchwork Go patch committed: Fix parsing of type switches

login
register
mail settings
Submitter Ian Taylor
Date Dec. 14, 2010, 5:57 a.m.
Message ID <mcry67szyjr.fsf@google.com>
Download mbox | patch
Permalink /patch/75470/
State New
Headers show

Comments

Ian Taylor - Dec. 14, 2010, 5:57 a.m.
gccgo would incorrectly permit code like
	switch x := <-ch.(type) {
	case int:
	}
This is invalid: a type switch has to just be expr.(type), not an
expression on a type guard.  This patch fixes the type switch parsing.
In testing it I saw that the error reporting for an invalid type guard
was pretty bad, so I fixed that up too.  Bootstrapped and ran Go tests
on x86_64-unknown-linux-gnu.  Committed to mainline.

Ian

Patch

diff -r a3c80279619e go/expressions.cc
--- a/go/expressions.cc	Mon Dec 13 21:17:25 2010 -0800
+++ b/go/expressions.cc	Mon Dec 13 21:51:50 2010 -0800
@@ -11620,24 +11620,29 @@ 
 	this->report_error(_("invalid unsafe.Pointer conversion"));
     }
   else if (expr_type->interface_type() == NULL)
-    this->report_error(_("type assertion only valid for interface types"));
+    {
+      if (!expr_type->is_error_type() && !this->type_->is_error_type())
+	this->report_error(_("type assertion only valid for interface types"));
+      this->set_is_error();
+    }
   else if (this->type_->interface_type() == NULL)
     {
       std::string reason;
       if (!expr_type->interface_type()->implements_interface(this->type_,
 							     &reason))
 	{
-	  if (reason.empty())
-	    this->report_error(_("impossible type assertion: "
-				 "type does not implement interface"));
-	  else
+	  if (!this->type_->is_error_type())
 	    {
-	      error_at(this->location(),
-		       ("impossible type assertion: "
-			"type does not implement interface (%s)"),
-		       reason.c_str());
-	      this->set_is_error();
+	      if (reason.empty())
+		this->report_error(_("impossible type assertion: "
+				     "type does not implement interface"));
+	      else
+		error_at(this->location(),
+			 ("impossible type assertion: "
+			  "type does not implement interface (%s)"),
+			 reason.c_str());
 	    }
+	  this->set_is_error();
 	}
     }
 }
diff -r a3c80279619e go/parse.cc
--- a/go/parse.cc	Mon Dec 13 21:17:25 2010 -0800
+++ b/go/parse.cc	Mon Dec 13 21:51:50 2010 -0800
@@ -2647,12 +2647,18 @@ 
     {
       this->advance_token();
       Type* type = NULL;
-      if (is_type_switch == NULL
-	  || !this->peek_token()->is_keyword(KEYWORD_TYPE))
+      if (!this->peek_token()->is_keyword(KEYWORD_TYPE))
 	type = this->type();
       else
 	{
-	  *is_type_switch = true;
+	  if (is_type_switch != NULL)
+	    *is_type_switch = true;
+	  else
+	    {
+	      error_at(this->location(),
+		       "use of %<.(type)%> outside type switch");
+	      type = Type::make_error_type();
+	    }
 	  this->advance_token();
 	}
       if (!this->peek_token()->is_op(OPERATOR_RPAREN))
@@ -2866,7 +2872,7 @@ 
       left = this->verify_not_sink(left);
       Expression* right = this->expression(right_precedence, false,
 					   may_be_composite_lit,
-					   is_type_switch);
+					   NULL);
       if (op == OPERATOR_CHANOP)
 	left = Expression::make_send(left, right, binop_location);
       else
@@ -2959,8 +2965,7 @@ 
 	  return Expression::make_type(this->type(), location);
 	}
 
-      Expression* expr = this->unary_expr(false, may_be_composite_lit,
-					  is_type_switch);
+      Expression* expr = this->unary_expr(false, may_be_composite_lit, NULL);
       if (expr->is_error_expression())
 	;
       else if (op == OPERATOR_MULT && expr->is_type_expression())
diff -r a3c80279619e go/statements.cc
--- a/go/statements.cc	Mon Dec 13 21:17:25 2010 -0800
+++ b/go/statements.cc	Mon Dec 13 21:51:50 2010 -0800
@@ -1296,7 +1296,8 @@ 
   Type* expr_type = this->expr_->type();
   if (expr_type->interface_type() == NULL)
     {
-      this->report_error(_("type assertion only valid for interface types"));
+      if (!expr_type->is_error_type() && !this->type_->is_error_type())
+	this->report_error(_("type assertion only valid for interface types"));
       return Statement::make_error_statement(loc);
     }