This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Go patch committed: Fix parse of (<- chan <- chan <- int)(x)
- From: Ian Lance Taylor <iant at google dot com>
- To: gcc-patches at gcc dot gnu dot org, gofrontend-dev at googlegroups dot com
- Date: Tue, 02 Oct 2012 15:22:40 -0700
- Subject: Go patch committed: Fix parse of (<- chan <- chan <- int)(x)
http://code.google.com/p/go/issues/detail?id=4110 points out that the Go
frontend is misparsing some channel operations. The parsing in this
area is rather complex for a recursive descent parser (though
straightforward for an LALR parser). In any case, this patch fixes the
problem. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Committed to mainline and 4.7 branch.
Ian
diff -r 0bdf9403f58e go/parse.cc
--- a/go/parse.cc Fri Sep 28 15:19:18 2012 -0700
+++ b/go/parse.cc Tue Oct 02 15:17:06 2012 -0700
@@ -3315,6 +3315,61 @@
bool* is_type_switch)
{
const Token* token = this->peek_token();
+
+ // There is a complex parse for <- chan. The choices are
+ // Convert x to type <- chan int:
+ // (<- chan int)(x)
+ // Receive from (x converted to type chan <- chan int):
+ // (<- chan <- chan int (x))
+ // Convert x to type <- chan (<- chan int).
+ // (<- chan <- chan int)(x)
+ if (token->is_op(OPERATOR_CHANOP))
+ {
+ Location location = token->location();
+ if (this->advance_token()->is_keyword(KEYWORD_CHAN))
+ {
+ Expression* expr = this->primary_expr(false, may_be_composite_lit,
+ NULL);
+ if (expr->is_error_expression())
+ return expr;
+ else if (!expr->is_type_expression())
+ return Expression::make_receive(expr, location);
+ else
+ {
+ if (expr->type()->is_error_type())
+ return expr;
+
+ // We picked up "chan TYPE", but it is not a type
+ // conversion.
+ Channel_type* ct = expr->type()->channel_type();
+ if (ct == NULL)
+ {
+ // This is probably impossible.
+ error_at(location, "expected channel type");
+ return Expression::make_error(location);
+ }
+ else if (ct->may_receive())
+ {
+ // <- chan TYPE.
+ Type* t = Type::make_channel_type(false, true,
+ ct->element_type());
+ return Expression::make_type(t, location);
+ }
+ else
+ {
+ // <- chan <- TYPE. Because we skipped the leading
+ // <-, we parsed this as chan <- TYPE. With the
+ // leading <-, we parse it as <- chan (<- TYPE).
+ Type *t = this->reassociate_chan_direction(ct, location);
+ return Expression::make_type(t, location);
+ }
+ }
+ }
+
+ this->unget_token(Token::make_operator_token(OPERATOR_CHANOP, location));
+ token = this->peek_token();
+ }
+
if (token->is_op(OPERATOR_PLUS)
|| token->is_op(OPERATOR_MINUS)
|| token->is_op(OPERATOR_NOT)
@@ -3327,14 +3382,6 @@
Operator op = token->op();
this->advance_token();
- if (op == OPERATOR_CHANOP
- && this->peek_token()->is_keyword(KEYWORD_CHAN))
- {
- // This is "<- chan" which must be the start of a type.
- this->unget_token(Token::make_operator_token(op, location));
- return Expression::make_type(this->type(), location);
- }
-
Expression* expr = this->unary_expr(false, may_be_composite_lit, NULL);
if (expr->is_error_expression())
;
@@ -3354,6 +3401,32 @@
is_type_switch);
}
+// This is called for the obscure case of
+// (<- chan <- chan int)(x)
+// In unary_expr we remove the leading <- and parse the remainder,
+// which gives us
+// chan <- (chan int)
+// When we add the leading <- back in, we really want
+// <- chan (<- chan int)
+// This means that we need to reassociate.
+
+Type*
+Parse::reassociate_chan_direction(Channel_type *ct, Location location)
+{
+ Channel_type* ele = ct->element_type()->channel_type();
+ if (ele == NULL)
+ {
+ error_at(location, "parse error");
+ return Type::make_error_type();
+ }
+ Type* sub = ele;
+ if (ele->may_send())
+ sub = Type::make_channel_type(false, true, ele->element_type());
+ else
+ sub = this->reassociate_chan_direction(ele, location);
+ return Type::make_channel_type(false, true, sub);
+}
+
// Statement =
// Declaration | LabeledStmt | SimpleStmt |
// GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
diff -r 0bdf9403f58e go/parse.h
--- a/go/parse.h Fri Sep 28 15:19:18 2012 -0700
+++ b/go/parse.h Tue Oct 02 15:17:06 2012 -0700
@@ -14,6 +14,7 @@
class Type;
class Typed_identifier;
class Typed_identifier_list;
+class Channel_type;
class Function_type;
class Block;
class Expression;
@@ -229,6 +230,7 @@
bool expression_may_start_here();
Expression* unary_expr(bool may_be_sink, bool may_be_composite_lit,
bool* is_type_switch);
+ Type* reassociate_chan_direction(Channel_type*, Location);
Expression* qualified_expr(Expression*, Location);
Expression* id_to_expression(const std::string&, Location);
void statement(Label*);