diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-03-24 00:01:44 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-03-24 00:01:44 +0000 |
commit | 27a19c584743458ee775ef5e0af5d0e32a465f06 (patch) | |
tree | 4cb70d5d25eafaf22a09b592159852d8ae95b17f /gcc/go/gofrontend | |
parent | e110e232b6f7bbd3b4315161373f61623204d2b4 (diff) | |
download | gcc-27a19c584743458ee775ef5e0af5d0e32a465f06.zip gcc-27a19c584743458ee775ef5e0af5d0e32a465f06.tar.gz gcc-27a19c584743458ee775ef5e0af5d0e32a465f06.tar.bz2 |
Change c <- v from an expression to a statement.
Don't do anything special if we don't use the value of <-c.
Fix sending an untyped constant in a select statement.
From-SVN: r171371
Diffstat (limited to 'gcc/go/gofrontend')
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 97 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 74 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 8 | ||||
-rw-r--r-- | gcc/go/gofrontend/parse.cc | 53 | ||||
-rw-r--r-- | gcc/go/gofrontend/parse.h | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 97 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.h | 44 |
7 files changed, 171 insertions, 204 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 8660c75..125715b 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -12357,103 +12357,6 @@ Expression::make_receive(Expression* channel, source_location location) return new Receive_expression(channel, location); } -// Class Send_expression. - -// Traversal. - -int -Send_expression::do_traverse(Traverse* traverse) -{ - if (Expression::traverse(&this->channel_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return Expression::traverse(&this->val_, traverse); -} - -// Get the type. - -Type* -Send_expression::do_type() -{ - if (this->is_value_discarded_) - return Type::make_void_type(); - else - return Type::lookup_bool_type(); -} - -// Set types. - -void -Send_expression::do_determine_type(const Type_context*) -{ - this->channel_->determine_type_no_context(); - - Type* type = this->channel_->type(); - Type_context subcontext; - if (type->channel_type() != NULL) - subcontext.type = type->channel_type()->element_type(); - this->val_->determine_type(&subcontext); -} - -// Check types. - -void -Send_expression::do_check_types(Gogo*) -{ - Type* type = this->channel_->type(); - if (type->is_error_type()) - { - this->set_is_error(); - return; - } - Channel_type* channel_type = type->channel_type(); - if (channel_type == NULL) - { - error_at(this->location(), "left operand of %<<-%> must be channel"); - this->set_is_error(); - return; - } - Type* element_type = channel_type->element_type(); - if (element_type != NULL - && !Type::are_assignable(element_type, this->val_->type(), NULL)) - { - this->report_error(_("incompatible types in send")); - return; - } - if (!channel_type->may_send()) - { - this->report_error(_("invalid send on receive-only channel")); - return; - } -} - -// Get a tree for a send expression. - -tree -Send_expression::do_get_tree(Translate_context* context) -{ - tree channel = this->channel_->get_tree(context); - tree val = this->val_->get_tree(context); - if (channel == error_mark_node || val == error_mark_node) - return error_mark_node; - Channel_type* channel_type = this->channel_->type()->channel_type(); - val = Expression::convert_for_assignment(context, - channel_type->element_type(), - this->val_->type(), - val, - this->location()); - return Gogo::send_on_channel(channel, val, this->is_value_discarded_, - this->for_select_, this->location()); -} - -// Make a send expression - -Send_expression* -Expression::make_send(Expression* channel, Expression* val, - source_location location) -{ - return new Send_expression(channel, val, location); -} - // An expression which evaluates to a pointer to the type descriptor // of a type. diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 1dc408d..fa240a6 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -36,7 +36,6 @@ class Field_reference_expression; class Interface_field_reference_expression; class Type_guard_expression; class Receive_expression; -class Send_expression; class Named_object; class Export; class Import; @@ -89,7 +88,6 @@ class Expression EXPRESSION_COMPOSITE_LITERAL, EXPRESSION_HEAP_COMPOSITE, EXPRESSION_RECEIVE, - EXPRESSION_SEND, EXPRESSION_TYPE_DESCRIPTOR, EXPRESSION_TYPE_INFO, EXPRESSION_STRUCT_FIELD_OFFSET, @@ -271,10 +269,6 @@ class Expression static Receive_expression* make_receive(Expression* channel, source_location); - // Make a send expression. - static Send_expression* - make_send(Expression* channel, Expression* val, source_location); - // Make an expression which evaluates to the type descriptor of a // type. static Expression* @@ -356,8 +350,7 @@ class Expression // This is called by the parser if the value of this expression is // being discarded. This issues warnings about computed values - // being unused, and handles send expressions which act differently - // depending upon whether the value is used. + // being unused. void discarding_value() { this->do_discarding_value(); } @@ -1807,7 +1800,7 @@ class Receive_expression : public Expression public: Receive_expression(Expression* channel, source_location location) : Expression(EXPRESSION_RECEIVE, location), - channel_(channel), is_value_discarded_(false), for_select_(false) + channel_(channel), for_select_(false) { } // Return the channel. @@ -1827,7 +1820,7 @@ class Receive_expression : public Expression void do_discarding_value() - { this->is_value_discarded_ = true; } + { } Type* do_type(); @@ -1855,67 +1848,6 @@ class Receive_expression : public Expression private: // The channel from which we are receiving. Expression* channel_; - // Whether the value is being discarded. - bool is_value_discarded_; - // Whether this is for a select statement. - bool for_select_; -}; - -// A send expression. - -class Send_expression : public Expression -{ - public: - Send_expression(Expression* channel, Expression* val, - source_location location) - : Expression(EXPRESSION_SEND, location), - channel_(channel), val_(val), is_value_discarded_(false), - for_select_(false) - { } - - // Note that this is for a select statement. - void - set_for_select() - { this->for_select_ = true; } - - protected: - int - do_traverse(Traverse* traverse); - - void - do_discarding_value() - { this->is_value_discarded_ = true; } - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return Expression::make_send(this->channel_->copy(), this->val_->copy(), - this->location()); - } - - bool - do_must_eval_in_order() const - { return true; } - - tree - do_get_tree(Translate_context*); - - private: - // The channel on which to send the value. - Expression* channel_; - // The value to send. - Expression* val_; - // Whether the value is being discarded. - bool is_value_discarded_; // Whether this is for a select statement. bool for_select_; }; diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index f8c143c..f2476d5 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -1926,14 +1926,6 @@ Order_eval::statement(Block* block, size_t* pindex, Statement* s) { Expression** pexpr = *p; - // If the last expression is a send or receive expression, we - // may be ignoring the value; we don't want to evaluate it - // early. - if (p + 1 == find_eval_ordering.end() - && ((*pexpr)->classification() == Expression::EXPRESSION_SEND - || (*pexpr)->classification() == Expression::EXPRESSION_RECEIVE)) - break; - // The last expression in a thunk will be the call passed to go // or defer, which we must not evaluate early. if (is_thunk && p + 1 == find_eval_ordering.end()) diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index 7c03870..2e59149 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -2944,9 +2944,6 @@ Parse::expression(Precedence precedence, bool may_be_sink, case OPERATOR_ANDAND: right_precedence = PRECEDENCE_ANDAND; break; - case OPERATOR_CHANOP: - right_precedence = PRECEDENCE_CHANOP; - break; case OPERATOR_EQEQ: case OPERATOR_NOTEQ: case OPERATOR_LT: @@ -2997,10 +2994,7 @@ Parse::expression(Precedence precedence, bool may_be_sink, Expression* right = this->expression(right_precedence, false, may_be_composite_lit, NULL); - if (op == OPERATOR_CHANOP) - left = Expression::make_send(left, right, binop_location); - else - left = Expression::make_binary(op, left, right, binop_location); + left = Expression::make_binary(op, left, right, binop_location); } } @@ -3302,8 +3296,10 @@ Parse::labeled_stmt(const std::string& label_name, source_location location) this->statement(label); } -// SimpleStat = -// ExpressionStat | IncDecStat | Assignment | SimpleVarDecl . +// SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | +// Assignment | ShortVarDecl . + +// 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 @@ -3360,7 +3356,10 @@ Parse::simple_stat(bool may_be_composite_lit, bool return_exp, return NULL; } token = this->peek_token(); - if (token->is_op(OPERATOR_PLUSPLUS) || token->is_op(OPERATOR_MINUSMINUS)) + if (token->is_op(OPERATOR_CHANOP)) + this->send_stmt(this->verify_not_sink(exp)); + else if (token->is_op(OPERATOR_PLUSPLUS) + || token->is_op(OPERATOR_MINUSMINUS)) this->inc_dec_stat(this->verify_not_sink(exp)); else if (token->is_op(OPERATOR_COMMA) || token->is_op(OPERATOR_EQ)) @@ -3430,6 +3429,20 @@ Parse::expression_stat(Expression* exp) this->gogo_->add_statement(Statement::make_statement(exp)); } +// SendStmt = Channel "<-" Expression . +// Channel = Expression . + +void +Parse::send_stmt(Expression* channel) +{ + gcc_assert(this->peek_token()->is_op(OPERATOR_CHANOP)); + source_location loc = this->location(); + this->advance_token(); + Expression* val = this->expression(PRECEDENCE_NORMAL, false, true, NULL); + Statement* s = Statement::make_send_statement(channel, val, loc); + this->gogo_->add_statement(s); +} + // IncDecStat = Expression ( "++" | "--" ) . void @@ -4159,7 +4172,7 @@ Parse::select_stat(const Label* label) this->gogo_->add_statement(statement); } -// CommClause = CommCase [ StatementList ] . +// CommClause = CommCase ":" { Statement ";" } . void Parse::comm_clause(Select_clauses* clauses, bool* saw_default) @@ -4173,6 +4186,11 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default) bool got_case = this->comm_case(&is_send, &channel, &val, &varname, &is_default); + if (this->peek_token()->is_op(OPERATOR_COLON)) + this->advance_token(); + else + error_at(this->location(), "expected colon"); + Block* statements = NULL; Named_object* var = NULL; if (this->peek_token()->is_op(OPERATOR_SEMICOLON)) @@ -4214,7 +4232,7 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default) } } -// CommCase = ( "default" | ( "case" ( SendExpr | RecvExpr) ) ) ":" . +// CommCase = "case" ( SendStmt | RecvStmt ) | "default" . bool Parse::comm_case(bool* is_send, Expression** channel, Expression** val, @@ -4240,18 +4258,9 @@ Parse::comm_case(bool* is_send, Expression** channel, Expression** val, return false; } - if (!this->peek_token()->is_op(OPERATOR_COLON)) - { - error_at(this->location(), "expected colon"); - return false; - } - - this->advance_token(); - return true; } -// SendExpr = Expression "<-" Expression . // RecvExpr = [ Expression ( "=" | ":=" ) ] "<-" Expression . bool @@ -4291,7 +4300,7 @@ Parse::send_or_recv_expr(bool* is_send, Expression** channel, Expression** val, } else { - Expression* left = this->expression(PRECEDENCE_CHANOP, true, true, NULL); + Expression* left = this->expression(PRECEDENCE_NORMAL, true, true, NULL); if (this->peek_token()->is_op(OPERATOR_EQ)) { diff --git a/gcc/go/gofrontend/parse.h b/gcc/go/gofrontend/parse.h index 6f2ac64..04ae324 100644 --- a/gcc/go/gofrontend/parse.h +++ b/gcc/go/gofrontend/parse.h @@ -44,7 +44,6 @@ class Parse PRECEDENCE_NORMAL = 0, PRECEDENCE_OROR, PRECEDENCE_ANDAND, - PRECEDENCE_CHANOP, PRECEDENCE_RELOP, PRECEDENCE_ADDOP, PRECEDENCE_MULOP @@ -229,6 +228,7 @@ class Parse void statement_list(); bool statement_list_may_start_here(); void expression_stat(Expression*); + void send_stmt(Expression*); void inc_dec_stat(Expression*); void assignment(Expression*, Range_clause*); void tuple_assignment(Expression_list*, Range_clause*); diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index c443519..5a4ad06 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -3987,6 +3987,90 @@ Statement::make_type_switch_statement(Named_object* var, Expression* expr, return new Type_switch_statement(var, expr, location); } +// Class Send_statement. + +// Traversal. + +int +Send_statement::do_traverse(Traverse* traverse) +{ + if (this->traverse_expression(traverse, &this->channel_) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + return this->traverse_expression(traverse, &this->val_); +} + +// Determine types. + +void +Send_statement::do_determine_types() +{ + this->channel_->determine_type_no_context(); + Type* type = this->channel_->type(); + Type_context context; + if (type->channel_type() != NULL) + context.type = type->channel_type()->element_type(); + this->val_->determine_type(&context); +} + +// Check types. + +void +Send_statement::do_check_types(Gogo*) +{ + Type* type = this->channel_->type(); + if (type->is_error_type()) + { + this->set_is_error(); + return; + } + Channel_type* channel_type = type->channel_type(); + if (channel_type == NULL) + { + error_at(this->location(), "left operand of %<<-%> must be channel"); + this->set_is_error(); + return; + } + Type* element_type = channel_type->element_type(); + if (!Type::are_assignable(element_type, this->val_->type(), NULL)) + { + this->report_error(_("incompatible types in send")); + return; + } + if (!channel_type->may_send()) + { + this->report_error(_("invalid send on receive-only channel")); + return; + } +} + +// Get a tree for a send statement. + +tree +Send_statement::do_get_tree(Translate_context* context) +{ + tree channel = this->channel_->get_tree(context); + tree val = this->val_->get_tree(context); + if (channel == error_mark_node || val == error_mark_node) + return error_mark_node; + Channel_type* channel_type = this->channel_->type()->channel_type(); + val = Expression::convert_for_assignment(context, + channel_type->element_type(), + this->val_->type(), + val, + this->location()); + return Gogo::send_on_channel(channel, val, true, this->for_select_, + this->location()); +} + +// Make a send statement. + +Send_statement* +Statement::make_send_statement(Expression* channel, Expression* val, + source_location location) +{ + return new Send_statement(channel, val, location); +} + // Class Select_clauses::Select_clause. // Traversal. @@ -4043,7 +4127,7 @@ Select_clauses::Select_clause::lower(Block* b) // If this is a send clause, evaluate the value to send before the // select statement. Temporary_statement* val_temp = NULL; - if (this->is_send_) + if (this->is_send_ && !this->val_->is_constant()) { val_temp = Statement::make_temporary(NULL, this->val_, loc); b->add_statement(val_temp); @@ -4054,11 +4138,14 @@ Select_clauses::Select_clause::lower(Block* b) Expression* ref = Expression::make_temporary_reference(channel_temp, loc); if (this->is_send_) { - Expression* ref2 = Expression::make_temporary_reference(val_temp, loc); - Send_expression* send = Expression::make_send(ref, ref2, loc); - send->discarding_value(); + Expression* ref2; + if (val_temp == NULL) + ref2 = this->val_; + else + ref2 = Expression::make_temporary_reference(val_temp, loc); + Send_statement* send = Statement::make_send_statement(ref, ref2, loc); send->set_for_select(); - init->add_statement(Statement::make_statement(send)); + init->add_statement(send); } else { diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h index 80cdffe..83d5436 100644 --- a/gcc/go/gofrontend/statements.h +++ b/gcc/go/gofrontend/statements.h @@ -23,6 +23,7 @@ class For_statement; class For_range_statement; class Switch_statement; class Type_switch_statement; +class Send_statement; class Select_statement; class Variable; class Named_object; @@ -99,6 +100,7 @@ class Statement STATEMENT_UNNAMED_LABEL, STATEMENT_IF, STATEMENT_CONSTANT_SWITCH, + STATEMENT_SEND, STATEMENT_SELECT, // These statements types are created by the parser, but they @@ -236,6 +238,10 @@ class Statement static Type_switch_statement* make_type_switch_statement(Named_object* var, Expression*, source_location); + // Make a send statement. + static Send_statement* + make_send_statement(Expression* channel, Expression* val, source_location); + // Make a select statement. static Select_statement* make_select_statement(source_location); @@ -592,6 +598,44 @@ class Return_statement : public Statement Expression_list* vals_; }; +// A send statement. + +class Send_statement : public Statement +{ + public: + Send_statement(Expression* channel, Expression* val, + source_location location) + : Statement(STATEMENT_SEND, location), + channel_(channel), val_(val), for_select_(false) + { } + + // Note that this is for a select statement. + void + set_for_select() + { this->for_select_ = true; } + + protected: + int + do_traverse(Traverse* traverse); + + void + do_determine_types(); + + void + do_check_types(Gogo*); + + tree + do_get_tree(Translate_context*); + + private: + // The channel on which to send the value. + Expression* channel_; + // The value to send. + Expression* val_; + // Whether this is for a select statement. + bool for_select_; +}; + // Select_clauses holds the clauses of a select statement. This is // built by the parser. |