From e395eacb4e15d30cf9862b6e73dd05c2dab58364 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 2 Oct 2012 22:22:28 +0000 Subject: [PATCH] compiler: Fix parse of (<- chan <- chan <- int)(x). From-SVN: r192011 --- gcc/go/gofrontend/parse.cc | 89 ++++++++++++++++++++++++++++++++++---- gcc/go/gofrontend/parse.h | 2 + 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*); -- 2.30.2