summaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2012-10-02 22:22:28 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2012-10-02 22:22:28 +0000
commit2cb4d0d5ce42215ec18456ce446dd88c57e0546a (patch)
treeb3483b5c8da16d6e9e82cbe8d4f7e81eeed60319 /gcc/go
parent81c99a703bd5ed894d0c6730e041201a41d167fd (diff)
downloadgcc-2cb4d0d5ce42215ec18456ce446dd88c57e0546a.tar.gz
compiler: Fix parse of (<- chan <- chan <- int)(x).
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@192011 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/go')
-rw-r--r--gcc/go/gofrontend/parse.cc89
-rw-r--r--gcc/go/gofrontend/parse.h2
2 files changed, 83 insertions, 8 deletions
diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc
index f6b9715d4c1..1ec283dca56 100644
--- a/gcc/go/gofrontend/parse.cc
+++ b/gcc/go/gofrontend/parse.cc
@@ -3315,6 +3315,61 @@ Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit,
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 @@ Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit,
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 @@ Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit,
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 --git a/gcc/go/gofrontend/parse.h b/gcc/go/gofrontend/parse.h
index 3139f7e8908..fb5c1f16411 100644
--- a/gcc/go/gofrontend/parse.h
+++ b/gcc/go/gofrontend/parse.h
@@ -14,6 +14,7 @@ class Named_object;
class Type;
class Typed_identifier;
class Typed_identifier_list;
+class Channel_type;
class Function_type;
class Block;
class Expression;
@@ -229,6 +230,7 @@ class Parse
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*);