compiler: More cases that need a temporary for interface conversion.
[official-gcc.git] / gcc / go / gofrontend / statements.cc
blob5da04710e39f8102b6b04a58d6008d293c1628ed
1 // statements.cc -- Go frontend statements.
3 // Copyright 2009 The Go Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file.
7 #include "go-system.h"
9 #include "go-c.h"
10 #include "types.h"
11 #include "expressions.h"
12 #include "gogo.h"
13 #include "runtime.h"
14 #include "backend.h"
15 #include "statements.h"
16 #include "ast-dump.h"
18 // Class Statement.
20 Statement::Statement(Statement_classification classification,
21 Location location)
22 : classification_(classification), location_(location)
26 Statement::~Statement()
30 // Traverse the tree. The work of walking the components is handled
31 // by the subclasses.
33 int
34 Statement::traverse(Block* block, size_t* pindex, Traverse* traverse)
36 if (this->classification_ == STATEMENT_ERROR)
37 return TRAVERSE_CONTINUE;
39 unsigned int traverse_mask = traverse->traverse_mask();
41 if ((traverse_mask & Traverse::traverse_statements) != 0)
43 int t = traverse->statement(block, pindex, this);
44 if (t == TRAVERSE_EXIT)
45 return TRAVERSE_EXIT;
46 else if (t == TRAVERSE_SKIP_COMPONENTS)
47 return TRAVERSE_CONTINUE;
50 // No point in checking traverse_mask here--a statement may contain
51 // other blocks or statements, and if we got here we always want to
52 // walk them.
53 return this->do_traverse(traverse);
56 // Traverse the contents of a statement.
58 int
59 Statement::traverse_contents(Traverse* traverse)
61 return this->do_traverse(traverse);
64 // Traverse assignments.
66 bool
67 Statement::traverse_assignments(Traverse_assignments* tassign)
69 if (this->classification_ == STATEMENT_ERROR)
70 return false;
71 return this->do_traverse_assignments(tassign);
74 // Traverse an expression in a statement. This is a helper function
75 // for child classes.
77 int
78 Statement::traverse_expression(Traverse* traverse, Expression** expr)
80 if ((traverse->traverse_mask()
81 & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0)
82 return TRAVERSE_CONTINUE;
83 return Expression::traverse(expr, traverse);
86 // Traverse an expression list in a statement. This is a helper
87 // function for child classes.
89 int
90 Statement::traverse_expression_list(Traverse* traverse,
91 Expression_list* expr_list)
93 if (expr_list == NULL)
94 return TRAVERSE_CONTINUE;
95 if ((traverse->traverse_mask()
96 & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0)
97 return TRAVERSE_CONTINUE;
98 return expr_list->traverse(traverse);
101 // Traverse a type in a statement. This is a helper function for
102 // child classes.
105 Statement::traverse_type(Traverse* traverse, Type* type)
107 if ((traverse->traverse_mask()
108 & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0)
109 return TRAVERSE_CONTINUE;
110 return Type::traverse(type, traverse);
113 // Set type information for unnamed constants. This is really done by
114 // the child class.
116 void
117 Statement::determine_types()
119 this->do_determine_types();
122 // If this is a thunk statement, return it.
124 Thunk_statement*
125 Statement::thunk_statement()
127 Thunk_statement* ret = this->convert<Thunk_statement, STATEMENT_GO>();
128 if (ret == NULL)
129 ret = this->convert<Thunk_statement, STATEMENT_DEFER>();
130 return ret;
133 // Convert a Statement to the backend representation. This is really
134 // done by the child class.
136 Bstatement*
137 Statement::get_backend(Translate_context* context)
139 if (this->classification_ == STATEMENT_ERROR)
140 return context->backend()->error_statement();
141 return this->do_get_backend(context);
144 // Dump AST representation for a statement to a dump context.
146 void
147 Statement::dump_statement(Ast_dump_context* ast_dump_context) const
149 this->do_dump_statement(ast_dump_context);
152 // Note that this statement is erroneous. This is called by children
153 // when they discover an error.
155 void
156 Statement::set_is_error()
158 this->classification_ = STATEMENT_ERROR;
161 // For children to call to report an error conveniently.
163 void
164 Statement::report_error(const char* msg)
166 error_at(this->location_, "%s", msg);
167 this->set_is_error();
170 // An error statement, used to avoid crashing after we report an
171 // error.
173 class Error_statement : public Statement
175 public:
176 Error_statement(Location location)
177 : Statement(STATEMENT_ERROR, location)
180 protected:
182 do_traverse(Traverse*)
183 { return TRAVERSE_CONTINUE; }
185 Bstatement*
186 do_get_backend(Translate_context*)
187 { go_unreachable(); }
189 void
190 do_dump_statement(Ast_dump_context*) const;
193 // Dump the AST representation for an error statement.
195 void
196 Error_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
198 ast_dump_context->print_indent();
199 ast_dump_context->ostream() << "Error statement" << std::endl;
202 // Make an error statement.
204 Statement*
205 Statement::make_error_statement(Location location)
207 return new Error_statement(location);
210 // Class Variable_declaration_statement.
212 Variable_declaration_statement::Variable_declaration_statement(
213 Named_object* var)
214 : Statement(STATEMENT_VARIABLE_DECLARATION, var->var_value()->location()),
215 var_(var)
219 // We don't actually traverse the variable here; it was traversed
220 // while traversing the Block.
223 Variable_declaration_statement::do_traverse(Traverse*)
225 return TRAVERSE_CONTINUE;
228 // Traverse the assignments in a variable declaration. Note that this
229 // traversal is different from the usual traversal.
231 bool
232 Variable_declaration_statement::do_traverse_assignments(
233 Traverse_assignments* tassign)
235 tassign->initialize_variable(this->var_);
236 return true;
239 // Lower the variable's initialization expression.
241 Statement*
242 Variable_declaration_statement::do_lower(Gogo* gogo, Named_object* function,
243 Block*, Statement_inserter* inserter)
245 this->var_->var_value()->lower_init_expression(gogo, function, inserter);
246 return this;
249 // Flatten the variable's initialization expression.
251 Statement*
252 Variable_declaration_statement::do_flatten(Gogo* gogo, Named_object* function,
253 Block*, Statement_inserter* inserter)
255 this->var_->var_value()->flatten_init_expression(gogo, function, inserter);
256 return this;
259 // Convert a variable declaration to the backend representation.
261 Bstatement*
262 Variable_declaration_statement::do_get_backend(Translate_context* context)
264 Variable* var = this->var_->var_value();
265 Bvariable* bvar = this->var_->get_backend_variable(context->gogo(),
266 context->function());
267 Bexpression* binit = var->get_init(context->gogo(), context->function());
269 if (!var->is_in_heap())
271 go_assert(binit != NULL);
272 return context->backend()->init_statement(bvar, binit);
275 // Something takes the address of this variable, so the value is
276 // stored in the heap. Initialize it to newly allocated memory
277 // space, and assign the initial value to the new space.
278 Location loc = this->location();
279 Named_object* newfn = context->gogo()->lookup_global("new");
280 go_assert(newfn != NULL && newfn->is_function_declaration());
281 Expression* func = Expression::make_func_reference(newfn, NULL, loc);
282 Expression_list* params = new Expression_list();
283 params->push_back(Expression::make_type(var->type(), loc));
284 Expression* call = Expression::make_call(func, params, false, loc);
285 context->gogo()->lower_expression(context->function(), NULL, &call);
286 Temporary_statement* temp = Statement::make_temporary(NULL, call, loc);
287 Bstatement* btemp = temp->get_backend(context);
289 Bstatement* set = NULL;
290 if (binit != NULL)
292 Expression* e = Expression::make_temporary_reference(temp, loc);
293 e = Expression::make_unary(OPERATOR_MULT, e, loc);
294 Bexpression* be = e->get_backend(context);
295 set = context->backend()->assignment_statement(be, binit, loc);
298 Expression* ref = Expression::make_temporary_reference(temp, loc);
299 Bexpression* bref = ref->get_backend(context);
300 Bstatement* sinit = context->backend()->init_statement(bvar, bref);
302 std::vector<Bstatement*> stats;
303 stats.reserve(3);
304 stats.push_back(btemp);
305 if (set != NULL)
306 stats.push_back(set);
307 stats.push_back(sinit);
308 return context->backend()->statement_list(stats);
311 // Dump the AST representation for a variable declaration.
313 void
314 Variable_declaration_statement::do_dump_statement(
315 Ast_dump_context* ast_dump_context) const
317 ast_dump_context->print_indent();
319 go_assert(var_->is_variable());
320 ast_dump_context->ostream() << "var " << this->var_->name() << " ";
321 Variable* var = this->var_->var_value();
322 if (var->has_type())
324 ast_dump_context->dump_type(var->type());
325 ast_dump_context->ostream() << " ";
327 if (var->init() != NULL)
329 ast_dump_context->ostream() << "= ";
330 ast_dump_context->dump_expression(var->init());
332 ast_dump_context->ostream() << std::endl;
335 // Make a variable declaration.
337 Statement*
338 Statement::make_variable_declaration(Named_object* var)
340 return new Variable_declaration_statement(var);
343 // Class Temporary_statement.
345 // Return the type of the temporary variable.
347 Type*
348 Temporary_statement::type() const
350 return this->type_ != NULL ? this->type_ : this->init_->type();
353 // Traversal.
356 Temporary_statement::do_traverse(Traverse* traverse)
358 if (this->type_ != NULL
359 && this->traverse_type(traverse, this->type_) == TRAVERSE_EXIT)
360 return TRAVERSE_EXIT;
361 if (this->init_ == NULL)
362 return TRAVERSE_CONTINUE;
363 else
364 return this->traverse_expression(traverse, &this->init_);
367 // Traverse assignments.
369 bool
370 Temporary_statement::do_traverse_assignments(Traverse_assignments* tassign)
372 if (this->init_ == NULL)
373 return false;
374 tassign->value(&this->init_, true, true);
375 return true;
378 // Determine types.
380 void
381 Temporary_statement::do_determine_types()
383 if (this->type_ != NULL && this->type_->is_abstract())
384 this->type_ = this->type_->make_non_abstract_type();
386 if (this->init_ != NULL)
388 if (this->type_ == NULL)
389 this->init_->determine_type_no_context();
390 else
392 Type_context context(this->type_, false);
393 this->init_->determine_type(&context);
397 if (this->type_ == NULL)
399 this->type_ = this->init_->type();
400 go_assert(!this->type_->is_abstract());
404 // Check types.
406 void
407 Temporary_statement::do_check_types(Gogo*)
409 if (this->type_ != NULL && this->init_ != NULL)
411 std::string reason;
412 if (!Type::are_assignable(this->type_, this->init_->type(), &reason))
414 if (reason.empty())
415 error_at(this->location(), "incompatible types in assignment");
416 else
417 error_at(this->location(), "incompatible types in assignment (%s)",
418 reason.c_str());
419 this->set_is_error();
424 // Flatten a temporary statement: add another temporary when it might
425 // be needed for interface conversion.
427 Statement*
428 Temporary_statement::do_flatten(Gogo*, Named_object*, Block*,
429 Statement_inserter* inserter)
431 if (this->type_ != NULL
432 && this->init_ != NULL
433 && !Type::are_identical(this->type_, this->init_->type(), false, NULL)
434 && this->init_->type()->interface_type() != NULL
435 && !this->init_->is_variable())
437 Temporary_statement *temp =
438 Statement::make_temporary(NULL, this->init_, this->location());
439 inserter->insert(temp);
440 this->init_ = Expression::make_temporary_reference(temp,
441 this->location());
443 return this;
446 // Convert to backend representation.
448 Bstatement*
449 Temporary_statement::do_get_backend(Translate_context* context)
451 go_assert(this->bvariable_ == NULL);
453 Named_object* function = context->function();
454 go_assert(function != NULL);
455 Bfunction* bfunction = function->func_value()->get_decl();
456 Btype* btype = this->type()->get_backend(context->gogo());
458 Bexpression* binit;
459 if (this->init_ == NULL)
460 binit = NULL;
461 else if (this->type_ == NULL)
462 binit = this->init_->get_backend(context);
463 else
465 Expression* init = Expression::convert_for_assignment(context->gogo(),
466 this->type_,
467 this->init_,
468 this->location());
469 binit = init->get_backend(context);
472 Bstatement* statement;
473 this->bvariable_ =
474 context->backend()->temporary_variable(bfunction, context->bblock(),
475 btype, binit,
476 this->is_address_taken_,
477 this->location(), &statement);
478 return statement;
481 // Return the backend variable.
483 Bvariable*
484 Temporary_statement::get_backend_variable(Translate_context* context) const
486 if (this->bvariable_ == NULL)
488 go_assert(saw_errors());
489 return context->backend()->error_variable();
491 return this->bvariable_;
494 // Dump the AST represemtation for a temporary statement
496 void
497 Temporary_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
499 ast_dump_context->print_indent();
500 ast_dump_context->dump_temp_variable_name(this);
501 if (this->type_ != NULL)
503 ast_dump_context->ostream() << " ";
504 ast_dump_context->dump_type(this->type_);
506 if (this->init_ != NULL)
508 ast_dump_context->ostream() << " = ";
509 ast_dump_context->dump_expression(this->init_);
511 ast_dump_context->ostream() << std::endl;
514 // Make and initialize a temporary variable in BLOCK.
516 Temporary_statement*
517 Statement::make_temporary(Type* type, Expression* init,
518 Location location)
520 return new Temporary_statement(type, init, location);
523 // An assignment statement.
525 class Assignment_statement : public Statement
527 public:
528 Assignment_statement(Expression* lhs, Expression* rhs,
529 Location location)
530 : Statement(STATEMENT_ASSIGNMENT, location),
531 lhs_(lhs), rhs_(rhs)
534 protected:
536 do_traverse(Traverse* traverse);
538 bool
539 do_traverse_assignments(Traverse_assignments*);
541 void
542 do_determine_types();
544 void
545 do_check_types(Gogo*);
547 Statement*
548 do_flatten(Gogo*, Named_object*, Block*, Statement_inserter*);
550 Bstatement*
551 do_get_backend(Translate_context*);
553 void
554 do_dump_statement(Ast_dump_context*) const;
556 private:
557 // Left hand side--the lvalue.
558 Expression* lhs_;
559 // Right hand side--the rvalue.
560 Expression* rhs_;
563 // Traversal.
566 Assignment_statement::do_traverse(Traverse* traverse)
568 if (this->traverse_expression(traverse, &this->lhs_) == TRAVERSE_EXIT)
569 return TRAVERSE_EXIT;
570 return this->traverse_expression(traverse, &this->rhs_);
573 bool
574 Assignment_statement::do_traverse_assignments(Traverse_assignments* tassign)
576 tassign->assignment(&this->lhs_, &this->rhs_);
577 return true;
580 // Set types for the assignment.
582 void
583 Assignment_statement::do_determine_types()
585 this->lhs_->determine_type_no_context();
586 Type* rhs_context_type = this->lhs_->type();
587 if (rhs_context_type->is_sink_type())
588 rhs_context_type = NULL;
589 Type_context context(rhs_context_type, false);
590 this->rhs_->determine_type(&context);
593 // Check types for an assignment.
595 void
596 Assignment_statement::do_check_types(Gogo*)
598 // The left hand side must be either addressable, a map index
599 // expression, or the blank identifier.
600 if (!this->lhs_->is_addressable()
601 && this->lhs_->map_index_expression() == NULL
602 && !this->lhs_->is_sink_expression())
604 if (!this->lhs_->type()->is_error())
605 this->report_error(_("invalid left hand side of assignment"));
606 return;
609 Type* lhs_type = this->lhs_->type();
610 Type* rhs_type = this->rhs_->type();
612 // Invalid assignment of nil to the blank identifier.
613 if (lhs_type->is_sink_type()
614 && rhs_type->is_nil_type())
616 this->report_error(_("use of untyped nil"));
617 return;
620 std::string reason;
621 if (!Type::are_assignable(lhs_type, rhs_type, &reason))
623 if (reason.empty())
624 error_at(this->location(), "incompatible types in assignment");
625 else
626 error_at(this->location(), "incompatible types in assignment (%s)",
627 reason.c_str());
628 this->set_is_error();
631 if (lhs_type->is_error() || rhs_type->is_error())
632 this->set_is_error();
635 // Flatten an assignment statement. We may need a temporary for
636 // interface conversion.
638 Statement*
639 Assignment_statement::do_flatten(Gogo*, Named_object*, Block*,
640 Statement_inserter* inserter)
642 if (!this->lhs_->is_sink_expression()
643 && !Type::are_identical(this->lhs_->type(), this->rhs_->type(),
644 false, NULL)
645 && this->rhs_->type()->interface_type() != NULL
646 && !this->rhs_->is_variable())
648 Temporary_statement* temp =
649 Statement::make_temporary(NULL, this->rhs_, this->location());
650 inserter->insert(temp);
651 this->rhs_ = Expression::make_temporary_reference(temp,
652 this->location());
654 return this;
657 // Convert an assignment statement to the backend representation.
659 Bstatement*
660 Assignment_statement::do_get_backend(Translate_context* context)
662 if (this->lhs_->is_sink_expression())
664 Bexpression* rhs = this->rhs_->get_backend(context);
665 return context->backend()->expression_statement(rhs);
668 Bexpression* lhs = this->lhs_->get_backend(context);
669 Expression* conv =
670 Expression::convert_for_assignment(context->gogo(), this->lhs_->type(),
671 this->rhs_, this->location());
672 Bexpression* rhs = conv->get_backend(context);
673 return context->backend()->assignment_statement(lhs, rhs, this->location());
676 // Dump the AST representation for an assignment statement.
678 void
679 Assignment_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
680 const
682 ast_dump_context->print_indent();
683 ast_dump_context->dump_expression(this->lhs_);
684 ast_dump_context->ostream() << " = " ;
685 ast_dump_context->dump_expression(this->rhs_);
686 ast_dump_context->ostream() << std::endl;
689 // Make an assignment statement.
691 Statement*
692 Statement::make_assignment(Expression* lhs, Expression* rhs,
693 Location location)
695 return new Assignment_statement(lhs, rhs, location);
698 // The Move_subexpressions class is used to move all top-level
699 // subexpressions of an expression. This is used for things like
700 // index expressions in which we must evaluate the index value before
701 // it can be changed by a multiple assignment.
703 class Move_subexpressions : public Traverse
705 public:
706 Move_subexpressions(int skip, Block* block)
707 : Traverse(traverse_expressions),
708 skip_(skip), block_(block)
711 protected:
713 expression(Expression**);
715 private:
716 // The number of subexpressions to skip moving. This is used to
717 // avoid moving the array itself, as we only need to move the index.
718 int skip_;
719 // The block where new temporary variables should be added.
720 Block* block_;
724 Move_subexpressions::expression(Expression** pexpr)
726 if (this->skip_ > 0)
727 --this->skip_;
728 else if ((*pexpr)->temporary_reference_expression() == NULL
729 && !(*pexpr)->is_nil_expression())
731 Location loc = (*pexpr)->location();
732 Temporary_statement* temp = Statement::make_temporary(NULL, *pexpr, loc);
733 this->block_->add_statement(temp);
734 *pexpr = Expression::make_temporary_reference(temp, loc);
736 // We only need to move top-level subexpressions.
737 return TRAVERSE_SKIP_COMPONENTS;
740 // The Move_ordered_evals class is used to find any subexpressions of
741 // an expression that have an evaluation order dependency. It creates
742 // temporary variables to hold them.
744 class Move_ordered_evals : public Traverse
746 public:
747 Move_ordered_evals(Block* block)
748 : Traverse(traverse_expressions),
749 block_(block)
752 protected:
754 expression(Expression**);
756 private:
757 // The block where new temporary variables should be added.
758 Block* block_;
762 Move_ordered_evals::expression(Expression** pexpr)
764 // We have to look at subexpressions first.
765 if ((*pexpr)->traverse_subexpressions(this) == TRAVERSE_EXIT)
766 return TRAVERSE_EXIT;
768 int i;
769 if ((*pexpr)->must_eval_subexpressions_in_order(&i))
771 Move_subexpressions ms(i, this->block_);
772 if ((*pexpr)->traverse_subexpressions(&ms) == TRAVERSE_EXIT)
773 return TRAVERSE_EXIT;
776 if ((*pexpr)->must_eval_in_order())
778 Call_expression* call = (*pexpr)->call_expression();
779 if (call != NULL && call->is_multi_value_arg())
781 // A call expression which returns multiple results as an argument
782 // to another call must be handled specially. We can't create a
783 // temporary because there is no type to give it. Instead, group
784 // the caller and this multi-valued call argument and use a temporary
785 // variable to hold them.
786 return TRAVERSE_SKIP_COMPONENTS;
789 Location loc = (*pexpr)->location();
790 Temporary_statement* temp = Statement::make_temporary(NULL, *pexpr, loc);
791 this->block_->add_statement(temp);
792 *pexpr = Expression::make_temporary_reference(temp, loc);
794 return TRAVERSE_SKIP_COMPONENTS;
797 // An assignment operation statement.
799 class Assignment_operation_statement : public Statement
801 public:
802 Assignment_operation_statement(Operator op, Expression* lhs, Expression* rhs,
803 Location location)
804 : Statement(STATEMENT_ASSIGNMENT_OPERATION, location),
805 op_(op), lhs_(lhs), rhs_(rhs)
808 protected:
810 do_traverse(Traverse*);
812 bool
813 do_traverse_assignments(Traverse_assignments*)
814 { go_unreachable(); }
816 Statement*
817 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
819 Bstatement*
820 do_get_backend(Translate_context*)
821 { go_unreachable(); }
823 void
824 do_dump_statement(Ast_dump_context*) const;
826 private:
827 // The operator (OPERATOR_PLUSEQ, etc.).
828 Operator op_;
829 // Left hand side.
830 Expression* lhs_;
831 // Right hand side.
832 Expression* rhs_;
835 // Traversal.
838 Assignment_operation_statement::do_traverse(Traverse* traverse)
840 if (this->traverse_expression(traverse, &this->lhs_) == TRAVERSE_EXIT)
841 return TRAVERSE_EXIT;
842 return this->traverse_expression(traverse, &this->rhs_);
845 // Lower an assignment operation statement to a regular assignment
846 // statement.
848 Statement*
849 Assignment_operation_statement::do_lower(Gogo*, Named_object*,
850 Block* enclosing, Statement_inserter*)
852 Location loc = this->location();
854 // We have to evaluate the left hand side expression only once. We
855 // do this by moving out any expression with side effects.
856 Block* b = new Block(enclosing, loc);
857 Move_ordered_evals moe(b);
858 this->lhs_->traverse_subexpressions(&moe);
860 Expression* lval = this->lhs_->copy();
862 Operator op;
863 switch (this->op_)
865 case OPERATOR_PLUSEQ:
866 op = OPERATOR_PLUS;
867 break;
868 case OPERATOR_MINUSEQ:
869 op = OPERATOR_MINUS;
870 break;
871 case OPERATOR_OREQ:
872 op = OPERATOR_OR;
873 break;
874 case OPERATOR_XOREQ:
875 op = OPERATOR_XOR;
876 break;
877 case OPERATOR_MULTEQ:
878 op = OPERATOR_MULT;
879 break;
880 case OPERATOR_DIVEQ:
881 op = OPERATOR_DIV;
882 break;
883 case OPERATOR_MODEQ:
884 op = OPERATOR_MOD;
885 break;
886 case OPERATOR_LSHIFTEQ:
887 op = OPERATOR_LSHIFT;
888 break;
889 case OPERATOR_RSHIFTEQ:
890 op = OPERATOR_RSHIFT;
891 break;
892 case OPERATOR_ANDEQ:
893 op = OPERATOR_AND;
894 break;
895 case OPERATOR_BITCLEAREQ:
896 op = OPERATOR_BITCLEAR;
897 break;
898 default:
899 go_unreachable();
902 Expression* binop = Expression::make_binary(op, lval, this->rhs_, loc);
903 Statement* s = Statement::make_assignment(this->lhs_, binop, loc);
904 if (b->statements()->empty())
906 delete b;
907 return s;
909 else
911 b->add_statement(s);
912 return Statement::make_block_statement(b, loc);
916 // Dump the AST representation for an assignment operation statement
918 void
919 Assignment_operation_statement::do_dump_statement(
920 Ast_dump_context* ast_dump_context) const
922 ast_dump_context->print_indent();
923 ast_dump_context->dump_expression(this->lhs_);
924 ast_dump_context->dump_operator(this->op_);
925 ast_dump_context->dump_expression(this->rhs_);
926 ast_dump_context->ostream() << std::endl;
929 // Make an assignment operation statement.
931 Statement*
932 Statement::make_assignment_operation(Operator op, Expression* lhs,
933 Expression* rhs, Location location)
935 return new Assignment_operation_statement(op, lhs, rhs, location);
938 // A tuple assignment statement. This differs from an assignment
939 // statement in that the right-hand-side expressions are evaluated in
940 // parallel.
942 class Tuple_assignment_statement : public Statement
944 public:
945 Tuple_assignment_statement(Expression_list* lhs, Expression_list* rhs,
946 Location location)
947 : Statement(STATEMENT_TUPLE_ASSIGNMENT, location),
948 lhs_(lhs), rhs_(rhs)
951 protected:
953 do_traverse(Traverse* traverse);
955 bool
956 do_traverse_assignments(Traverse_assignments*)
957 { go_unreachable(); }
959 Statement*
960 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
962 Bstatement*
963 do_get_backend(Translate_context*)
964 { go_unreachable(); }
966 void
967 do_dump_statement(Ast_dump_context*) const;
969 private:
970 // Left hand side--a list of lvalues.
971 Expression_list* lhs_;
972 // Right hand side--a list of rvalues.
973 Expression_list* rhs_;
976 // Traversal.
979 Tuple_assignment_statement::do_traverse(Traverse* traverse)
981 if (this->traverse_expression_list(traverse, this->lhs_) == TRAVERSE_EXIT)
982 return TRAVERSE_EXIT;
983 return this->traverse_expression_list(traverse, this->rhs_);
986 // Lower a tuple assignment. We use temporary variables to split it
987 // up into a set of single assignments.
989 Statement*
990 Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
991 Statement_inserter*)
993 Location loc = this->location();
995 Block* b = new Block(enclosing, loc);
997 // First move out any subexpressions on the left hand side. The
998 // right hand side will be evaluated in the required order anyhow.
999 Move_ordered_evals moe(b);
1000 for (Expression_list::iterator plhs = this->lhs_->begin();
1001 plhs != this->lhs_->end();
1002 ++plhs)
1003 Expression::traverse(&*plhs, &moe);
1005 std::vector<Temporary_statement*> temps;
1006 temps.reserve(this->lhs_->size());
1008 Expression_list::const_iterator prhs = this->rhs_->begin();
1009 for (Expression_list::const_iterator plhs = this->lhs_->begin();
1010 plhs != this->lhs_->end();
1011 ++plhs, ++prhs)
1013 go_assert(prhs != this->rhs_->end());
1015 if ((*plhs)->is_error_expression()
1016 || (*plhs)->type()->is_error()
1017 || (*prhs)->is_error_expression()
1018 || (*prhs)->type()->is_error())
1019 continue;
1021 if ((*plhs)->is_sink_expression())
1023 if ((*prhs)->type()->is_nil_type())
1024 this->report_error(_("use of untyped nil"));
1025 else
1026 b->add_statement(Statement::make_statement(*prhs, true));
1027 continue;
1030 Temporary_statement* temp = Statement::make_temporary((*plhs)->type(),
1031 *prhs, loc);
1032 b->add_statement(temp);
1033 temps.push_back(temp);
1036 go_assert(prhs == this->rhs_->end());
1038 prhs = this->rhs_->begin();
1039 std::vector<Temporary_statement*>::const_iterator ptemp = temps.begin();
1040 for (Expression_list::const_iterator plhs = this->lhs_->begin();
1041 plhs != this->lhs_->end();
1042 ++plhs, ++prhs)
1044 if ((*plhs)->is_error_expression()
1045 || (*plhs)->type()->is_error()
1046 || (*prhs)->is_error_expression()
1047 || (*prhs)->type()->is_error())
1048 continue;
1050 if ((*plhs)->is_sink_expression())
1051 continue;
1053 Expression* ref = Expression::make_temporary_reference(*ptemp, loc);
1054 b->add_statement(Statement::make_assignment(*plhs, ref, loc));
1055 ++ptemp;
1057 go_assert(ptemp == temps.end() || saw_errors());
1059 return Statement::make_block_statement(b, loc);
1062 // Dump the AST representation for a tuple assignment statement.
1064 void
1065 Tuple_assignment_statement::do_dump_statement(
1066 Ast_dump_context* ast_dump_context) const
1068 ast_dump_context->print_indent();
1069 ast_dump_context->dump_expression_list(this->lhs_);
1070 ast_dump_context->ostream() << " = ";
1071 ast_dump_context->dump_expression_list(this->rhs_);
1072 ast_dump_context->ostream() << std::endl;
1075 // Make a tuple assignment statement.
1077 Statement*
1078 Statement::make_tuple_assignment(Expression_list* lhs, Expression_list* rhs,
1079 Location location)
1081 return new Tuple_assignment_statement(lhs, rhs, location);
1084 // A tuple assignment from a map index expression.
1085 // v, ok = m[k]
1087 class Tuple_map_assignment_statement : public Statement
1089 public:
1090 Tuple_map_assignment_statement(Expression* val, Expression* present,
1091 Expression* map_index,
1092 Location location)
1093 : Statement(STATEMENT_TUPLE_MAP_ASSIGNMENT, location),
1094 val_(val), present_(present), map_index_(map_index)
1097 protected:
1099 do_traverse(Traverse* traverse);
1101 bool
1102 do_traverse_assignments(Traverse_assignments*)
1103 { go_unreachable(); }
1105 Statement*
1106 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1108 Bstatement*
1109 do_get_backend(Translate_context*)
1110 { go_unreachable(); }
1112 void
1113 do_dump_statement(Ast_dump_context*) const;
1115 private:
1116 // Lvalue which receives the value from the map.
1117 Expression* val_;
1118 // Lvalue which receives whether the key value was present.
1119 Expression* present_;
1120 // The map index expression.
1121 Expression* map_index_;
1124 // Traversal.
1127 Tuple_map_assignment_statement::do_traverse(Traverse* traverse)
1129 if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
1130 || this->traverse_expression(traverse, &this->present_) == TRAVERSE_EXIT)
1131 return TRAVERSE_EXIT;
1132 return this->traverse_expression(traverse, &this->map_index_);
1135 // Lower a tuple map assignment.
1137 Statement*
1138 Tuple_map_assignment_statement::do_lower(Gogo*, Named_object*,
1139 Block* enclosing, Statement_inserter*)
1141 Location loc = this->location();
1143 Map_index_expression* map_index = this->map_index_->map_index_expression();
1144 if (map_index == NULL)
1146 this->report_error(_("expected map index on right hand side"));
1147 return Statement::make_error_statement(loc);
1149 Map_type* map_type = map_index->get_map_type();
1150 if (map_type == NULL)
1151 return Statement::make_error_statement(loc);
1153 Block* b = new Block(enclosing, loc);
1155 // Move out any subexpressions to make sure that functions are
1156 // called in the required order.
1157 Move_ordered_evals moe(b);
1158 this->val_->traverse_subexpressions(&moe);
1159 this->present_->traverse_subexpressions(&moe);
1161 // Copy the key value into a temporary so that we can take its
1162 // address without pushing the value onto the heap.
1164 // var key_temp KEY_TYPE = MAP_INDEX
1165 Temporary_statement* key_temp =
1166 Statement::make_temporary(map_type->key_type(), map_index->index(), loc);
1167 b->add_statement(key_temp);
1169 // var val_temp VAL_TYPE
1170 Temporary_statement* val_temp =
1171 Statement::make_temporary(map_type->val_type(), NULL, loc);
1172 b->add_statement(val_temp);
1174 // var present_temp bool
1175 Temporary_statement* present_temp =
1176 Statement::make_temporary((this->present_->type()->is_sink_type())
1177 ? Type::make_boolean_type()
1178 : this->present_->type(),
1179 NULL, loc);
1180 b->add_statement(present_temp);
1182 // present_temp = mapaccess2(DESCRIPTOR, MAP, &key_temp, &val_temp)
1183 Expression* a1 = Expression::make_type_descriptor(map_type, loc);
1184 Expression* a2 = map_index->map();
1185 Temporary_reference_expression* ref =
1186 Expression::make_temporary_reference(key_temp, loc);
1187 Expression* a3 = Expression::make_unary(OPERATOR_AND, ref, loc);
1188 ref = Expression::make_temporary_reference(val_temp, loc);
1189 Expression* a4 = Expression::make_unary(OPERATOR_AND, ref, loc);
1190 Expression* call = Runtime::make_call(Runtime::MAPACCESS2, loc, 4,
1191 a1, a2, a3, a4);
1192 ref = Expression::make_temporary_reference(present_temp, loc);
1193 ref->set_is_lvalue();
1194 Statement* s = Statement::make_assignment(ref, call, loc);
1195 b->add_statement(s);
1197 // val = val_temp
1198 ref = Expression::make_temporary_reference(val_temp, loc);
1199 s = Statement::make_assignment(this->val_, ref, loc);
1200 b->add_statement(s);
1202 // present = present_temp
1203 ref = Expression::make_temporary_reference(present_temp, loc);
1204 s = Statement::make_assignment(this->present_, ref, loc);
1205 b->add_statement(s);
1207 return Statement::make_block_statement(b, loc);
1210 // Dump the AST representation for a tuple map assignment statement.
1212 void
1213 Tuple_map_assignment_statement::do_dump_statement(
1214 Ast_dump_context* ast_dump_context) const
1216 ast_dump_context->print_indent();
1217 ast_dump_context->dump_expression(this->val_);
1218 ast_dump_context->ostream() << ", ";
1219 ast_dump_context->dump_expression(this->present_);
1220 ast_dump_context->ostream() << " = ";
1221 ast_dump_context->dump_expression(this->map_index_);
1222 ast_dump_context->ostream() << std::endl;
1225 // Make a map assignment statement which returns a pair of values.
1227 Statement*
1228 Statement::make_tuple_map_assignment(Expression* val, Expression* present,
1229 Expression* map_index,
1230 Location location)
1232 return new Tuple_map_assignment_statement(val, present, map_index, location);
1235 // Assign a pair of entries to a map.
1236 // m[k] = v, p
1238 class Map_assignment_statement : public Statement
1240 public:
1241 Map_assignment_statement(Expression* map_index,
1242 Expression* val, Expression* should_set,
1243 Location location)
1244 : Statement(STATEMENT_MAP_ASSIGNMENT, location),
1245 map_index_(map_index), val_(val), should_set_(should_set)
1248 protected:
1250 do_traverse(Traverse* traverse);
1252 bool
1253 do_traverse_assignments(Traverse_assignments*)
1254 { go_unreachable(); }
1256 Statement*
1257 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1259 Bstatement*
1260 do_get_backend(Translate_context*)
1261 { go_unreachable(); }
1263 void
1264 do_dump_statement(Ast_dump_context*) const;
1266 private:
1267 // A reference to the map index which should be set or deleted.
1268 Expression* map_index_;
1269 // The value to add to the map.
1270 Expression* val_;
1271 // Whether or not to add the value.
1272 Expression* should_set_;
1275 // Traverse a map assignment.
1278 Map_assignment_statement::do_traverse(Traverse* traverse)
1280 if (this->traverse_expression(traverse, &this->map_index_) == TRAVERSE_EXIT
1281 || this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT)
1282 return TRAVERSE_EXIT;
1283 return this->traverse_expression(traverse, &this->should_set_);
1286 // Lower a map assignment to a function call.
1288 Statement*
1289 Map_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
1290 Statement_inserter*)
1292 Location loc = this->location();
1294 Map_index_expression* map_index = this->map_index_->map_index_expression();
1295 if (map_index == NULL)
1297 this->report_error(_("expected map index on left hand side"));
1298 return Statement::make_error_statement(loc);
1300 Map_type* map_type = map_index->get_map_type();
1301 if (map_type == NULL)
1302 return Statement::make_error_statement(loc);
1304 Block* b = new Block(enclosing, loc);
1306 // Evaluate the map first to get order of evaluation right.
1307 // map_temp := m // we are evaluating m[k] = v, p
1308 Temporary_statement* map_temp = Statement::make_temporary(map_type,
1309 map_index->map(),
1310 loc);
1311 b->add_statement(map_temp);
1313 // var key_temp MAP_KEY_TYPE = k
1314 Temporary_statement* key_temp =
1315 Statement::make_temporary(map_type->key_type(), map_index->index(), loc);
1316 b->add_statement(key_temp);
1318 // var val_temp MAP_VAL_TYPE = v
1319 Temporary_statement* val_temp =
1320 Statement::make_temporary(map_type->val_type(), this->val_, loc);
1321 b->add_statement(val_temp);
1323 // var insert_temp bool = p
1324 Temporary_statement* insert_temp =
1325 Statement::make_temporary(Type::lookup_bool_type(), this->should_set_,
1326 loc);
1327 b->add_statement(insert_temp);
1329 // mapassign2(map_temp, &key_temp, &val_temp, p)
1330 Expression* p1 = Expression::make_temporary_reference(map_temp, loc);
1331 Expression* ref = Expression::make_temporary_reference(key_temp, loc);
1332 Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
1333 ref = Expression::make_temporary_reference(val_temp, loc);
1334 Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
1335 Expression* p4 = Expression::make_temporary_reference(insert_temp, loc);
1336 Expression* call = Runtime::make_call(Runtime::MAPASSIGN2, loc, 4,
1337 p1, p2, p3, p4);
1338 Statement* s = Statement::make_statement(call, true);
1339 b->add_statement(s);
1341 return Statement::make_block_statement(b, loc);
1344 // Dump the AST representation for a map assignment statement.
1346 void
1347 Map_assignment_statement::do_dump_statement(
1348 Ast_dump_context* ast_dump_context) const
1350 ast_dump_context->print_indent();
1351 ast_dump_context->dump_expression(this->map_index_);
1352 ast_dump_context->ostream() << " = ";
1353 ast_dump_context->dump_expression(this->val_);
1354 ast_dump_context->ostream() << ", ";
1355 ast_dump_context->dump_expression(this->should_set_);
1356 ast_dump_context->ostream() << std::endl;
1359 // Make a statement which assigns a pair of entries to a map.
1361 Statement*
1362 Statement::make_map_assignment(Expression* map_index,
1363 Expression* val, Expression* should_set,
1364 Location location)
1366 return new Map_assignment_statement(map_index, val, should_set, location);
1369 // A tuple assignment from a receive statement.
1371 class Tuple_receive_assignment_statement : public Statement
1373 public:
1374 Tuple_receive_assignment_statement(Expression* val, Expression* closed,
1375 Expression* channel, Location location)
1376 : Statement(STATEMENT_TUPLE_RECEIVE_ASSIGNMENT, location),
1377 val_(val), closed_(closed), channel_(channel)
1380 protected:
1382 do_traverse(Traverse* traverse);
1384 bool
1385 do_traverse_assignments(Traverse_assignments*)
1386 { go_unreachable(); }
1388 Statement*
1389 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1391 Bstatement*
1392 do_get_backend(Translate_context*)
1393 { go_unreachable(); }
1395 void
1396 do_dump_statement(Ast_dump_context*) const;
1398 private:
1399 // Lvalue which receives the value from the channel.
1400 Expression* val_;
1401 // Lvalue which receives whether the channel is closed.
1402 Expression* closed_;
1403 // The channel on which we receive the value.
1404 Expression* channel_;
1407 // Traversal.
1410 Tuple_receive_assignment_statement::do_traverse(Traverse* traverse)
1412 if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
1413 || this->traverse_expression(traverse, &this->closed_) == TRAVERSE_EXIT)
1414 return TRAVERSE_EXIT;
1415 return this->traverse_expression(traverse, &this->channel_);
1418 // Lower to a function call.
1420 Statement*
1421 Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
1422 Block* enclosing,
1423 Statement_inserter*)
1425 Location loc = this->location();
1427 Channel_type* channel_type = this->channel_->type()->channel_type();
1428 if (channel_type == NULL)
1430 this->report_error(_("expected channel"));
1431 return Statement::make_error_statement(loc);
1433 if (!channel_type->may_receive())
1435 this->report_error(_("invalid receive on send-only channel"));
1436 return Statement::make_error_statement(loc);
1439 Block* b = new Block(enclosing, loc);
1441 // Make sure that any subexpressions on the left hand side are
1442 // evaluated in the right order.
1443 Move_ordered_evals moe(b);
1444 this->val_->traverse_subexpressions(&moe);
1445 this->closed_->traverse_subexpressions(&moe);
1447 // var val_temp ELEMENT_TYPE
1448 Temporary_statement* val_temp =
1449 Statement::make_temporary(channel_type->element_type(), NULL, loc);
1450 b->add_statement(val_temp);
1452 // var closed_temp bool
1453 Temporary_statement* closed_temp =
1454 Statement::make_temporary((this->closed_->type()->is_sink_type())
1455 ? Type::make_boolean_type()
1456 : this->closed_->type(),
1457 NULL, loc);
1458 b->add_statement(closed_temp);
1460 // closed_temp = chanrecv2(type, channel, &val_temp)
1461 Expression* td = Expression::make_type_descriptor(this->channel_->type(),
1462 loc);
1463 Temporary_reference_expression* ref =
1464 Expression::make_temporary_reference(val_temp, loc);
1465 Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
1466 Expression* call = Runtime::make_call(Runtime::CHANRECV2,
1467 loc, 3, td, this->channel_, p2);
1468 ref = Expression::make_temporary_reference(closed_temp, loc);
1469 ref->set_is_lvalue();
1470 Statement* s = Statement::make_assignment(ref, call, loc);
1471 b->add_statement(s);
1473 // val = val_temp
1474 ref = Expression::make_temporary_reference(val_temp, loc);
1475 s = Statement::make_assignment(this->val_, ref, loc);
1476 b->add_statement(s);
1478 // closed = closed_temp
1479 ref = Expression::make_temporary_reference(closed_temp, loc);
1480 s = Statement::make_assignment(this->closed_, ref, loc);
1481 b->add_statement(s);
1483 return Statement::make_block_statement(b, loc);
1486 // Dump the AST representation for a tuple receive statement.
1488 void
1489 Tuple_receive_assignment_statement::do_dump_statement(
1490 Ast_dump_context* ast_dump_context) const
1492 ast_dump_context->print_indent();
1493 ast_dump_context->dump_expression(this->val_);
1494 ast_dump_context->ostream() << ", ";
1495 ast_dump_context->dump_expression(this->closed_);
1496 ast_dump_context->ostream() << " <- ";
1497 ast_dump_context->dump_expression(this->channel_);
1498 ast_dump_context->ostream() << std::endl;
1501 // Make a nonblocking receive statement.
1503 Statement*
1504 Statement::make_tuple_receive_assignment(Expression* val, Expression* closed,
1505 Expression* channel,
1506 Location location)
1508 return new Tuple_receive_assignment_statement(val, closed, channel,
1509 location);
1512 // An assignment to a pair of values from a type guard. This is a
1513 // conditional type guard. v, ok = i.(type).
1515 class Tuple_type_guard_assignment_statement : public Statement
1517 public:
1518 Tuple_type_guard_assignment_statement(Expression* val, Expression* ok,
1519 Expression* expr, Type* type,
1520 Location location)
1521 : Statement(STATEMENT_TUPLE_TYPE_GUARD_ASSIGNMENT, location),
1522 val_(val), ok_(ok), expr_(expr), type_(type)
1525 protected:
1527 do_traverse(Traverse*);
1529 bool
1530 do_traverse_assignments(Traverse_assignments*)
1531 { go_unreachable(); }
1533 Statement*
1534 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1536 Bstatement*
1537 do_get_backend(Translate_context*)
1538 { go_unreachable(); }
1540 void
1541 do_dump_statement(Ast_dump_context*) const;
1543 private:
1544 Call_expression*
1545 lower_to_type(Runtime::Function);
1547 void
1548 lower_to_object_type(Block*, Runtime::Function);
1550 // The variable which recieves the converted value.
1551 Expression* val_;
1552 // The variable which receives the indication of success.
1553 Expression* ok_;
1554 // The expression being converted.
1555 Expression* expr_;
1556 // The type to which the expression is being converted.
1557 Type* type_;
1560 // Traverse a type guard tuple assignment.
1563 Tuple_type_guard_assignment_statement::do_traverse(Traverse* traverse)
1565 if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
1566 || this->traverse_expression(traverse, &this->ok_) == TRAVERSE_EXIT
1567 || this->traverse_type(traverse, this->type_) == TRAVERSE_EXIT)
1568 return TRAVERSE_EXIT;
1569 return this->traverse_expression(traverse, &this->expr_);
1572 // Lower to a function call.
1574 Statement*
1575 Tuple_type_guard_assignment_statement::do_lower(Gogo*, Named_object*,
1576 Block* enclosing,
1577 Statement_inserter*)
1579 Location loc = this->location();
1581 Type* expr_type = this->expr_->type();
1582 if (expr_type->interface_type() == NULL)
1584 if (!expr_type->is_error() && !this->type_->is_error())
1585 this->report_error(_("type assertion only valid for interface types"));
1586 return Statement::make_error_statement(loc);
1589 Block* b = new Block(enclosing, loc);
1591 // Make sure that any subexpressions on the left hand side are
1592 // evaluated in the right order.
1593 Move_ordered_evals moe(b);
1594 this->val_->traverse_subexpressions(&moe);
1595 this->ok_->traverse_subexpressions(&moe);
1597 bool expr_is_empty = expr_type->interface_type()->is_empty();
1598 Call_expression* call;
1599 if (this->type_->interface_type() != NULL)
1601 if (this->type_->interface_type()->is_empty())
1602 call = Runtime::make_call((expr_is_empty
1603 ? Runtime::IFACEE2E2
1604 : Runtime::IFACEI2E2),
1605 loc, 1, this->expr_);
1606 else
1607 call = this->lower_to_type(expr_is_empty
1608 ? Runtime::IFACEE2I2
1609 : Runtime::IFACEI2I2);
1611 else if (this->type_->points_to() != NULL)
1612 call = this->lower_to_type(expr_is_empty
1613 ? Runtime::IFACEE2T2P
1614 : Runtime::IFACEI2T2P);
1615 else
1617 this->lower_to_object_type(b,
1618 (expr_is_empty
1619 ? Runtime::IFACEE2T2
1620 : Runtime::IFACEI2T2));
1621 call = NULL;
1624 if (call != NULL)
1626 Expression* res = Expression::make_call_result(call, 0);
1627 res = Expression::make_unsafe_cast(this->type_, res, loc);
1628 Statement* s = Statement::make_assignment(this->val_, res, loc);
1629 b->add_statement(s);
1631 res = Expression::make_call_result(call, 1);
1632 s = Statement::make_assignment(this->ok_, res, loc);
1633 b->add_statement(s);
1636 return Statement::make_block_statement(b, loc);
1639 // Lower a conversion to a non-empty interface type or a pointer type.
1641 Call_expression*
1642 Tuple_type_guard_assignment_statement::lower_to_type(Runtime::Function code)
1644 Location loc = this->location();
1645 return Runtime::make_call(code, loc, 2,
1646 Expression::make_type_descriptor(this->type_, loc),
1647 this->expr_);
1650 // Lower a conversion to a non-interface non-pointer type.
1652 void
1653 Tuple_type_guard_assignment_statement::lower_to_object_type(
1654 Block* b,
1655 Runtime::Function code)
1657 Location loc = this->location();
1659 // var val_temp TYPE
1660 Temporary_statement* val_temp = Statement::make_temporary(this->type_,
1661 NULL, loc);
1662 b->add_statement(val_temp);
1664 // ok = CODE(type_descriptor, expr, &val_temp)
1665 Expression* p1 = Expression::make_type_descriptor(this->type_, loc);
1666 Expression* ref = Expression::make_temporary_reference(val_temp, loc);
1667 Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
1668 Expression* call = Runtime::make_call(code, loc, 3, p1, this->expr_, p3);
1669 Statement* s = Statement::make_assignment(this->ok_, call, loc);
1670 b->add_statement(s);
1672 // val = val_temp
1673 ref = Expression::make_temporary_reference(val_temp, loc);
1674 s = Statement::make_assignment(this->val_, ref, loc);
1675 b->add_statement(s);
1678 // Dump the AST representation for a tuple type guard statement.
1680 void
1681 Tuple_type_guard_assignment_statement::do_dump_statement(
1682 Ast_dump_context* ast_dump_context) const
1684 ast_dump_context->print_indent();
1685 ast_dump_context->dump_expression(this->val_);
1686 ast_dump_context->ostream() << ", ";
1687 ast_dump_context->dump_expression(this->ok_);
1688 ast_dump_context->ostream() << " = ";
1689 ast_dump_context->dump_expression(this->expr_);
1690 ast_dump_context->ostream() << " . ";
1691 ast_dump_context->dump_type(this->type_);
1692 ast_dump_context->ostream() << std::endl;
1695 // Make an assignment from a type guard to a pair of variables.
1697 Statement*
1698 Statement::make_tuple_type_guard_assignment(Expression* val, Expression* ok,
1699 Expression* expr, Type* type,
1700 Location location)
1702 return new Tuple_type_guard_assignment_statement(val, ok, expr, type,
1703 location);
1706 // Class Expression_statement.
1708 // Constructor.
1710 Expression_statement::Expression_statement(Expression* expr, bool is_ignored)
1711 : Statement(STATEMENT_EXPRESSION, expr->location()),
1712 expr_(expr), is_ignored_(is_ignored)
1716 // Determine types.
1718 void
1719 Expression_statement::do_determine_types()
1721 this->expr_->determine_type_no_context();
1724 // Check the types of an expression statement. The only check we do
1725 // is to possibly give an error about discarding the value of the
1726 // expression.
1728 void
1729 Expression_statement::do_check_types(Gogo*)
1731 if (!this->is_ignored_)
1732 this->expr_->discarding_value();
1735 // An expression statement is only a terminating statement if it is
1736 // a call to panic.
1738 bool
1739 Expression_statement::do_may_fall_through() const
1741 const Call_expression* call = this->expr_->call_expression();
1742 if (call != NULL)
1744 const Expression* fn = call->fn();
1745 // panic is still an unknown named object.
1746 const Unknown_expression* ue = fn->unknown_expression();
1747 if (ue != NULL)
1749 Named_object* no = ue->named_object();
1751 if (no->is_unknown())
1752 no = no->unknown_value()->real_named_object();
1753 if (no != NULL)
1755 Function_type* fntype;
1756 if (no->is_function())
1757 fntype = no->func_value()->type();
1758 else if (no->is_function_declaration())
1759 fntype = no->func_declaration_value()->type();
1760 else
1761 fntype = NULL;
1763 // The builtin function panic does not return.
1764 if (fntype != NULL && fntype->is_builtin() && no->name() == "panic")
1765 return false;
1769 return true;
1772 // Convert to backend representation.
1774 Bstatement*
1775 Expression_statement::do_get_backend(Translate_context* context)
1777 Bexpression* bexpr = this->expr_->get_backend(context);
1778 return context->backend()->expression_statement(bexpr);
1781 // Dump the AST representation for an expression statement
1783 void
1784 Expression_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
1785 const
1787 ast_dump_context->print_indent();
1788 ast_dump_context->dump_expression(expr_);
1789 ast_dump_context->ostream() << std::endl;
1792 // Make an expression statement from an Expression.
1794 Statement*
1795 Statement::make_statement(Expression* expr, bool is_ignored)
1797 return new Expression_statement(expr, is_ignored);
1800 // A block statement--a list of statements which may include variable
1801 // definitions.
1803 class Block_statement : public Statement
1805 public:
1806 Block_statement(Block* block, Location location)
1807 : Statement(STATEMENT_BLOCK, location),
1808 block_(block)
1811 protected:
1813 do_traverse(Traverse* traverse)
1814 { return this->block_->traverse(traverse); }
1816 void
1817 do_determine_types()
1818 { this->block_->determine_types(); }
1820 bool
1821 do_may_fall_through() const
1822 { return this->block_->may_fall_through(); }
1824 Bstatement*
1825 do_get_backend(Translate_context* context);
1827 void
1828 do_dump_statement(Ast_dump_context*) const;
1830 private:
1831 Block* block_;
1834 // Convert a block to the backend representation of a statement.
1836 Bstatement*
1837 Block_statement::do_get_backend(Translate_context* context)
1839 Bblock* bblock = this->block_->get_backend(context);
1840 return context->backend()->block_statement(bblock);
1843 // Dump the AST for a block statement
1845 void
1846 Block_statement::do_dump_statement(Ast_dump_context*) const
1848 // block statement braces are dumped when traversing.
1851 // Make a block statement.
1853 Statement*
1854 Statement::make_block_statement(Block* block, Location location)
1856 return new Block_statement(block, location);
1859 // An increment or decrement statement.
1861 class Inc_dec_statement : public Statement
1863 public:
1864 Inc_dec_statement(bool is_inc, Expression* expr)
1865 : Statement(STATEMENT_INCDEC, expr->location()),
1866 expr_(expr), is_inc_(is_inc)
1869 protected:
1871 do_traverse(Traverse* traverse)
1872 { return this->traverse_expression(traverse, &this->expr_); }
1874 bool
1875 do_traverse_assignments(Traverse_assignments*)
1876 { go_unreachable(); }
1878 Statement*
1879 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1881 Bstatement*
1882 do_get_backend(Translate_context*)
1883 { go_unreachable(); }
1885 void
1886 do_dump_statement(Ast_dump_context*) const;
1888 private:
1889 // The l-value to increment or decrement.
1890 Expression* expr_;
1891 // Whether to increment or decrement.
1892 bool is_inc_;
1895 // Lower to += or -=.
1897 Statement*
1898 Inc_dec_statement::do_lower(Gogo*, Named_object*, Block*, Statement_inserter*)
1900 Location loc = this->location();
1901 Expression* oexpr = Expression::make_integer_ul(1, this->expr_->type(), loc);
1902 Operator op = this->is_inc_ ? OPERATOR_PLUSEQ : OPERATOR_MINUSEQ;
1903 return Statement::make_assignment_operation(op, this->expr_, oexpr, loc);
1906 // Dump the AST representation for a inc/dec statement.
1908 void
1909 Inc_dec_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
1911 ast_dump_context->print_indent();
1912 ast_dump_context->dump_expression(expr_);
1913 ast_dump_context->ostream() << (is_inc_? "++": "--") << std::endl;
1916 // Make an increment statement.
1918 Statement*
1919 Statement::make_inc_statement(Expression* expr)
1921 return new Inc_dec_statement(true, expr);
1924 // Make a decrement statement.
1926 Statement*
1927 Statement::make_dec_statement(Expression* expr)
1929 return new Inc_dec_statement(false, expr);
1932 // Class Thunk_statement. This is the base class for go and defer
1933 // statements.
1935 Unordered_set(const Struct_type*) Thunk_statement::thunk_types;
1937 // Constructor.
1939 Thunk_statement::Thunk_statement(Statement_classification classification,
1940 Call_expression* call,
1941 Location location)
1942 : Statement(classification, location),
1943 call_(call), struct_type_(NULL)
1947 // Return whether this is a simple statement which does not require a
1948 // thunk.
1950 bool
1951 Thunk_statement::is_simple(Function_type* fntype) const
1953 // We need a thunk to call a method, or to pass a variable number of
1954 // arguments.
1955 if (fntype->is_method() || fntype->is_varargs())
1956 return false;
1958 // A defer statement requires a thunk to set up for whether the
1959 // function can call recover.
1960 if (this->classification() == STATEMENT_DEFER)
1961 return false;
1963 // We can only permit a single parameter of pointer type.
1964 const Typed_identifier_list* parameters = fntype->parameters();
1965 if (parameters != NULL
1966 && (parameters->size() > 1
1967 || (parameters->size() == 1
1968 && parameters->begin()->type()->points_to() == NULL)))
1969 return false;
1971 // If the function returns multiple values, or returns a type other
1972 // than integer, floating point, or pointer, then it may get a
1973 // hidden first parameter, in which case we need the more
1974 // complicated approach. This is true even though we are going to
1975 // ignore the return value.
1976 const Typed_identifier_list* results = fntype->results();
1977 if (results != NULL
1978 && (results->size() > 1
1979 || (results->size() == 1
1980 && !results->begin()->type()->is_basic_type()
1981 && results->begin()->type()->points_to() == NULL)))
1982 return false;
1984 // If this calls something that is not a simple function, then we
1985 // need a thunk.
1986 Expression* fn = this->call_->call_expression()->fn();
1987 if (fn->func_expression() == NULL)
1988 return false;
1990 // If the function uses a closure, then we need a thunk. FIXME: We
1991 // could accept a zero argument function with a closure.
1992 if (fn->func_expression()->closure() != NULL)
1993 return false;
1995 return true;
1998 // Traverse a thunk statement.
2001 Thunk_statement::do_traverse(Traverse* traverse)
2003 return this->traverse_expression(traverse, &this->call_);
2006 // We implement traverse_assignment for a thunk statement because it
2007 // effectively copies the function call.
2009 bool
2010 Thunk_statement::do_traverse_assignments(Traverse_assignments* tassign)
2012 Expression* fn = this->call_->call_expression()->fn();
2013 Expression* fn2 = fn;
2014 tassign->value(&fn2, true, false);
2015 return true;
2018 // Determine types in a thunk statement.
2020 void
2021 Thunk_statement::do_determine_types()
2023 this->call_->determine_type_no_context();
2025 // Now that we know the types of the call, build the struct used to
2026 // pass parameters.
2027 Call_expression* ce = this->call_->call_expression();
2028 if (ce == NULL)
2029 return;
2030 Function_type* fntype = ce->get_function_type();
2031 if (fntype != NULL && !this->is_simple(fntype))
2032 this->struct_type_ = this->build_struct(fntype);
2035 // Check types in a thunk statement.
2037 void
2038 Thunk_statement::do_check_types(Gogo*)
2040 if (!this->call_->discarding_value())
2041 return;
2042 Call_expression* ce = this->call_->call_expression();
2043 if (ce == NULL)
2045 if (!this->call_->is_error_expression())
2046 this->report_error("expected call expression");
2047 return;
2051 // The Traverse class used to find and simplify thunk statements.
2053 class Simplify_thunk_traverse : public Traverse
2055 public:
2056 Simplify_thunk_traverse(Gogo* gogo)
2057 : Traverse(traverse_functions | traverse_blocks),
2058 gogo_(gogo), function_(NULL)
2062 function(Named_object*);
2065 block(Block*);
2067 private:
2068 // General IR.
2069 Gogo* gogo_;
2070 // The function we are traversing.
2071 Named_object* function_;
2074 // Keep track of the current function while looking for thunks.
2077 Simplify_thunk_traverse::function(Named_object* no)
2079 go_assert(this->function_ == NULL);
2080 this->function_ = no;
2081 int t = no->func_value()->traverse(this);
2082 this->function_ = NULL;
2083 if (t == TRAVERSE_EXIT)
2084 return t;
2085 return TRAVERSE_SKIP_COMPONENTS;
2088 // Look for thunks in a block.
2091 Simplify_thunk_traverse::block(Block* b)
2093 // The parser ensures that thunk statements always appear at the end
2094 // of a block.
2095 if (b->statements()->size() < 1)
2096 return TRAVERSE_CONTINUE;
2097 Thunk_statement* stat = b->statements()->back()->thunk_statement();
2098 if (stat == NULL)
2099 return TRAVERSE_CONTINUE;
2100 if (stat->simplify_statement(this->gogo_, this->function_, b))
2101 return TRAVERSE_SKIP_COMPONENTS;
2102 return TRAVERSE_CONTINUE;
2105 // Simplify all thunk statements.
2107 void
2108 Gogo::simplify_thunk_statements()
2110 Simplify_thunk_traverse thunk_traverse(this);
2111 this->traverse(&thunk_traverse);
2114 // Return true if the thunk function is a constant, which means that
2115 // it does not need to be passed to the thunk routine.
2117 bool
2118 Thunk_statement::is_constant_function() const
2120 Call_expression* ce = this->call_->call_expression();
2121 Function_type* fntype = ce->get_function_type();
2122 if (fntype == NULL)
2124 go_assert(saw_errors());
2125 return false;
2127 if (fntype->is_builtin())
2128 return true;
2129 Expression* fn = ce->fn();
2130 if (fn->func_expression() != NULL)
2131 return fn->func_expression()->closure() == NULL;
2132 if (fn->interface_field_reference_expression() != NULL)
2133 return true;
2134 return false;
2137 // Simplify complex thunk statements into simple ones. A complicated
2138 // thunk statement is one which takes anything other than zero
2139 // parameters or a single pointer parameter. We rewrite it into code
2140 // which allocates a struct, stores the parameter values into the
2141 // struct, and does a simple go or defer statement which passes the
2142 // struct to a thunk. The thunk does the real call.
2144 bool
2145 Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
2146 Block* block)
2148 if (this->classification() == STATEMENT_ERROR)
2149 return false;
2150 if (this->call_->is_error_expression())
2151 return false;
2153 if (this->classification() == STATEMENT_DEFER)
2155 // Make sure that the defer stack exists for the function. We
2156 // will use when converting this statement to the backend
2157 // representation, but we want it to exist when we start
2158 // converting the function.
2159 function->func_value()->defer_stack(this->location());
2162 Call_expression* ce = this->call_->call_expression();
2163 Function_type* fntype = ce->get_function_type();
2164 if (fntype == NULL)
2166 go_assert(saw_errors());
2167 this->set_is_error();
2168 return false;
2170 if (this->is_simple(fntype))
2171 return false;
2173 Expression* fn = ce->fn();
2174 Interface_field_reference_expression* interface_method =
2175 fn->interface_field_reference_expression();
2177 Location location = this->location();
2179 std::string thunk_name = Gogo::thunk_name();
2181 // Build the thunk.
2182 this->build_thunk(gogo, thunk_name);
2184 // Generate code to call the thunk.
2186 // Get the values to store into the struct which is the single
2187 // argument to the thunk.
2189 Expression_list* vals = new Expression_list();
2190 if (!this->is_constant_function())
2191 vals->push_back(fn);
2193 if (interface_method != NULL)
2194 vals->push_back(interface_method->expr());
2196 if (ce->args() != NULL)
2198 for (Expression_list::const_iterator p = ce->args()->begin();
2199 p != ce->args()->end();
2200 ++p)
2202 if ((*p)->is_constant())
2203 continue;
2204 vals->push_back(*p);
2208 // Build the struct.
2209 Expression* constructor =
2210 Expression::make_struct_composite_literal(this->struct_type_, vals,
2211 location);
2213 // Allocate the initialized struct on the heap.
2214 constructor = Expression::make_heap_expression(constructor, location);
2216 // Look up the thunk.
2217 Named_object* named_thunk = gogo->lookup(thunk_name, NULL);
2218 go_assert(named_thunk != NULL && named_thunk->is_function());
2220 // Build the call.
2221 Expression* func = Expression::make_func_reference(named_thunk, NULL,
2222 location);
2223 Expression_list* params = new Expression_list();
2224 params->push_back(constructor);
2225 Call_expression* call = Expression::make_call(func, params, false, location);
2227 // Build the simple go or defer statement.
2228 Statement* s;
2229 if (this->classification() == STATEMENT_GO)
2230 s = Statement::make_go_statement(call, location);
2231 else if (this->classification() == STATEMENT_DEFER)
2232 s = Statement::make_defer_statement(call, location);
2233 else
2234 go_unreachable();
2236 // The current block should end with the go statement.
2237 go_assert(block->statements()->size() >= 1);
2238 go_assert(block->statements()->back() == this);
2239 block->replace_statement(block->statements()->size() - 1, s);
2241 // We already ran the determine_types pass, so we need to run it now
2242 // for the new statement.
2243 s->determine_types();
2245 // Sanity check.
2246 gogo->check_types_in_block(block);
2248 // Return true to tell the block not to keep looking at statements.
2249 return true;
2252 // Set the name to use for thunk parameter N.
2254 void
2255 Thunk_statement::thunk_field_param(int n, char* buf, size_t buflen)
2257 snprintf(buf, buflen, "a%d", n);
2260 // Build a new struct type to hold the parameters for a complicated
2261 // thunk statement. FNTYPE is the type of the function call.
2263 Struct_type*
2264 Thunk_statement::build_struct(Function_type* fntype)
2266 Location location = this->location();
2268 Struct_field_list* fields = new Struct_field_list();
2270 Call_expression* ce = this->call_->call_expression();
2271 Expression* fn = ce->fn();
2273 if (!this->is_constant_function())
2275 // The function to call.
2276 fields->push_back(Struct_field(Typed_identifier("fn", fntype,
2277 location)));
2280 // If this thunk statement calls a method on an interface, we pass
2281 // the interface object to the thunk.
2282 Interface_field_reference_expression* interface_method =
2283 fn->interface_field_reference_expression();
2284 if (interface_method != NULL)
2286 Typed_identifier tid("object", interface_method->expr()->type(),
2287 location);
2288 fields->push_back(Struct_field(tid));
2291 // The predeclared recover function has no argument. However, we
2292 // add an argument when building recover thunks. Handle that here.
2293 if (ce->is_recover_call())
2295 fields->push_back(Struct_field(Typed_identifier("can_recover",
2296 Type::lookup_bool_type(),
2297 location)));
2300 const Expression_list* args = ce->args();
2301 if (args != NULL)
2303 int i = 0;
2304 for (Expression_list::const_iterator p = args->begin();
2305 p != args->end();
2306 ++p, ++i)
2308 if ((*p)->is_constant())
2309 continue;
2311 char buf[50];
2312 this->thunk_field_param(i, buf, sizeof buf);
2313 fields->push_back(Struct_field(Typed_identifier(buf, (*p)->type(),
2314 location)));
2318 Struct_type *st = Type::make_struct_type(fields, location);
2320 Thunk_statement::thunk_types.insert(st);
2322 return st;
2325 // Return whether ST is a type created to hold thunk parameters.
2327 bool
2328 Thunk_statement::is_thunk_struct(const Struct_type* st)
2330 return (Thunk_statement::thunk_types.find(st)
2331 != Thunk_statement::thunk_types.end());
2334 // Build the thunk we are going to call. This is a brand new, albeit
2335 // artificial, function.
2337 void
2338 Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
2340 Location location = this->location();
2342 Call_expression* ce = this->call_->call_expression();
2344 bool may_call_recover = false;
2345 if (this->classification() == STATEMENT_DEFER)
2347 Func_expression* fn = ce->fn()->func_expression();
2348 if (fn == NULL)
2349 may_call_recover = true;
2350 else
2352 const Named_object* no = fn->named_object();
2353 if (!no->is_function())
2354 may_call_recover = true;
2355 else
2356 may_call_recover = no->func_value()->calls_recover();
2360 // Build the type of the thunk. The thunk takes a single parameter,
2361 // which is a pointer to the special structure we build.
2362 const char* const parameter_name = "__go_thunk_parameter";
2363 Typed_identifier_list* thunk_parameters = new Typed_identifier_list();
2364 Type* pointer_to_struct_type = Type::make_pointer_type(this->struct_type_);
2365 thunk_parameters->push_back(Typed_identifier(parameter_name,
2366 pointer_to_struct_type,
2367 location));
2369 Typed_identifier_list* thunk_results = NULL;
2370 if (may_call_recover)
2372 // When deferring a function which may call recover, add a
2373 // return value, to disable tail call optimizations which will
2374 // break the way we check whether recover is permitted.
2375 thunk_results = new Typed_identifier_list();
2376 thunk_results->push_back(Typed_identifier("", Type::lookup_bool_type(),
2377 location));
2380 Function_type* thunk_type = Type::make_function_type(NULL, thunk_parameters,
2381 thunk_results,
2382 location);
2384 // Start building the thunk.
2385 Named_object* function = gogo->start_function(thunk_name, thunk_type, true,
2386 location);
2388 gogo->start_block(location);
2390 // For a defer statement, start with a call to
2391 // __go_set_defer_retaddr. */
2392 Label* retaddr_label = NULL;
2393 if (may_call_recover)
2395 retaddr_label = gogo->add_label_reference("retaddr", location, false);
2396 Expression* arg = Expression::make_label_addr(retaddr_label, location);
2397 Expression* call = Runtime::make_call(Runtime::SET_DEFER_RETADDR,
2398 location, 1, arg);
2400 // This is a hack to prevent the middle-end from deleting the
2401 // label.
2402 gogo->start_block(location);
2403 gogo->add_statement(Statement::make_goto_statement(retaddr_label,
2404 location));
2405 Block* then_block = gogo->finish_block(location);
2406 then_block->determine_types();
2408 Statement* s = Statement::make_if_statement(call, then_block, NULL,
2409 location);
2410 s->determine_types();
2411 gogo->add_statement(s);
2413 function->func_value()->set_calls_defer_retaddr();
2416 // Get a reference to the parameter.
2417 Named_object* named_parameter = gogo->lookup(parameter_name, NULL);
2418 go_assert(named_parameter != NULL && named_parameter->is_variable());
2420 // Build the call. Note that the field names are the same as the
2421 // ones used in build_struct.
2422 Expression* thunk_parameter = Expression::make_var_reference(named_parameter,
2423 location);
2424 thunk_parameter = Expression::make_unary(OPERATOR_MULT, thunk_parameter,
2425 location);
2427 Interface_field_reference_expression* interface_method =
2428 ce->fn()->interface_field_reference_expression();
2430 Expression* func_to_call;
2431 unsigned int next_index;
2432 if (this->is_constant_function())
2434 func_to_call = ce->fn();
2435 next_index = 0;
2437 else
2439 func_to_call = Expression::make_field_reference(thunk_parameter,
2440 0, location);
2441 next_index = 1;
2444 if (interface_method != NULL)
2446 // The main program passes the interface object.
2447 go_assert(next_index == 0);
2448 Expression* r = Expression::make_field_reference(thunk_parameter, 0,
2449 location);
2450 const std::string& name(interface_method->name());
2451 func_to_call = Expression::make_interface_field_reference(r, name,
2452 location);
2453 next_index = 1;
2456 Expression_list* call_params = new Expression_list();
2457 const Struct_field_list* fields = this->struct_type_->fields();
2458 Struct_field_list::const_iterator p = fields->begin();
2459 for (unsigned int i = 0; i < next_index; ++i)
2460 ++p;
2461 bool is_recover_call = ce->is_recover_call();
2462 Expression* recover_arg = NULL;
2464 const Expression_list* args = ce->args();
2465 if (args != NULL)
2467 for (Expression_list::const_iterator arg = args->begin();
2468 arg != args->end();
2469 ++arg)
2471 Expression* param;
2472 if ((*arg)->is_constant())
2473 param = *arg;
2474 else
2476 Expression* thunk_param =
2477 Expression::make_var_reference(named_parameter, location);
2478 thunk_param =
2479 Expression::make_unary(OPERATOR_MULT, thunk_param, location);
2480 param = Expression::make_field_reference(thunk_param,
2481 next_index,
2482 location);
2483 ++next_index;
2486 if (!is_recover_call)
2487 call_params->push_back(param);
2488 else
2490 go_assert(call_params->empty());
2491 recover_arg = param;
2496 if (call_params->empty())
2498 delete call_params;
2499 call_params = NULL;
2502 Call_expression* call = Expression::make_call(func_to_call, call_params,
2503 false, location);
2505 // This call expression was already lowered before entering the
2506 // thunk statement. Don't try to lower varargs again, as that will
2507 // cause confusion for, e.g., method calls which already have a
2508 // receiver parameter.
2509 call->set_varargs_are_lowered();
2511 Statement* call_statement = Statement::make_statement(call, true);
2513 gogo->add_statement(call_statement);
2515 // If this is a defer statement, the label comes immediately after
2516 // the call.
2517 if (may_call_recover)
2519 gogo->add_label_definition("retaddr", location);
2521 Expression_list* vals = new Expression_list();
2522 vals->push_back(Expression::make_boolean(false, location));
2523 gogo->add_statement(Statement::make_return_statement(vals, location));
2526 Block* b = gogo->finish_block(location);
2528 gogo->add_block(b, location);
2530 gogo->lower_block(function, b);
2532 // We already ran the determine_types pass, so we need to run it
2533 // just for the call statement now. The other types are known.
2534 call_statement->determine_types();
2536 gogo->flatten_block(function, b);
2538 if (may_call_recover || recover_arg != NULL)
2540 // Dig up the call expression, which may have been changed
2541 // during lowering.
2542 go_assert(call_statement->classification() == STATEMENT_EXPRESSION);
2543 Expression_statement* es =
2544 static_cast<Expression_statement*>(call_statement);
2545 Call_expression* ce = es->expr()->call_expression();
2546 if (ce == NULL)
2547 go_assert(saw_errors());
2548 else
2550 if (may_call_recover)
2551 ce->set_is_deferred();
2552 if (recover_arg != NULL)
2553 ce->set_recover_arg(recover_arg);
2557 // That is all the thunk has to do.
2558 gogo->finish_function(location);
2561 // Get the function and argument expressions.
2563 bool
2564 Thunk_statement::get_fn_and_arg(Expression** pfn, Expression** parg)
2566 if (this->call_->is_error_expression())
2567 return false;
2569 Call_expression* ce = this->call_->call_expression();
2571 Expression* fn = ce->fn();
2572 Func_expression* fe = fn->func_expression();
2573 go_assert(fe != NULL);
2574 *pfn = Expression::make_func_code_reference(fe->named_object(),
2575 fe->location());
2577 const Expression_list* args = ce->args();
2578 if (args == NULL || args->empty())
2579 *parg = Expression::make_nil(this->location());
2580 else
2582 go_assert(args->size() == 1);
2583 *parg = args->front();
2586 return true;
2589 // Class Go_statement.
2591 Bstatement*
2592 Go_statement::do_get_backend(Translate_context* context)
2594 Expression* fn;
2595 Expression* arg;
2596 if (!this->get_fn_and_arg(&fn, &arg))
2597 return context->backend()->error_statement();
2599 Expression* call = Runtime::make_call(Runtime::GO, this->location(), 2,
2600 fn, arg);
2601 Bexpression* bcall = call->get_backend(context);
2602 return context->backend()->expression_statement(bcall);
2605 // Dump the AST representation for go statement.
2607 void
2608 Go_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
2610 ast_dump_context->print_indent();
2611 ast_dump_context->ostream() << "go ";
2612 ast_dump_context->dump_expression(this->call());
2613 ast_dump_context->ostream() << std::endl;
2616 // Make a go statement.
2618 Statement*
2619 Statement::make_go_statement(Call_expression* call, Location location)
2621 return new Go_statement(call, location);
2624 // Class Defer_statement.
2626 Bstatement*
2627 Defer_statement::do_get_backend(Translate_context* context)
2629 Expression* fn;
2630 Expression* arg;
2631 if (!this->get_fn_and_arg(&fn, &arg))
2632 return context->backend()->error_statement();
2634 Location loc = this->location();
2635 Expression* ds = context->function()->func_value()->defer_stack(loc);
2637 Expression* call = Runtime::make_call(Runtime::DEFER, loc, 3,
2638 ds, fn, arg);
2639 Bexpression* bcall = call->get_backend(context);
2640 return context->backend()->expression_statement(bcall);
2643 // Dump the AST representation for defer statement.
2645 void
2646 Defer_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
2648 ast_dump_context->print_indent();
2649 ast_dump_context->ostream() << "defer ";
2650 ast_dump_context->dump_expression(this->call());
2651 ast_dump_context->ostream() << std::endl;
2654 // Make a defer statement.
2656 Statement*
2657 Statement::make_defer_statement(Call_expression* call,
2658 Location location)
2660 return new Defer_statement(call, location);
2663 // Class Return_statement.
2665 // Traverse assignments. We treat each return value as a top level
2666 // RHS in an expression.
2668 bool
2669 Return_statement::do_traverse_assignments(Traverse_assignments* tassign)
2671 Expression_list* vals = this->vals_;
2672 if (vals != NULL)
2674 for (Expression_list::iterator p = vals->begin();
2675 p != vals->end();
2676 ++p)
2677 tassign->value(&*p, true, true);
2679 return true;
2682 // Lower a return statement. If we are returning a function call
2683 // which returns multiple values which match the current function,
2684 // split up the call's results. If the return statement lists
2685 // explicit values, implement this statement by assigning the values
2686 // to the result variables and change this statement to a naked
2687 // return. This lets panic/recover work correctly.
2689 Statement*
2690 Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing,
2691 Statement_inserter*)
2693 if (this->is_lowered_)
2694 return this;
2696 Expression_list* vals = this->vals_;
2697 this->vals_ = NULL;
2698 this->is_lowered_ = true;
2700 Location loc = this->location();
2702 size_t vals_count = vals == NULL ? 0 : vals->size();
2703 Function::Results* results = function->func_value()->result_variables();
2704 size_t results_count = results == NULL ? 0 : results->size();
2706 if (vals_count == 0)
2708 if (results_count > 0 && !function->func_value()->results_are_named())
2710 this->report_error(_("not enough arguments to return"));
2711 return this;
2713 return this;
2716 if (results_count == 0)
2718 this->report_error(_("return with value in function "
2719 "with no return type"));
2720 return this;
2723 // If the current function has multiple return values, and we are
2724 // returning a single call expression, split up the call expression.
2725 if (results_count > 1
2726 && vals->size() == 1
2727 && vals->front()->call_expression() != NULL)
2729 Call_expression* call = vals->front()->call_expression();
2730 call->set_expected_result_count(results_count);
2731 delete vals;
2732 vals = new Expression_list;
2733 for (size_t i = 0; i < results_count; ++i)
2734 vals->push_back(Expression::make_call_result(call, i));
2735 vals_count = results_count;
2738 if (vals_count < results_count)
2740 this->report_error(_("not enough arguments to return"));
2741 return this;
2744 if (vals_count > results_count)
2746 this->report_error(_("too many values in return statement"));
2747 return this;
2750 Block* b = new Block(enclosing, loc);
2752 Expression_list* lhs = new Expression_list();
2753 Expression_list* rhs = new Expression_list();
2755 Expression_list::const_iterator pe = vals->begin();
2756 int i = 1;
2757 for (Function::Results::const_iterator pr = results->begin();
2758 pr != results->end();
2759 ++pr, ++pe, ++i)
2761 Named_object* rv = *pr;
2762 Expression* e = *pe;
2764 // Check types now so that we give a good error message. The
2765 // result type is known. We determine the expression type
2766 // early.
2768 Type *rvtype = rv->result_var_value()->type();
2769 Type_context type_context(rvtype, false);
2770 e->determine_type(&type_context);
2772 std::string reason;
2773 if (Type::are_assignable(rvtype, e->type(), &reason))
2775 Expression* ve = Expression::make_var_reference(rv, e->location());
2776 lhs->push_back(ve);
2777 rhs->push_back(e);
2779 else
2781 if (reason.empty())
2782 error_at(e->location(), "incompatible type for return value %d", i);
2783 else
2784 error_at(e->location(),
2785 "incompatible type for return value %d (%s)",
2786 i, reason.c_str());
2789 go_assert(lhs->size() == rhs->size());
2791 if (lhs->empty())
2793 else if (lhs->size() == 1)
2795 b->add_statement(Statement::make_assignment(lhs->front(), rhs->front(),
2796 loc));
2797 delete lhs;
2798 delete rhs;
2800 else
2801 b->add_statement(Statement::make_tuple_assignment(lhs, rhs, loc));
2803 b->add_statement(this);
2805 delete vals;
2807 return Statement::make_block_statement(b, loc);
2810 // Convert a return statement to the backend representation.
2812 Bstatement*
2813 Return_statement::do_get_backend(Translate_context* context)
2815 Location loc = this->location();
2817 Function* function = context->function()->func_value();
2818 Function::Results* results = function->result_variables();
2819 std::vector<Bexpression*> retvals;
2820 if (results != NULL && !results->empty())
2822 retvals.reserve(results->size());
2823 for (Function::Results::const_iterator p = results->begin();
2824 p != results->end();
2825 p++)
2827 Expression* vr = Expression::make_var_reference(*p, loc);
2828 retvals.push_back(vr->get_backend(context));
2832 return context->backend()->return_statement(function->get_decl(),
2833 retvals, loc);
2836 // Dump the AST representation for a return statement.
2838 void
2839 Return_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
2841 ast_dump_context->print_indent();
2842 ast_dump_context->ostream() << "return " ;
2843 ast_dump_context->dump_expression_list(this->vals_);
2844 ast_dump_context->ostream() << std::endl;
2847 // Make a return statement.
2849 Return_statement*
2850 Statement::make_return_statement(Expression_list* vals,
2851 Location location)
2853 return new Return_statement(vals, location);
2856 // Make a statement that returns the result of a call expression.
2858 Statement*
2859 Statement::make_return_from_call(Call_expression* call, Location location)
2861 size_t rc = call->result_count();
2862 if (rc == 0)
2863 return Statement::make_statement(call, true);
2864 else
2866 Expression_list* vals = new Expression_list();
2867 if (rc == 1)
2868 vals->push_back(call);
2869 else
2871 for (size_t i = 0; i < rc; ++i)
2872 vals->push_back(Expression::make_call_result(call, i));
2874 return Statement::make_return_statement(vals, location);
2878 // A break or continue statement.
2880 class Bc_statement : public Statement
2882 public:
2883 Bc_statement(bool is_break, Unnamed_label* label, Location location)
2884 : Statement(STATEMENT_BREAK_OR_CONTINUE, location),
2885 label_(label), is_break_(is_break)
2888 bool
2889 is_break() const
2890 { return this->is_break_; }
2892 protected:
2894 do_traverse(Traverse*)
2895 { return TRAVERSE_CONTINUE; }
2897 bool
2898 do_may_fall_through() const
2899 { return false; }
2901 Bstatement*
2902 do_get_backend(Translate_context* context)
2903 { return this->label_->get_goto(context, this->location()); }
2905 void
2906 do_dump_statement(Ast_dump_context*) const;
2908 private:
2909 // The label that this branches to.
2910 Unnamed_label* label_;
2911 // True if this is "break", false if it is "continue".
2912 bool is_break_;
2915 // Dump the AST representation for a break/continue statement
2917 void
2918 Bc_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
2920 ast_dump_context->print_indent();
2921 ast_dump_context->ostream() << (this->is_break_ ? "break" : "continue");
2922 if (this->label_ != NULL)
2924 ast_dump_context->ostream() << " ";
2925 ast_dump_context->dump_label_name(this->label_);
2927 ast_dump_context->ostream() << std::endl;
2930 // Make a break statement.
2932 Statement*
2933 Statement::make_break_statement(Unnamed_label* label, Location location)
2935 return new Bc_statement(true, label, location);
2938 // Make a continue statement.
2940 Statement*
2941 Statement::make_continue_statement(Unnamed_label* label,
2942 Location location)
2944 return new Bc_statement(false, label, location);
2947 // A goto statement.
2949 class Goto_statement : public Statement
2951 public:
2952 Goto_statement(Label* label, Location location)
2953 : Statement(STATEMENT_GOTO, location),
2954 label_(label)
2957 protected:
2959 do_traverse(Traverse*)
2960 { return TRAVERSE_CONTINUE; }
2962 void
2963 do_check_types(Gogo*);
2965 bool
2966 do_may_fall_through() const
2967 { return false; }
2969 Bstatement*
2970 do_get_backend(Translate_context*);
2972 void
2973 do_dump_statement(Ast_dump_context*) const;
2975 private:
2976 Label* label_;
2979 // Check types for a label. There aren't any types per se, but we use
2980 // this to give an error if the label was never defined.
2982 void
2983 Goto_statement::do_check_types(Gogo*)
2985 if (!this->label_->is_defined())
2987 error_at(this->location(), "reference to undefined label %qs",
2988 Gogo::message_name(this->label_->name()).c_str());
2989 this->set_is_error();
2993 // Convert the goto statement to the backend representation.
2995 Bstatement*
2996 Goto_statement::do_get_backend(Translate_context* context)
2998 Blabel* blabel = this->label_->get_backend_label(context);
2999 return context->backend()->goto_statement(blabel, this->location());
3002 // Dump the AST representation for a goto statement.
3004 void
3005 Goto_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3007 ast_dump_context->print_indent();
3008 ast_dump_context->ostream() << "goto " << this->label_->name() << std::endl;
3011 // Make a goto statement.
3013 Statement*
3014 Statement::make_goto_statement(Label* label, Location location)
3016 return new Goto_statement(label, location);
3019 // A goto statement to an unnamed label.
3021 class Goto_unnamed_statement : public Statement
3023 public:
3024 Goto_unnamed_statement(Unnamed_label* label, Location location)
3025 : Statement(STATEMENT_GOTO_UNNAMED, location),
3026 label_(label)
3029 protected:
3031 do_traverse(Traverse*)
3032 { return TRAVERSE_CONTINUE; }
3034 bool
3035 do_may_fall_through() const
3036 { return false; }
3038 Bstatement*
3039 do_get_backend(Translate_context* context)
3040 { return this->label_->get_goto(context, this->location()); }
3042 void
3043 do_dump_statement(Ast_dump_context*) const;
3045 private:
3046 Unnamed_label* label_;
3049 // Dump the AST representation for an unnamed goto statement
3051 void
3052 Goto_unnamed_statement::do_dump_statement(
3053 Ast_dump_context* ast_dump_context) const
3055 ast_dump_context->print_indent();
3056 ast_dump_context->ostream() << "goto ";
3057 ast_dump_context->dump_label_name(this->label_);
3058 ast_dump_context->ostream() << std::endl;
3061 // Make a goto statement to an unnamed label.
3063 Statement*
3064 Statement::make_goto_unnamed_statement(Unnamed_label* label,
3065 Location location)
3067 return new Goto_unnamed_statement(label, location);
3070 // Class Label_statement.
3072 // Traversal.
3075 Label_statement::do_traverse(Traverse*)
3077 return TRAVERSE_CONTINUE;
3080 // Return the backend representation of the statement defining this
3081 // label.
3083 Bstatement*
3084 Label_statement::do_get_backend(Translate_context* context)
3086 Blabel* blabel = this->label_->get_backend_label(context);
3087 return context->backend()->label_definition_statement(blabel);
3090 // Dump the AST for a label definition statement.
3092 void
3093 Label_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3095 ast_dump_context->print_indent();
3096 ast_dump_context->ostream() << this->label_->name() << ":" << std::endl;
3099 // Make a label statement.
3101 Statement*
3102 Statement::make_label_statement(Label* label, Location location)
3104 return new Label_statement(label, location);
3107 // An unnamed label statement.
3109 class Unnamed_label_statement : public Statement
3111 public:
3112 Unnamed_label_statement(Unnamed_label* label)
3113 : Statement(STATEMENT_UNNAMED_LABEL, label->location()),
3114 label_(label)
3117 protected:
3119 do_traverse(Traverse*)
3120 { return TRAVERSE_CONTINUE; }
3122 Bstatement*
3123 do_get_backend(Translate_context* context)
3124 { return this->label_->get_definition(context); }
3126 void
3127 do_dump_statement(Ast_dump_context*) const;
3129 private:
3130 // The label.
3131 Unnamed_label* label_;
3134 // Dump the AST representation for an unnamed label definition statement.
3136 void
3137 Unnamed_label_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
3138 const
3140 ast_dump_context->print_indent();
3141 ast_dump_context->dump_label_name(this->label_);
3142 ast_dump_context->ostream() << ":" << std::endl;
3145 // Make an unnamed label statement.
3147 Statement*
3148 Statement::make_unnamed_label_statement(Unnamed_label* label)
3150 return new Unnamed_label_statement(label);
3153 // An if statement.
3155 class If_statement : public Statement
3157 public:
3158 If_statement(Expression* cond, Block* then_block, Block* else_block,
3159 Location location)
3160 : Statement(STATEMENT_IF, location),
3161 cond_(cond), then_block_(then_block), else_block_(else_block)
3164 protected:
3166 do_traverse(Traverse*);
3168 void
3169 do_determine_types();
3171 void
3172 do_check_types(Gogo*);
3174 bool
3175 do_may_fall_through() const;
3177 Bstatement*
3178 do_get_backend(Translate_context*);
3180 void
3181 do_dump_statement(Ast_dump_context*) const;
3183 private:
3184 Expression* cond_;
3185 Block* then_block_;
3186 Block* else_block_;
3189 // Traversal.
3192 If_statement::do_traverse(Traverse* traverse)
3194 if (this->traverse_expression(traverse, &this->cond_) == TRAVERSE_EXIT
3195 || this->then_block_->traverse(traverse) == TRAVERSE_EXIT)
3196 return TRAVERSE_EXIT;
3197 if (this->else_block_ != NULL)
3199 if (this->else_block_->traverse(traverse) == TRAVERSE_EXIT)
3200 return TRAVERSE_EXIT;
3202 return TRAVERSE_CONTINUE;
3205 void
3206 If_statement::do_determine_types()
3208 Type_context context(Type::lookup_bool_type(), false);
3209 this->cond_->determine_type(&context);
3210 this->then_block_->determine_types();
3211 if (this->else_block_ != NULL)
3212 this->else_block_->determine_types();
3215 // Check types.
3217 void
3218 If_statement::do_check_types(Gogo*)
3220 Type* type = this->cond_->type();
3221 if (type->is_error())
3222 this->set_is_error();
3223 else if (!type->is_boolean_type())
3224 this->report_error(_("expected boolean expression"));
3227 // Whether the overall statement may fall through.
3229 bool
3230 If_statement::do_may_fall_through() const
3232 return (this->else_block_ == NULL
3233 || this->then_block_->may_fall_through()
3234 || this->else_block_->may_fall_through());
3237 // Get the backend representation.
3239 Bstatement*
3240 If_statement::do_get_backend(Translate_context* context)
3242 go_assert(this->cond_->type()->is_boolean_type()
3243 || this->cond_->type()->is_error());
3244 Bexpression* cond = this->cond_->get_backend(context);
3245 Bblock* then_block = this->then_block_->get_backend(context);
3246 Bblock* else_block = (this->else_block_ == NULL
3247 ? NULL
3248 : this->else_block_->get_backend(context));
3249 return context->backend()->if_statement(cond, then_block, else_block,
3250 this->location());
3253 // Dump the AST representation for an if statement
3255 void
3256 If_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3258 ast_dump_context->print_indent();
3259 ast_dump_context->ostream() << "if ";
3260 ast_dump_context->dump_expression(this->cond_);
3261 ast_dump_context->ostream() << std::endl;
3262 if (ast_dump_context->dump_subblocks())
3264 ast_dump_context->dump_block(this->then_block_);
3265 if (this->else_block_ != NULL)
3267 ast_dump_context->print_indent();
3268 ast_dump_context->ostream() << "else" << std::endl;
3269 ast_dump_context->dump_block(this->else_block_);
3274 // Make an if statement.
3276 Statement*
3277 Statement::make_if_statement(Expression* cond, Block* then_block,
3278 Block* else_block, Location location)
3280 return new If_statement(cond, then_block, else_block, location);
3283 // Class Case_clauses::Hash_integer_value.
3285 class Case_clauses::Hash_integer_value
3287 public:
3288 size_t
3289 operator()(Expression*) const;
3292 size_t
3293 Case_clauses::Hash_integer_value::operator()(Expression* pe) const
3295 Numeric_constant nc;
3296 mpz_t ival;
3297 if (!pe->numeric_constant_value(&nc) || !nc.to_int(&ival))
3298 go_unreachable();
3299 size_t ret = mpz_get_ui(ival);
3300 mpz_clear(ival);
3301 return ret;
3304 // Class Case_clauses::Eq_integer_value.
3306 class Case_clauses::Eq_integer_value
3308 public:
3309 bool
3310 operator()(Expression*, Expression*) const;
3313 bool
3314 Case_clauses::Eq_integer_value::operator()(Expression* a, Expression* b) const
3316 Numeric_constant anc;
3317 mpz_t aval;
3318 Numeric_constant bnc;
3319 mpz_t bval;
3320 if (!a->numeric_constant_value(&anc)
3321 || !anc.to_int(&aval)
3322 || !b->numeric_constant_value(&bnc)
3323 || !bnc.to_int(&bval))
3324 go_unreachable();
3325 bool ret = mpz_cmp(aval, bval) == 0;
3326 mpz_clear(aval);
3327 mpz_clear(bval);
3328 return ret;
3331 // Class Case_clauses::Case_clause.
3333 // Traversal.
3336 Case_clauses::Case_clause::traverse(Traverse* traverse)
3338 if (this->cases_ != NULL
3339 && (traverse->traverse_mask()
3340 & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0)
3342 if (this->cases_->traverse(traverse) == TRAVERSE_EXIT)
3343 return TRAVERSE_EXIT;
3345 if (this->statements_ != NULL)
3347 if (this->statements_->traverse(traverse) == TRAVERSE_EXIT)
3348 return TRAVERSE_EXIT;
3350 return TRAVERSE_CONTINUE;
3353 // Check whether all the case expressions are integer constants.
3355 bool
3356 Case_clauses::Case_clause::is_constant() const
3358 if (this->cases_ != NULL)
3360 for (Expression_list::const_iterator p = this->cases_->begin();
3361 p != this->cases_->end();
3362 ++p)
3363 if (!(*p)->is_constant() || (*p)->type()->integer_type() == NULL)
3364 return false;
3366 return true;
3369 // Lower a case clause for a nonconstant switch. VAL_TEMP is the
3370 // value we are switching on; it may be NULL. If START_LABEL is not
3371 // NULL, it goes at the start of the statements, after the condition
3372 // test. We branch to FINISH_LABEL at the end of the statements.
3374 void
3375 Case_clauses::Case_clause::lower(Block* b, Temporary_statement* val_temp,
3376 Unnamed_label* start_label,
3377 Unnamed_label* finish_label) const
3379 Location loc = this->location_;
3380 Unnamed_label* next_case_label;
3381 if (this->cases_ == NULL || this->cases_->empty())
3383 go_assert(this->is_default_);
3384 next_case_label = NULL;
3386 else
3388 Expression* cond = NULL;
3390 for (Expression_list::const_iterator p = this->cases_->begin();
3391 p != this->cases_->end();
3392 ++p)
3394 Expression* ref = Expression::make_temporary_reference(val_temp,
3395 loc);
3396 Expression* this_cond = Expression::make_binary(OPERATOR_EQEQ, ref,
3397 *p, loc);
3398 if (cond == NULL)
3399 cond = this_cond;
3400 else
3401 cond = Expression::make_binary(OPERATOR_OROR, cond, this_cond, loc);
3404 Block* then_block = new Block(b, loc);
3405 next_case_label = new Unnamed_label(Linemap::unknown_location());
3406 Statement* s = Statement::make_goto_unnamed_statement(next_case_label,
3407 loc);
3408 then_block->add_statement(s);
3410 // if !COND { goto NEXT_CASE_LABEL }
3411 cond = Expression::make_unary(OPERATOR_NOT, cond, loc);
3412 s = Statement::make_if_statement(cond, then_block, NULL, loc);
3413 b->add_statement(s);
3416 if (start_label != NULL)
3417 b->add_statement(Statement::make_unnamed_label_statement(start_label));
3419 if (this->statements_ != NULL)
3420 b->add_statement(Statement::make_block_statement(this->statements_, loc));
3422 Statement* s = Statement::make_goto_unnamed_statement(finish_label, loc);
3423 b->add_statement(s);
3425 if (next_case_label != NULL)
3426 b->add_statement(Statement::make_unnamed_label_statement(next_case_label));
3429 // Determine types.
3431 void
3432 Case_clauses::Case_clause::determine_types(Type* type)
3434 if (this->cases_ != NULL)
3436 Type_context case_context(type, false);
3437 for (Expression_list::iterator p = this->cases_->begin();
3438 p != this->cases_->end();
3439 ++p)
3440 (*p)->determine_type(&case_context);
3442 if (this->statements_ != NULL)
3443 this->statements_->determine_types();
3446 // Check types. Returns false if there was an error.
3448 bool
3449 Case_clauses::Case_clause::check_types(Type* type)
3451 if (this->cases_ != NULL)
3453 for (Expression_list::iterator p = this->cases_->begin();
3454 p != this->cases_->end();
3455 ++p)
3457 if (!Type::are_assignable(type, (*p)->type(), NULL)
3458 && !Type::are_assignable((*p)->type(), type, NULL))
3460 error_at((*p)->location(),
3461 "type mismatch between switch value and case clause");
3462 return false;
3466 return true;
3469 // Return true if this clause may fall through to the following
3470 // statements. Note that this is not the same as whether the case
3471 // uses the "fallthrough" keyword.
3473 bool
3474 Case_clauses::Case_clause::may_fall_through() const
3476 if (this->statements_ == NULL)
3477 return true;
3478 return this->statements_->may_fall_through();
3481 // Convert the case values and statements to the backend
3482 // representation. BREAK_LABEL is the label which break statements
3483 // should branch to. CASE_CONSTANTS is used to detect duplicate
3484 // constants. *CASES should be passed as an empty vector; the values
3485 // for this case will be added to it. If this is the default case,
3486 // *CASES will remain empty. This returns the statement to execute if
3487 // one of these cases is selected.
3489 Bstatement*
3490 Case_clauses::Case_clause::get_backend(Translate_context* context,
3491 Unnamed_label* break_label,
3492 Case_constants* case_constants,
3493 std::vector<Bexpression*>* cases) const
3495 if (this->cases_ != NULL)
3497 go_assert(!this->is_default_);
3498 for (Expression_list::const_iterator p = this->cases_->begin();
3499 p != this->cases_->end();
3500 ++p)
3502 Expression* e = *p;
3503 if (e->classification() != Expression::EXPRESSION_INTEGER)
3505 Numeric_constant nc;
3506 mpz_t ival;
3507 if (!(*p)->numeric_constant_value(&nc) || !nc.to_int(&ival))
3509 // Something went wrong. This can happen with a
3510 // negative constant and an unsigned switch value.
3511 go_assert(saw_errors());
3512 continue;
3514 go_assert(nc.type() != NULL);
3515 e = Expression::make_integer_z(&ival, nc.type(), e->location());
3516 mpz_clear(ival);
3519 std::pair<Case_constants::iterator, bool> ins =
3520 case_constants->insert(e);
3521 if (!ins.second)
3523 // Value was already present.
3524 error_at(this->location_, "duplicate case in switch");
3525 e = Expression::make_error(this->location_);
3527 cases->push_back(e->get_backend(context));
3531 Bstatement* statements;
3532 if (this->statements_ == NULL)
3533 statements = NULL;
3534 else
3536 Bblock* bblock = this->statements_->get_backend(context);
3537 statements = context->backend()->block_statement(bblock);
3540 Bstatement* break_stat;
3541 if (this->is_fallthrough_)
3542 break_stat = NULL;
3543 else
3544 break_stat = break_label->get_goto(context, this->location_);
3546 if (statements == NULL)
3547 return break_stat;
3548 else if (break_stat == NULL)
3549 return statements;
3550 else
3551 return context->backend()->compound_statement(statements, break_stat);
3554 // Dump the AST representation for a case clause
3556 void
3557 Case_clauses::Case_clause::dump_clause(Ast_dump_context* ast_dump_context)
3558 const
3560 ast_dump_context->print_indent();
3561 if (this->is_default_)
3563 ast_dump_context->ostream() << "default:";
3565 else
3567 ast_dump_context->ostream() << "case ";
3568 ast_dump_context->dump_expression_list(this->cases_);
3569 ast_dump_context->ostream() << ":" ;
3571 ast_dump_context->dump_block(this->statements_);
3572 if (this->is_fallthrough_)
3574 ast_dump_context->print_indent();
3575 ast_dump_context->ostream() << " (fallthrough)" << std::endl;
3579 // Class Case_clauses.
3581 // Traversal.
3584 Case_clauses::traverse(Traverse* traverse)
3586 for (Clauses::iterator p = this->clauses_.begin();
3587 p != this->clauses_.end();
3588 ++p)
3590 if (p->traverse(traverse) == TRAVERSE_EXIT)
3591 return TRAVERSE_EXIT;
3593 return TRAVERSE_CONTINUE;
3596 // Check whether all the case expressions are constant.
3598 bool
3599 Case_clauses::is_constant() const
3601 for (Clauses::const_iterator p = this->clauses_.begin();
3602 p != this->clauses_.end();
3603 ++p)
3604 if (!p->is_constant())
3605 return false;
3606 return true;
3609 // Lower case clauses for a nonconstant switch.
3611 void
3612 Case_clauses::lower(Block* b, Temporary_statement* val_temp,
3613 Unnamed_label* break_label) const
3615 // The default case.
3616 const Case_clause* default_case = NULL;
3618 // The label for the fallthrough of the previous case.
3619 Unnamed_label* last_fallthrough_label = NULL;
3621 // The label for the start of the default case. This is used if the
3622 // case before the default case falls through.
3623 Unnamed_label* default_start_label = NULL;
3625 // The label for the end of the default case. This normally winds
3626 // up as BREAK_LABEL, but it will be different if the default case
3627 // falls through.
3628 Unnamed_label* default_finish_label = NULL;
3630 for (Clauses::const_iterator p = this->clauses_.begin();
3631 p != this->clauses_.end();
3632 ++p)
3634 // The label to use for the start of the statements for this
3635 // case. This is NULL unless the previous case falls through.
3636 Unnamed_label* start_label = last_fallthrough_label;
3638 // The label to jump to after the end of the statements for this
3639 // case.
3640 Unnamed_label* finish_label = break_label;
3642 last_fallthrough_label = NULL;
3643 if (p->is_fallthrough() && p + 1 != this->clauses_.end())
3645 finish_label = new Unnamed_label(p->location());
3646 last_fallthrough_label = finish_label;
3649 if (!p->is_default())
3650 p->lower(b, val_temp, start_label, finish_label);
3651 else
3653 // We have to move the default case to the end, so that we
3654 // only use it if all the other tests fail.
3655 default_case = &*p;
3656 default_start_label = start_label;
3657 default_finish_label = finish_label;
3661 if (default_case != NULL)
3662 default_case->lower(b, val_temp, default_start_label,
3663 default_finish_label);
3666 // Determine types.
3668 void
3669 Case_clauses::determine_types(Type* type)
3671 for (Clauses::iterator p = this->clauses_.begin();
3672 p != this->clauses_.end();
3673 ++p)
3674 p->determine_types(type);
3677 // Check types. Returns false if there was an error.
3679 bool
3680 Case_clauses::check_types(Type* type)
3682 bool ret = true;
3683 for (Clauses::iterator p = this->clauses_.begin();
3684 p != this->clauses_.end();
3685 ++p)
3687 if (!p->check_types(type))
3688 ret = false;
3690 return ret;
3693 // Return true if these clauses may fall through to the statements
3694 // following the switch statement.
3696 bool
3697 Case_clauses::may_fall_through() const
3699 bool found_default = false;
3700 for (Clauses::const_iterator p = this->clauses_.begin();
3701 p != this->clauses_.end();
3702 ++p)
3704 if (p->may_fall_through() && !p->is_fallthrough())
3705 return true;
3706 if (p->is_default())
3707 found_default = true;
3709 return !found_default;
3712 // Convert the cases to the backend representation. This sets
3713 // *ALL_CASES and *ALL_STATEMENTS.
3715 void
3716 Case_clauses::get_backend(Translate_context* context,
3717 Unnamed_label* break_label,
3718 std::vector<std::vector<Bexpression*> >* all_cases,
3719 std::vector<Bstatement*>* all_statements) const
3721 Case_constants case_constants;
3723 size_t c = this->clauses_.size();
3724 all_cases->resize(c);
3725 all_statements->resize(c);
3727 size_t i = 0;
3728 for (Clauses::const_iterator p = this->clauses_.begin();
3729 p != this->clauses_.end();
3730 ++p, ++i)
3732 std::vector<Bexpression*> cases;
3733 Bstatement* stat = p->get_backend(context, break_label, &case_constants,
3734 &cases);
3735 (*all_cases)[i].swap(cases);
3736 (*all_statements)[i] = stat;
3740 // Dump the AST representation for case clauses (from a switch statement)
3742 void
3743 Case_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
3745 for (Clauses::const_iterator p = this->clauses_.begin();
3746 p != this->clauses_.end();
3747 ++p)
3748 p->dump_clause(ast_dump_context);
3751 // A constant switch statement. A Switch_statement is lowered to this
3752 // when all the cases are constants.
3754 class Constant_switch_statement : public Statement
3756 public:
3757 Constant_switch_statement(Expression* val, Case_clauses* clauses,
3758 Unnamed_label* break_label,
3759 Location location)
3760 : Statement(STATEMENT_CONSTANT_SWITCH, location),
3761 val_(val), clauses_(clauses), break_label_(break_label)
3764 protected:
3766 do_traverse(Traverse*);
3768 void
3769 do_determine_types();
3771 void
3772 do_check_types(Gogo*);
3774 Bstatement*
3775 do_get_backend(Translate_context*);
3777 void
3778 do_dump_statement(Ast_dump_context*) const;
3780 private:
3781 // The value to switch on.
3782 Expression* val_;
3783 // The case clauses.
3784 Case_clauses* clauses_;
3785 // The break label, if needed.
3786 Unnamed_label* break_label_;
3789 // Traversal.
3792 Constant_switch_statement::do_traverse(Traverse* traverse)
3794 if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT)
3795 return TRAVERSE_EXIT;
3796 return this->clauses_->traverse(traverse);
3799 // Determine types.
3801 void
3802 Constant_switch_statement::do_determine_types()
3804 this->val_->determine_type_no_context();
3805 this->clauses_->determine_types(this->val_->type());
3808 // Check types.
3810 void
3811 Constant_switch_statement::do_check_types(Gogo*)
3813 if (!this->clauses_->check_types(this->val_->type()))
3814 this->set_is_error();
3817 // Convert to GENERIC.
3819 Bstatement*
3820 Constant_switch_statement::do_get_backend(Translate_context* context)
3822 Bexpression* switch_val_expr = this->val_->get_backend(context);
3824 Unnamed_label* break_label = this->break_label_;
3825 if (break_label == NULL)
3826 break_label = new Unnamed_label(this->location());
3828 std::vector<std::vector<Bexpression*> > all_cases;
3829 std::vector<Bstatement*> all_statements;
3830 this->clauses_->get_backend(context, break_label, &all_cases,
3831 &all_statements);
3833 Bfunction* bfunction = context->function()->func_value()->get_decl();
3834 Bstatement* switch_statement;
3835 switch_statement = context->backend()->switch_statement(bfunction,
3836 switch_val_expr,
3837 all_cases,
3838 all_statements,
3839 this->location());
3840 Bstatement* ldef = break_label->get_definition(context);
3841 return context->backend()->compound_statement(switch_statement, ldef);
3844 // Dump the AST representation for a constant switch statement.
3846 void
3847 Constant_switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
3848 const
3850 ast_dump_context->print_indent();
3851 ast_dump_context->ostream() << "switch ";
3852 ast_dump_context->dump_expression(this->val_);
3854 if (ast_dump_context->dump_subblocks())
3856 ast_dump_context->ostream() << " {" << std::endl;
3857 this->clauses_->dump_clauses(ast_dump_context);
3858 ast_dump_context->ostream() << "}";
3861 ast_dump_context->ostream() << std::endl;
3864 // Class Switch_statement.
3866 // Traversal.
3869 Switch_statement::do_traverse(Traverse* traverse)
3871 if (this->val_ != NULL)
3873 if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT)
3874 return TRAVERSE_EXIT;
3876 return this->clauses_->traverse(traverse);
3879 // Lower a Switch_statement to a Constant_switch_statement or a series
3880 // of if statements.
3882 Statement*
3883 Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
3884 Statement_inserter*)
3886 Location loc = this->location();
3888 if (this->val_ != NULL
3889 && (this->val_->is_error_expression()
3890 || this->val_->type()->is_error()))
3891 return Statement::make_error_statement(loc);
3893 if (this->val_ != NULL
3894 && this->val_->type()->integer_type() != NULL
3895 && !this->clauses_->empty()
3896 && this->clauses_->is_constant())
3897 return new Constant_switch_statement(this->val_, this->clauses_,
3898 this->break_label_, loc);
3900 if (this->val_ != NULL
3901 && !this->val_->type()->is_comparable()
3902 && !Type::are_compatible_for_comparison(true, this->val_->type(),
3903 Type::make_nil_type(), NULL))
3905 error_at(this->val_->location(),
3906 "cannot switch on value whose type that may not be compared");
3907 return Statement::make_error_statement(loc);
3910 Block* b = new Block(enclosing, loc);
3912 if (this->clauses_->empty())
3914 Expression* val = this->val_;
3915 if (val == NULL)
3916 val = Expression::make_boolean(true, loc);
3917 return Statement::make_statement(val, true);
3920 // var val_temp VAL_TYPE = VAL
3921 Expression* val = this->val_;
3922 if (val == NULL)
3923 val = Expression::make_boolean(true, loc);
3925 Type* type = val->type();
3926 if (type->is_abstract())
3927 type = type->make_non_abstract_type();
3928 Temporary_statement* val_temp = Statement::make_temporary(type, val, loc);
3929 b->add_statement(val_temp);
3931 this->clauses_->lower(b, val_temp, this->break_label());
3933 Statement* s = Statement::make_unnamed_label_statement(this->break_label_);
3934 b->add_statement(s);
3936 return Statement::make_block_statement(b, loc);
3939 // Return the break label for this switch statement, creating it if
3940 // necessary.
3942 Unnamed_label*
3943 Switch_statement::break_label()
3945 if (this->break_label_ == NULL)
3946 this->break_label_ = new Unnamed_label(this->location());
3947 return this->break_label_;
3950 // Dump the AST representation for a switch statement.
3952 void
3953 Switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3955 ast_dump_context->print_indent();
3956 ast_dump_context->ostream() << "switch ";
3957 if (this->val_ != NULL)
3959 ast_dump_context->dump_expression(this->val_);
3961 if (ast_dump_context->dump_subblocks())
3963 ast_dump_context->ostream() << " {" << std::endl;
3964 this->clauses_->dump_clauses(ast_dump_context);
3965 ast_dump_context->print_indent();
3966 ast_dump_context->ostream() << "}";
3968 ast_dump_context->ostream() << std::endl;
3971 // Return whether this switch may fall through.
3973 bool
3974 Switch_statement::do_may_fall_through() const
3976 if (this->clauses_ == NULL)
3977 return true;
3979 // If we have a break label, then some case needed it. That implies
3980 // that the switch statement as a whole can fall through.
3981 if (this->break_label_ != NULL)
3982 return true;
3984 return this->clauses_->may_fall_through();
3987 // Make a switch statement.
3989 Switch_statement*
3990 Statement::make_switch_statement(Expression* val, Location location)
3992 return new Switch_statement(val, location);
3995 // Class Type_case_clauses::Type_case_clause.
3997 // Traversal.
4000 Type_case_clauses::Type_case_clause::traverse(Traverse* traverse)
4002 if (!this->is_default_
4003 && ((traverse->traverse_mask()
4004 & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0)
4005 && Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
4006 return TRAVERSE_EXIT;
4007 if (this->statements_ != NULL)
4008 return this->statements_->traverse(traverse);
4009 return TRAVERSE_CONTINUE;
4012 // Lower one clause in a type switch. Add statements to the block B.
4013 // The type descriptor we are switching on is in DESCRIPTOR_TEMP.
4014 // BREAK_LABEL is the label at the end of the type switch.
4015 // *STMTS_LABEL, if not NULL, is a label to put at the start of the
4016 // statements.
4018 void
4019 Type_case_clauses::Type_case_clause::lower(Type* switch_val_type,
4020 Block* b,
4021 Temporary_statement* descriptor_temp,
4022 Unnamed_label* break_label,
4023 Unnamed_label** stmts_label) const
4025 Location loc = this->location_;
4027 Unnamed_label* next_case_label = NULL;
4028 if (!this->is_default_)
4030 Type* type = this->type_;
4032 std::string reason;
4033 if (switch_val_type->interface_type() != NULL
4034 && !type->is_nil_constant_as_type()
4035 && type->interface_type() == NULL
4036 && !switch_val_type->interface_type()->implements_interface(type,
4037 &reason))
4039 if (reason.empty())
4040 error_at(this->location_, "impossible type switch case");
4041 else
4042 error_at(this->location_, "impossible type switch case (%s)",
4043 reason.c_str());
4046 Expression* ref = Expression::make_temporary_reference(descriptor_temp,
4047 loc);
4049 Expression* cond;
4050 // The language permits case nil, which is of course a constant
4051 // rather than a type. It will appear here as an invalid
4052 // forwarding type.
4053 if (type->is_nil_constant_as_type())
4054 cond = Expression::make_binary(OPERATOR_EQEQ, ref,
4055 Expression::make_nil(loc),
4056 loc);
4057 else
4058 cond = Runtime::make_call((type->interface_type() == NULL
4059 ? Runtime::IFACETYPEEQ
4060 : Runtime::IFACEI2TP),
4061 loc, 2,
4062 Expression::make_type_descriptor(type, loc),
4063 ref);
4065 Unnamed_label* dest;
4066 if (!this->is_fallthrough_)
4068 // if !COND { goto NEXT_CASE_LABEL }
4069 next_case_label = new Unnamed_label(Linemap::unknown_location());
4070 dest = next_case_label;
4071 cond = Expression::make_unary(OPERATOR_NOT, cond, loc);
4073 else
4075 // if COND { goto STMTS_LABEL }
4076 go_assert(stmts_label != NULL);
4077 if (*stmts_label == NULL)
4078 *stmts_label = new Unnamed_label(Linemap::unknown_location());
4079 dest = *stmts_label;
4081 Block* then_block = new Block(b, loc);
4082 Statement* s = Statement::make_goto_unnamed_statement(dest, loc);
4083 then_block->add_statement(s);
4084 s = Statement::make_if_statement(cond, then_block, NULL, loc);
4085 b->add_statement(s);
4088 if (this->statements_ != NULL
4089 || (!this->is_fallthrough_
4090 && stmts_label != NULL
4091 && *stmts_label != NULL))
4093 go_assert(!this->is_fallthrough_);
4094 if (stmts_label != NULL && *stmts_label != NULL)
4096 go_assert(!this->is_default_);
4097 if (this->statements_ != NULL)
4098 (*stmts_label)->set_location(this->statements_->start_location());
4099 Statement* s = Statement::make_unnamed_label_statement(*stmts_label);
4100 b->add_statement(s);
4101 *stmts_label = NULL;
4103 if (this->statements_ != NULL)
4104 b->add_statement(Statement::make_block_statement(this->statements_,
4105 loc));
4108 if (this->is_fallthrough_)
4109 go_assert(next_case_label == NULL);
4110 else
4112 Location gloc = (this->statements_ == NULL
4113 ? loc
4114 : this->statements_->end_location());
4115 b->add_statement(Statement::make_goto_unnamed_statement(break_label,
4116 gloc));
4117 if (next_case_label != NULL)
4119 Statement* s =
4120 Statement::make_unnamed_label_statement(next_case_label);
4121 b->add_statement(s);
4126 // Return true if this type clause may fall through to the statements
4127 // following the switch.
4129 bool
4130 Type_case_clauses::Type_case_clause::may_fall_through() const
4132 if (this->is_fallthrough_)
4134 // This case means that we automatically fall through to the
4135 // next case (it's used for T1 in case T1, T2:). It does not
4136 // mean that we fall through to the end of the type switch as a
4137 // whole. There is sure to be a next case and that next case
4138 // will determine whether we fall through to the statements
4139 // after the type switch.
4140 return false;
4142 if (this->statements_ == NULL)
4143 return true;
4144 return this->statements_->may_fall_through();
4147 // Dump the AST representation for a type case clause
4149 void
4150 Type_case_clauses::Type_case_clause::dump_clause(
4151 Ast_dump_context* ast_dump_context) const
4153 ast_dump_context->print_indent();
4154 if (this->is_default_)
4156 ast_dump_context->ostream() << "default:";
4158 else
4160 ast_dump_context->ostream() << "case ";
4161 ast_dump_context->dump_type(this->type_);
4162 ast_dump_context->ostream() << ":" ;
4164 ast_dump_context->dump_block(this->statements_);
4165 if (this->is_fallthrough_)
4167 ast_dump_context->print_indent();
4168 ast_dump_context->ostream() << " (fallthrough)" << std::endl;
4172 // Class Type_case_clauses.
4174 // Traversal.
4177 Type_case_clauses::traverse(Traverse* traverse)
4179 for (Type_clauses::iterator p = this->clauses_.begin();
4180 p != this->clauses_.end();
4181 ++p)
4183 if (p->traverse(traverse) == TRAVERSE_EXIT)
4184 return TRAVERSE_EXIT;
4186 return TRAVERSE_CONTINUE;
4189 // Check for duplicate types.
4191 void
4192 Type_case_clauses::check_duplicates() const
4194 typedef Unordered_set_hash(const Type*, Type_hash_identical,
4195 Type_identical) Types_seen;
4196 Types_seen types_seen;
4197 for (Type_clauses::const_iterator p = this->clauses_.begin();
4198 p != this->clauses_.end();
4199 ++p)
4201 Type* t = p->type();
4202 if (t == NULL)
4203 continue;
4204 if (t->is_nil_constant_as_type())
4205 t = Type::make_nil_type();
4206 std::pair<Types_seen::iterator, bool> ins = types_seen.insert(t);
4207 if (!ins.second)
4208 error_at(p->location(), "duplicate type in switch");
4212 // Lower the clauses in a type switch. Add statements to the block B.
4213 // The type descriptor we are switching on is in DESCRIPTOR_TEMP.
4214 // BREAK_LABEL is the label at the end of the type switch.
4216 void
4217 Type_case_clauses::lower(Type* switch_val_type, Block* b,
4218 Temporary_statement* descriptor_temp,
4219 Unnamed_label* break_label) const
4221 const Type_case_clause* default_case = NULL;
4223 Unnamed_label* stmts_label = NULL;
4224 for (Type_clauses::const_iterator p = this->clauses_.begin();
4225 p != this->clauses_.end();
4226 ++p)
4228 if (!p->is_default())
4229 p->lower(switch_val_type, b, descriptor_temp, break_label,
4230 &stmts_label);
4231 else
4233 // We are generating a series of tests, which means that we
4234 // need to move the default case to the end.
4235 default_case = &*p;
4238 go_assert(stmts_label == NULL);
4240 if (default_case != NULL)
4241 default_case->lower(switch_val_type, b, descriptor_temp, break_label,
4242 NULL);
4245 // Return true if these clauses may fall through to the statements
4246 // following the switch statement.
4248 bool
4249 Type_case_clauses::may_fall_through() const
4251 bool found_default = false;
4252 for (Type_clauses::const_iterator p = this->clauses_.begin();
4253 p != this->clauses_.end();
4254 ++p)
4256 if (p->may_fall_through())
4257 return true;
4258 if (p->is_default())
4259 found_default = true;
4261 return !found_default;
4264 // Dump the AST representation for case clauses (from a switch statement)
4266 void
4267 Type_case_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
4269 for (Type_clauses::const_iterator p = this->clauses_.begin();
4270 p != this->clauses_.end();
4271 ++p)
4272 p->dump_clause(ast_dump_context);
4275 // Class Type_switch_statement.
4277 // Traversal.
4280 Type_switch_statement::do_traverse(Traverse* traverse)
4282 if (this->var_ == NULL)
4284 if (this->traverse_expression(traverse, &this->expr_) == TRAVERSE_EXIT)
4285 return TRAVERSE_EXIT;
4287 if (this->clauses_ != NULL)
4288 return this->clauses_->traverse(traverse);
4289 return TRAVERSE_CONTINUE;
4292 // Lower a type switch statement to a series of if statements. The gc
4293 // compiler is able to generate a table in some cases. However, that
4294 // does not work for us because we may have type descriptors in
4295 // different shared libraries, so we can't compare them with simple
4296 // equality testing.
4298 Statement*
4299 Type_switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
4300 Statement_inserter*)
4302 const Location loc = this->location();
4304 if (this->clauses_ != NULL)
4305 this->clauses_->check_duplicates();
4307 Block* b = new Block(enclosing, loc);
4309 Type* val_type = (this->var_ != NULL
4310 ? this->var_->var_value()->type()
4311 : this->expr_->type());
4313 if (val_type->interface_type() == NULL)
4315 if (!val_type->is_error())
4316 this->report_error(_("cannot type switch on non-interface value"));
4317 return Statement::make_error_statement(loc);
4320 // var descriptor_temp DESCRIPTOR_TYPE
4321 Type* descriptor_type = Type::make_type_descriptor_ptr_type();
4322 Temporary_statement* descriptor_temp =
4323 Statement::make_temporary(descriptor_type, NULL, loc);
4324 b->add_statement(descriptor_temp);
4326 // descriptor_temp = ifacetype(val_temp) FIXME: This should be
4327 // inlined.
4328 bool is_empty = val_type->interface_type()->is_empty();
4329 Expression* ref;
4330 if (this->var_ == NULL)
4331 ref = this->expr_;
4332 else
4333 ref = Expression::make_var_reference(this->var_, loc);
4334 Expression* call = Runtime::make_call((is_empty
4335 ? Runtime::EFACETYPE
4336 : Runtime::IFACETYPE),
4337 loc, 1, ref);
4338 Temporary_reference_expression* lhs =
4339 Expression::make_temporary_reference(descriptor_temp, loc);
4340 lhs->set_is_lvalue();
4341 Statement* s = Statement::make_assignment(lhs, call, loc);
4342 b->add_statement(s);
4344 if (this->clauses_ != NULL)
4345 this->clauses_->lower(val_type, b, descriptor_temp, this->break_label());
4347 s = Statement::make_unnamed_label_statement(this->break_label_);
4348 b->add_statement(s);
4350 return Statement::make_block_statement(b, loc);
4353 // Return whether this switch may fall through.
4355 bool
4356 Type_switch_statement::do_may_fall_through() const
4358 if (this->clauses_ == NULL)
4359 return true;
4361 // If we have a break label, then some case needed it. That implies
4362 // that the switch statement as a whole can fall through.
4363 if (this->break_label_ != NULL)
4364 return true;
4366 return this->clauses_->may_fall_through();
4369 // Return the break label for this type switch statement, creating it
4370 // if necessary.
4372 Unnamed_label*
4373 Type_switch_statement::break_label()
4375 if (this->break_label_ == NULL)
4376 this->break_label_ = new Unnamed_label(this->location());
4377 return this->break_label_;
4380 // Dump the AST representation for a type switch statement
4382 void
4383 Type_switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
4384 const
4386 ast_dump_context->print_indent();
4387 ast_dump_context->ostream() << "switch " << this->var_->name() << " = ";
4388 ast_dump_context->dump_expression(this->expr_);
4389 ast_dump_context->ostream() << " .(type)";
4390 if (ast_dump_context->dump_subblocks())
4392 ast_dump_context->ostream() << " {" << std::endl;
4393 this->clauses_->dump_clauses(ast_dump_context);
4394 ast_dump_context->ostream() << "}";
4396 ast_dump_context->ostream() << std::endl;
4399 // Make a type switch statement.
4401 Type_switch_statement*
4402 Statement::make_type_switch_statement(Named_object* var, Expression* expr,
4403 Location location)
4405 return new Type_switch_statement(var, expr, location);
4408 // Class Send_statement.
4410 // Traversal.
4413 Send_statement::do_traverse(Traverse* traverse)
4415 if (this->traverse_expression(traverse, &this->channel_) == TRAVERSE_EXIT)
4416 return TRAVERSE_EXIT;
4417 return this->traverse_expression(traverse, &this->val_);
4420 // Determine types.
4422 void
4423 Send_statement::do_determine_types()
4425 this->channel_->determine_type_no_context();
4426 Type* type = this->channel_->type();
4427 Type_context context;
4428 if (type->channel_type() != NULL)
4429 context.type = type->channel_type()->element_type();
4430 this->val_->determine_type(&context);
4433 // Check types.
4435 void
4436 Send_statement::do_check_types(Gogo*)
4438 Type* type = this->channel_->type();
4439 if (type->is_error())
4441 this->set_is_error();
4442 return;
4444 Channel_type* channel_type = type->channel_type();
4445 if (channel_type == NULL)
4447 error_at(this->location(), "left operand of %<<-%> must be channel");
4448 this->set_is_error();
4449 return;
4451 Type* element_type = channel_type->element_type();
4452 if (!Type::are_assignable(element_type, this->val_->type(), NULL))
4454 this->report_error(_("incompatible types in send"));
4455 return;
4457 if (!channel_type->may_send())
4459 this->report_error(_("invalid send on receive-only channel"));
4460 return;
4464 // Flatten a send statement. We may need a temporary for interface
4465 // conversion.
4467 Statement*
4468 Send_statement::do_flatten(Gogo*, Named_object*, Block*,
4469 Statement_inserter* inserter)
4471 Type* element_type = this->channel_->type()->channel_type()->element_type();
4472 if (!Type::are_identical(element_type, this->val_->type(), false, NULL)
4473 && this->val_->type()->interface_type() != NULL
4474 && !this->val_->is_variable())
4476 Temporary_statement* temp =
4477 Statement::make_temporary(NULL, this->val_, this->location());
4478 inserter->insert(temp);
4479 this->val_ = Expression::make_temporary_reference(temp,
4480 this->location());
4482 return this;
4485 // Convert a send statement to the backend representation.
4487 Bstatement*
4488 Send_statement::do_get_backend(Translate_context* context)
4490 Location loc = this->location();
4492 Channel_type* channel_type = this->channel_->type()->channel_type();
4493 Type* element_type = channel_type->element_type();
4494 Expression* val = Expression::convert_for_assignment(context->gogo(),
4495 element_type,
4496 this->val_, loc);
4498 bool is_small;
4499 bool can_take_address;
4500 switch (element_type->base()->classification())
4502 case Type::TYPE_BOOLEAN:
4503 case Type::TYPE_INTEGER:
4504 case Type::TYPE_FUNCTION:
4505 case Type::TYPE_POINTER:
4506 case Type::TYPE_MAP:
4507 case Type::TYPE_CHANNEL:
4508 is_small = true;
4509 can_take_address = false;
4510 break;
4512 case Type::TYPE_FLOAT:
4513 case Type::TYPE_COMPLEX:
4514 case Type::TYPE_STRING:
4515 case Type::TYPE_INTERFACE:
4516 is_small = false;
4517 can_take_address = false;
4518 break;
4520 case Type::TYPE_STRUCT:
4521 is_small = false;
4522 can_take_address = true;
4523 break;
4525 case Type::TYPE_ARRAY:
4526 is_small = false;
4527 can_take_address = !element_type->is_slice_type();
4528 break;
4530 default:
4531 case Type::TYPE_ERROR:
4532 case Type::TYPE_VOID:
4533 case Type::TYPE_SINK:
4534 case Type::TYPE_NIL:
4535 case Type::TYPE_NAMED:
4536 case Type::TYPE_FORWARD:
4537 go_assert(saw_errors());
4538 return context->backend()->error_statement();
4541 // Only try to take the address of a variable. We have already
4542 // moved variables to the heap, so this should not cause that to
4543 // happen unnecessarily.
4544 if (can_take_address
4545 && val->var_expression() == NULL
4546 && val->temporary_reference_expression() == NULL)
4547 can_take_address = false;
4549 Expression* td = Expression::make_type_descriptor(this->channel_->type(),
4550 loc);
4552 Runtime::Function code;
4553 Bstatement* btemp = NULL;
4554 if (is_small)
4556 // Type is small enough to handle as uint64.
4557 code = Runtime::SEND_SMALL;
4558 val = Expression::make_unsafe_cast(Type::lookup_integer_type("uint64"),
4559 val, loc);
4561 else if (can_take_address)
4563 // Must pass address of value. The function doesn't change the
4564 // value, so just take its address directly.
4565 code = Runtime::SEND_BIG;
4566 val = Expression::make_unary(OPERATOR_AND, val, loc);
4568 else
4570 // Must pass address of value, but the value is small enough
4571 // that it might be in registers. Copy value into temporary
4572 // variable to take address.
4573 code = Runtime::SEND_BIG;
4574 Temporary_statement* temp = Statement::make_temporary(element_type,
4575 val, loc);
4576 Expression* ref = Expression::make_temporary_reference(temp, loc);
4577 val = Expression::make_unary(OPERATOR_AND, ref, loc);
4578 btemp = temp->get_backend(context);
4581 Expression* call = Runtime::make_call(code, loc, 3, td, this->channel_, val);
4583 context->gogo()->lower_expression(context->function(), NULL, &call);
4584 Bexpression* bcall = call->get_backend(context);
4585 Bstatement* s = context->backend()->expression_statement(bcall);
4587 if (btemp == NULL)
4588 return s;
4589 else
4590 return context->backend()->compound_statement(btemp, s);
4593 // Dump the AST representation for a send statement
4595 void
4596 Send_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
4598 ast_dump_context->print_indent();
4599 ast_dump_context->dump_expression(this->channel_);
4600 ast_dump_context->ostream() << " <- ";
4601 ast_dump_context->dump_expression(this->val_);
4602 ast_dump_context->ostream() << std::endl;
4605 // Make a send statement.
4607 Send_statement*
4608 Statement::make_send_statement(Expression* channel, Expression* val,
4609 Location location)
4611 return new Send_statement(channel, val, location);
4614 // Class Select_clauses::Select_clause.
4616 // Traversal.
4619 Select_clauses::Select_clause::traverse(Traverse* traverse)
4621 if (!this->is_lowered_
4622 && (traverse->traverse_mask()
4623 & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0)
4625 if (this->channel_ != NULL)
4627 if (Expression::traverse(&this->channel_, traverse) == TRAVERSE_EXIT)
4628 return TRAVERSE_EXIT;
4630 if (this->val_ != NULL)
4632 if (Expression::traverse(&this->val_, traverse) == TRAVERSE_EXIT)
4633 return TRAVERSE_EXIT;
4635 if (this->closed_ != NULL)
4637 if (Expression::traverse(&this->closed_, traverse) == TRAVERSE_EXIT)
4638 return TRAVERSE_EXIT;
4641 if (this->statements_ != NULL)
4643 if (this->statements_->traverse(traverse) == TRAVERSE_EXIT)
4644 return TRAVERSE_EXIT;
4646 return TRAVERSE_CONTINUE;
4649 // Lowering. We call a function to register this clause, and arrange
4650 // to set any variables in any receive clause.
4652 void
4653 Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
4654 Block* b, Temporary_statement* sel)
4656 Location loc = this->location_;
4658 Expression* selref = Expression::make_temporary_reference(sel, loc);
4660 Expression* index_expr = Expression::make_integer_ul(this->index_, NULL,
4661 loc);
4663 if (this->is_default_)
4665 go_assert(this->channel_ == NULL && this->val_ == NULL);
4666 this->lower_default(b, selref, index_expr);
4667 this->is_lowered_ = true;
4668 return;
4671 // Evaluate the channel before the select statement.
4672 Temporary_statement* channel_temp = Statement::make_temporary(NULL,
4673 this->channel_,
4674 loc);
4675 b->add_statement(channel_temp);
4676 Expression* chanref = Expression::make_temporary_reference(channel_temp,
4677 loc);
4679 if (this->is_send_)
4680 this->lower_send(b, selref, chanref, index_expr);
4681 else
4682 this->lower_recv(gogo, function, b, selref, chanref, index_expr);
4684 // Now all references should be handled through the statements, not
4685 // through here.
4686 this->is_lowered_ = true;
4687 this->val_ = NULL;
4688 this->var_ = NULL;
4691 // Lower a default clause in a select statement.
4693 void
4694 Select_clauses::Select_clause::lower_default(Block* b, Expression* selref,
4695 Expression* index_expr)
4697 Location loc = this->location_;
4698 Expression* call = Runtime::make_call(Runtime::SELECTDEFAULT, loc, 2, selref,
4699 index_expr);
4700 b->add_statement(Statement::make_statement(call, true));
4703 // Lower a send clause in a select statement.
4705 void
4706 Select_clauses::Select_clause::lower_send(Block* b, Expression* selref,
4707 Expression* chanref,
4708 Expression* index_expr)
4710 Location loc = this->location_;
4712 Channel_type* ct = this->channel_->type()->channel_type();
4713 if (ct == NULL)
4714 return;
4716 Type* valtype = ct->element_type();
4718 // Note that copying the value to a temporary here means that we
4719 // evaluate the send values in the required order.
4720 Temporary_statement* val = Statement::make_temporary(valtype, this->val_,
4721 loc);
4722 b->add_statement(val);
4724 Expression* valref = Expression::make_temporary_reference(val, loc);
4725 Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc);
4727 Expression* call = Runtime::make_call(Runtime::SELECTSEND, loc, 4, selref,
4728 chanref, valaddr, index_expr);
4729 b->add_statement(Statement::make_statement(call, true));
4732 // Lower a receive clause in a select statement.
4734 void
4735 Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function,
4736 Block* b, Expression* selref,
4737 Expression* chanref,
4738 Expression* index_expr)
4740 Location loc = this->location_;
4742 Channel_type* ct = this->channel_->type()->channel_type();
4743 if (ct == NULL)
4744 return;
4746 Type* valtype = ct->element_type();
4747 Temporary_statement* val = Statement::make_temporary(valtype, NULL, loc);
4748 b->add_statement(val);
4750 Expression* valref = Expression::make_temporary_reference(val, loc);
4751 Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc);
4753 Temporary_statement* closed_temp = NULL;
4755 Expression* call;
4756 if (this->closed_ == NULL && this->closedvar_ == NULL)
4757 call = Runtime::make_call(Runtime::SELECTRECV, loc, 4, selref, chanref,
4758 valaddr, index_expr);
4759 else
4761 closed_temp = Statement::make_temporary(Type::lookup_bool_type(), NULL,
4762 loc);
4763 b->add_statement(closed_temp);
4764 Expression* cref = Expression::make_temporary_reference(closed_temp,
4765 loc);
4766 Expression* caddr = Expression::make_unary(OPERATOR_AND, cref, loc);
4767 call = Runtime::make_call(Runtime::SELECTRECV2, loc, 5, selref, chanref,
4768 valaddr, caddr, index_expr);
4771 b->add_statement(Statement::make_statement(call, true));
4773 // If the block of statements is executed, arrange for the received
4774 // value to move from VAL to the place where the statements expect
4775 // it.
4777 Block* init = NULL;
4779 if (this->var_ != NULL)
4781 go_assert(this->val_ == NULL);
4782 valref = Expression::make_temporary_reference(val, loc);
4783 this->var_->var_value()->set_init(valref);
4784 this->var_->var_value()->clear_type_from_chan_element();
4786 else if (this->val_ != NULL && !this->val_->is_sink_expression())
4788 init = new Block(b, loc);
4789 valref = Expression::make_temporary_reference(val, loc);
4790 init->add_statement(Statement::make_assignment(this->val_, valref, loc));
4793 if (this->closedvar_ != NULL)
4795 go_assert(this->closed_ == NULL);
4796 Expression* cref = Expression::make_temporary_reference(closed_temp,
4797 loc);
4798 this->closedvar_->var_value()->set_init(cref);
4800 else if (this->closed_ != NULL && !this->closed_->is_sink_expression())
4802 if (init == NULL)
4803 init = new Block(b, loc);
4804 Expression* cref = Expression::make_temporary_reference(closed_temp,
4805 loc);
4806 init->add_statement(Statement::make_assignment(this->closed_, cref,
4807 loc));
4810 if (init != NULL)
4812 gogo->lower_block(function, init);
4814 if (this->statements_ != NULL)
4815 init->add_statement(Statement::make_block_statement(this->statements_,
4816 loc));
4817 this->statements_ = init;
4821 // Determine types.
4823 void
4824 Select_clauses::Select_clause::determine_types()
4826 go_assert(this->is_lowered_);
4827 if (this->statements_ != NULL)
4828 this->statements_->determine_types();
4831 // Check types.
4833 void
4834 Select_clauses::Select_clause::check_types()
4836 if (this->is_default_)
4837 return;
4839 Channel_type* ct = this->channel_->type()->channel_type();
4840 if (ct == NULL)
4842 error_at(this->channel_->location(), "expected channel");
4843 return;
4846 if (this->is_send_ && !ct->may_send())
4847 error_at(this->location(), "invalid send on receive-only channel");
4848 else if (!this->is_send_ && !ct->may_receive())
4849 error_at(this->location(), "invalid receive on send-only channel");
4852 // Whether this clause may fall through to the statement which follows
4853 // the overall select statement.
4855 bool
4856 Select_clauses::Select_clause::may_fall_through() const
4858 if (this->statements_ == NULL)
4859 return true;
4860 return this->statements_->may_fall_through();
4863 // Return the backend representation for the statements to execute.
4865 Bstatement*
4866 Select_clauses::Select_clause::get_statements_backend(
4867 Translate_context* context)
4869 if (this->statements_ == NULL)
4870 return NULL;
4871 Bblock* bblock = this->statements_->get_backend(context);
4872 return context->backend()->block_statement(bblock);
4875 // Dump the AST representation for a select case clause
4877 void
4878 Select_clauses::Select_clause::dump_clause(
4879 Ast_dump_context* ast_dump_context) const
4881 ast_dump_context->print_indent();
4882 if (this->is_default_)
4884 ast_dump_context->ostream() << "default:";
4886 else
4888 ast_dump_context->ostream() << "case " ;
4889 if (this->is_send_)
4891 ast_dump_context->dump_expression(this->channel_);
4892 ast_dump_context->ostream() << " <- " ;
4893 if (this->val_ != NULL)
4894 ast_dump_context->dump_expression(this->val_);
4896 else
4898 if (this->val_ != NULL)
4899 ast_dump_context->dump_expression(this->val_);
4900 if (this->closed_ != NULL)
4902 // FIXME: can val_ == NULL and closed_ ! = NULL?
4903 ast_dump_context->ostream() << " , " ;
4904 ast_dump_context->dump_expression(this->closed_);
4906 if (this->closedvar_ != NULL || this->var_ != NULL)
4907 ast_dump_context->ostream() << " := " ;
4909 ast_dump_context->ostream() << " <- " ;
4910 ast_dump_context->dump_expression(this->channel_);
4912 ast_dump_context->ostream() << ":" ;
4914 ast_dump_context->dump_block(this->statements_);
4917 // Class Select_clauses.
4919 // Traversal.
4922 Select_clauses::traverse(Traverse* traverse)
4924 for (Clauses::iterator p = this->clauses_.begin();
4925 p != this->clauses_.end();
4926 ++p)
4928 if (p->traverse(traverse) == TRAVERSE_EXIT)
4929 return TRAVERSE_EXIT;
4931 return TRAVERSE_CONTINUE;
4934 // Lowering. Here we pull out the channel and the send values, to
4935 // enforce the order of evaluation. We also add explicit send and
4936 // receive statements to the clauses.
4938 void
4939 Select_clauses::lower(Gogo* gogo, Named_object* function, Block* b,
4940 Temporary_statement* sel)
4942 for (Clauses::iterator p = this->clauses_.begin();
4943 p != this->clauses_.end();
4944 ++p)
4945 p->lower(gogo, function, b, sel);
4948 // Determine types.
4950 void
4951 Select_clauses::determine_types()
4953 for (Clauses::iterator p = this->clauses_.begin();
4954 p != this->clauses_.end();
4955 ++p)
4956 p->determine_types();
4959 // Check types.
4961 void
4962 Select_clauses::check_types()
4964 for (Clauses::iterator p = this->clauses_.begin();
4965 p != this->clauses_.end();
4966 ++p)
4967 p->check_types();
4970 // Return whether these select clauses fall through to the statement
4971 // following the overall select statement.
4973 bool
4974 Select_clauses::may_fall_through() const
4976 for (Clauses::const_iterator p = this->clauses_.begin();
4977 p != this->clauses_.end();
4978 ++p)
4979 if (p->may_fall_through())
4980 return true;
4981 return false;
4984 // Convert to the backend representation. We have already accumulated
4985 // all the select information. Now we call selectgo, which will
4986 // return the index of the clause to execute.
4988 Bstatement*
4989 Select_clauses::get_backend(Translate_context* context,
4990 Temporary_statement* sel,
4991 Unnamed_label *break_label,
4992 Location location)
4994 size_t count = this->clauses_.size();
4995 std::vector<std::vector<Bexpression*> > cases(count);
4996 std::vector<Bstatement*> clauses(count);
4998 Type* int32_type = Type::lookup_integer_type("int32");
5000 int i = 0;
5001 for (Clauses::iterator p = this->clauses_.begin();
5002 p != this->clauses_.end();
5003 ++p, ++i)
5005 int index = p->index();
5006 Expression* index_expr = Expression::make_integer_ul(index, int32_type,
5007 location);
5008 cases[i].push_back(index_expr->get_backend(context));
5010 Bstatement* s = p->get_statements_backend(context);
5011 Location gloc = (p->statements() == NULL
5012 ? p->location()
5013 : p->statements()->end_location());
5014 Bstatement* g = break_label->get_goto(context, gloc);
5016 if (s == NULL)
5017 clauses[i] = g;
5018 else
5019 clauses[i] = context->backend()->compound_statement(s, g);
5022 Expression* selref = Expression::make_temporary_reference(sel, location);
5023 Expression* call = Runtime::make_call(Runtime::SELECTGO, location, 1,
5024 selref);
5025 context->gogo()->lower_expression(context->function(), NULL, &call);
5026 Bexpression* bcall = call->get_backend(context);
5028 if (count == 0)
5029 return context->backend()->expression_statement(bcall);
5031 std::vector<Bstatement*> statements;
5032 statements.reserve(2);
5034 Bfunction* bfunction = context->function()->func_value()->get_decl();
5035 Bstatement* switch_stmt = context->backend()->switch_statement(bfunction,
5036 bcall,
5037 cases,
5038 clauses,
5039 location);
5040 statements.push_back(switch_stmt);
5042 Bstatement* ldef = break_label->get_definition(context);
5043 statements.push_back(ldef);
5045 return context->backend()->statement_list(statements);
5047 // Dump the AST representation for select clauses.
5049 void
5050 Select_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
5052 for (Clauses::const_iterator p = this->clauses_.begin();
5053 p != this->clauses_.end();
5054 ++p)
5055 p->dump_clause(ast_dump_context);
5058 // Class Select_statement.
5060 // Return the break label for this switch statement, creating it if
5061 // necessary.
5063 Unnamed_label*
5064 Select_statement::break_label()
5066 if (this->break_label_ == NULL)
5067 this->break_label_ = new Unnamed_label(this->location());
5068 return this->break_label_;
5071 // Lower a select statement. This will still return a select
5072 // statement, but it will be modified to implement the order of
5073 // evaluation rules, and to include the send and receive statements as
5074 // explicit statements in the clauses.
5076 Statement*
5077 Select_statement::do_lower(Gogo* gogo, Named_object* function,
5078 Block* enclosing, Statement_inserter*)
5080 if (this->is_lowered_)
5081 return this;
5083 Location loc = this->location();
5085 Block* b = new Block(enclosing, loc);
5087 go_assert(this->sel_ == NULL);
5089 Expression* size_expr = Expression::make_integer_ul(this->clauses_->size(),
5090 NULL, loc);
5091 Expression* call = Runtime::make_call(Runtime::NEWSELECT, loc, 1, size_expr);
5093 this->sel_ = Statement::make_temporary(NULL, call, loc);
5094 b->add_statement(this->sel_);
5096 this->clauses_->lower(gogo, function, b, this->sel_);
5097 this->is_lowered_ = true;
5098 b->add_statement(this);
5100 return Statement::make_block_statement(b, loc);
5103 // Whether the select statement itself may fall through to the following
5104 // statement.
5106 bool
5107 Select_statement::do_may_fall_through() const
5109 // A select statement is terminating if no break statement
5110 // refers to it and all of its clauses are terminating.
5111 if (this->break_label_ != NULL)
5112 return true;
5113 return this->clauses_->may_fall_through();
5116 // Return the backend representation for a select statement.
5118 Bstatement*
5119 Select_statement::do_get_backend(Translate_context* context)
5121 return this->clauses_->get_backend(context, this->sel_, this->break_label(),
5122 this->location());
5125 // Dump the AST representation for a select statement.
5127 void
5128 Select_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
5130 ast_dump_context->print_indent();
5131 ast_dump_context->ostream() << "select";
5132 if (ast_dump_context->dump_subblocks())
5134 ast_dump_context->ostream() << " {" << std::endl;
5135 this->clauses_->dump_clauses(ast_dump_context);
5136 ast_dump_context->ostream() << "}";
5138 ast_dump_context->ostream() << std::endl;
5141 // Make a select statement.
5143 Select_statement*
5144 Statement::make_select_statement(Location location)
5146 return new Select_statement(location);
5149 // Class For_statement.
5151 // Traversal.
5154 For_statement::do_traverse(Traverse* traverse)
5156 if (this->init_ != NULL)
5158 if (this->init_->traverse(traverse) == TRAVERSE_EXIT)
5159 return TRAVERSE_EXIT;
5161 if (this->cond_ != NULL)
5163 if (this->traverse_expression(traverse, &this->cond_) == TRAVERSE_EXIT)
5164 return TRAVERSE_EXIT;
5166 if (this->post_ != NULL)
5168 if (this->post_->traverse(traverse) == TRAVERSE_EXIT)
5169 return TRAVERSE_EXIT;
5171 return this->statements_->traverse(traverse);
5174 // Lower a For_statement into if statements and gotos. Getting rid of
5175 // complex statements make it easier to handle garbage collection.
5177 Statement*
5178 For_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
5179 Statement_inserter*)
5181 Statement* s;
5182 Location loc = this->location();
5184 Block* b = new Block(enclosing, this->location());
5185 if (this->init_ != NULL)
5187 s = Statement::make_block_statement(this->init_,
5188 this->init_->start_location());
5189 b->add_statement(s);
5192 Unnamed_label* entry = NULL;
5193 if (this->cond_ != NULL)
5195 entry = new Unnamed_label(this->location());
5196 b->add_statement(Statement::make_goto_unnamed_statement(entry, loc));
5199 Unnamed_label* top = new Unnamed_label(this->location());
5200 b->add_statement(Statement::make_unnamed_label_statement(top));
5202 s = Statement::make_block_statement(this->statements_,
5203 this->statements_->start_location());
5204 b->add_statement(s);
5206 Location end_loc = this->statements_->end_location();
5208 Unnamed_label* cont = this->continue_label_;
5209 if (cont != NULL)
5210 b->add_statement(Statement::make_unnamed_label_statement(cont));
5212 if (this->post_ != NULL)
5214 s = Statement::make_block_statement(this->post_,
5215 this->post_->start_location());
5216 b->add_statement(s);
5217 end_loc = this->post_->end_location();
5220 if (this->cond_ == NULL)
5221 b->add_statement(Statement::make_goto_unnamed_statement(top, end_loc));
5222 else
5224 b->add_statement(Statement::make_unnamed_label_statement(entry));
5226 Location cond_loc = this->cond_->location();
5227 Block* then_block = new Block(b, cond_loc);
5228 s = Statement::make_goto_unnamed_statement(top, cond_loc);
5229 then_block->add_statement(s);
5231 s = Statement::make_if_statement(this->cond_, then_block, NULL, cond_loc);
5232 b->add_statement(s);
5235 Unnamed_label* brk = this->break_label_;
5236 if (brk != NULL)
5237 b->add_statement(Statement::make_unnamed_label_statement(brk));
5239 b->set_end_location(end_loc);
5241 return Statement::make_block_statement(b, loc);
5244 // Return the break label, creating it if necessary.
5246 Unnamed_label*
5247 For_statement::break_label()
5249 if (this->break_label_ == NULL)
5250 this->break_label_ = new Unnamed_label(this->location());
5251 return this->break_label_;
5254 // Return the continue LABEL_EXPR.
5256 Unnamed_label*
5257 For_statement::continue_label()
5259 if (this->continue_label_ == NULL)
5260 this->continue_label_ = new Unnamed_label(this->location());
5261 return this->continue_label_;
5264 // Set the break and continue labels a for statement. This is used
5265 // when lowering a for range statement.
5267 void
5268 For_statement::set_break_continue_labels(Unnamed_label* break_label,
5269 Unnamed_label* continue_label)
5271 go_assert(this->break_label_ == NULL && this->continue_label_ == NULL);
5272 this->break_label_ = break_label;
5273 this->continue_label_ = continue_label;
5276 // Whether the overall statement may fall through.
5278 bool
5279 For_statement::do_may_fall_through() const
5281 // A for loop is terminating if it has no condition and
5282 // no break statement.
5283 if(this->cond_ != NULL)
5284 return true;
5285 if(this->break_label_ != NULL)
5286 return true;
5287 return false;
5290 // Dump the AST representation for a for statement.
5292 void
5293 For_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
5295 if (this->init_ != NULL && ast_dump_context->dump_subblocks())
5297 ast_dump_context->print_indent();
5298 ast_dump_context->indent();
5299 ast_dump_context->ostream() << "// INIT " << std::endl;
5300 ast_dump_context->dump_block(this->init_);
5301 ast_dump_context->unindent();
5303 ast_dump_context->print_indent();
5304 ast_dump_context->ostream() << "for ";
5305 if (this->cond_ != NULL)
5306 ast_dump_context->dump_expression(this->cond_);
5308 if (ast_dump_context->dump_subblocks())
5310 ast_dump_context->ostream() << " {" << std::endl;
5311 ast_dump_context->dump_block(this->statements_);
5312 if (this->init_ != NULL)
5314 ast_dump_context->print_indent();
5315 ast_dump_context->ostream() << "// POST " << std::endl;
5316 ast_dump_context->dump_block(this->post_);
5318 ast_dump_context->unindent();
5320 ast_dump_context->print_indent();
5321 ast_dump_context->ostream() << "}";
5324 ast_dump_context->ostream() << std::endl;
5327 // Make a for statement.
5329 For_statement*
5330 Statement::make_for_statement(Block* init, Expression* cond, Block* post,
5331 Location location)
5333 return new For_statement(init, cond, post, location);
5336 // Class For_range_statement.
5338 // Traversal.
5341 For_range_statement::do_traverse(Traverse* traverse)
5343 if (this->index_var_ != NULL)
5345 if (this->traverse_expression(traverse, &this->index_var_)
5346 == TRAVERSE_EXIT)
5347 return TRAVERSE_EXIT;
5349 if (this->value_var_ != NULL)
5351 if (this->traverse_expression(traverse, &this->value_var_)
5352 == TRAVERSE_EXIT)
5353 return TRAVERSE_EXIT;
5355 if (this->traverse_expression(traverse, &this->range_) == TRAVERSE_EXIT)
5356 return TRAVERSE_EXIT;
5357 return this->statements_->traverse(traverse);
5360 // Lower a for range statement. For simplicity we lower this into a
5361 // for statement, which will then be lowered in turn to goto
5362 // statements.
5364 Statement*
5365 For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
5366 Statement_inserter*)
5368 Type* range_type = this->range_->type();
5369 if (range_type->points_to() != NULL
5370 && range_type->points_to()->array_type() != NULL
5371 && !range_type->points_to()->is_slice_type())
5372 range_type = range_type->points_to();
5374 Type* index_type;
5375 Type* value_type = NULL;
5376 if (range_type->array_type() != NULL)
5378 index_type = Type::lookup_integer_type("int");
5379 value_type = range_type->array_type()->element_type();
5381 else if (range_type->is_string_type())
5383 index_type = Type::lookup_integer_type("int");
5384 value_type = Type::lookup_integer_type("int32");
5386 else if (range_type->map_type() != NULL)
5388 index_type = range_type->map_type()->key_type();
5389 value_type = range_type->map_type()->val_type();
5391 else if (range_type->channel_type() != NULL)
5393 index_type = range_type->channel_type()->element_type();
5394 if (this->value_var_ != NULL)
5396 if (!this->value_var_->type()->is_error())
5397 this->report_error(_("too many variables for range clause "
5398 "with channel"));
5399 return Statement::make_error_statement(this->location());
5402 else
5404 this->report_error(_("range clause must have "
5405 "array, slice, string, map, or channel type"));
5406 return Statement::make_error_statement(this->location());
5409 Location loc = this->location();
5410 Block* temp_block = new Block(enclosing, loc);
5412 Named_object* range_object = NULL;
5413 Temporary_statement* range_temp = NULL;
5414 Var_expression* ve = this->range_->var_expression();
5415 if (ve != NULL)
5416 range_object = ve->named_object();
5417 else
5419 range_temp = Statement::make_temporary(NULL, this->range_, loc);
5420 temp_block->add_statement(range_temp);
5421 this->range_ = NULL;
5424 Temporary_statement* index_temp = Statement::make_temporary(index_type,
5425 NULL, loc);
5426 temp_block->add_statement(index_temp);
5428 Temporary_statement* value_temp = NULL;
5429 if (this->value_var_ != NULL)
5431 value_temp = Statement::make_temporary(value_type, NULL, loc);
5432 temp_block->add_statement(value_temp);
5435 Block* body = new Block(temp_block, loc);
5437 Block* init;
5438 Expression* cond;
5439 Block* iter_init;
5440 Block* post;
5442 // Arrange to do a loop appropriate for the type. We will produce
5443 // for INIT ; COND ; POST {
5444 // ITER_INIT
5445 // INDEX = INDEX_TEMP
5446 // VALUE = VALUE_TEMP // If there is a value
5447 // original statements
5448 // }
5450 if (range_type->is_slice_type())
5451 this->lower_range_slice(gogo, temp_block, body, range_object, range_temp,
5452 index_temp, value_temp, &init, &cond, &iter_init,
5453 &post);
5454 else if (range_type->array_type() != NULL)
5455 this->lower_range_array(gogo, temp_block, body, range_object, range_temp,
5456 index_temp, value_temp, &init, &cond, &iter_init,
5457 &post);
5458 else if (range_type->is_string_type())
5459 this->lower_range_string(gogo, temp_block, body, range_object, range_temp,
5460 index_temp, value_temp, &init, &cond, &iter_init,
5461 &post);
5462 else if (range_type->map_type() != NULL)
5463 this->lower_range_map(gogo, temp_block, body, range_object, range_temp,
5464 index_temp, value_temp, &init, &cond, &iter_init,
5465 &post);
5466 else if (range_type->channel_type() != NULL)
5467 this->lower_range_channel(gogo, temp_block, body, range_object, range_temp,
5468 index_temp, value_temp, &init, &cond, &iter_init,
5469 &post);
5470 else
5471 go_unreachable();
5473 if (iter_init != NULL)
5474 body->add_statement(Statement::make_block_statement(iter_init, loc));
5476 if (this->index_var_ != NULL)
5478 Statement* assign;
5479 Expression* index_ref =
5480 Expression::make_temporary_reference(index_temp, loc);
5481 if (this->value_var_ == NULL)
5482 assign = Statement::make_assignment(this->index_var_, index_ref, loc);
5483 else
5485 Expression_list* lhs = new Expression_list();
5486 lhs->push_back(this->index_var_);
5487 lhs->push_back(this->value_var_);
5489 Expression_list* rhs = new Expression_list();
5490 rhs->push_back(index_ref);
5491 rhs->push_back(Expression::make_temporary_reference(value_temp, loc));
5493 assign = Statement::make_tuple_assignment(lhs, rhs, loc);
5495 body->add_statement(assign);
5498 body->add_statement(Statement::make_block_statement(this->statements_, loc));
5500 body->set_end_location(this->statements_->end_location());
5502 For_statement* loop = Statement::make_for_statement(init, cond, post,
5503 this->location());
5504 loop->add_statements(body);
5505 loop->set_break_continue_labels(this->break_label_, this->continue_label_);
5507 temp_block->add_statement(loop);
5509 return Statement::make_block_statement(temp_block, loc);
5512 // Return a reference to the range, which may be in RANGE_OBJECT or in
5513 // RANGE_TEMP.
5515 Expression*
5516 For_range_statement::make_range_ref(Named_object* range_object,
5517 Temporary_statement* range_temp,
5518 Location loc)
5520 if (range_object != NULL)
5521 return Expression::make_var_reference(range_object, loc);
5522 else
5523 return Expression::make_temporary_reference(range_temp, loc);
5526 // Return a call to the predeclared function FUNCNAME passing a
5527 // reference to the temporary variable ARG.
5529 Expression*
5530 For_range_statement::call_builtin(Gogo* gogo, const char* funcname,
5531 Expression* arg,
5532 Location loc)
5534 Named_object* no = gogo->lookup_global(funcname);
5535 go_assert(no != NULL && no->is_function_declaration());
5536 Expression* func = Expression::make_func_reference(no, NULL, loc);
5537 Expression_list* params = new Expression_list();
5538 params->push_back(arg);
5539 return Expression::make_call(func, params, false, loc);
5542 // Lower a for range over an array.
5544 void
5545 For_range_statement::lower_range_array(Gogo* gogo,
5546 Block* enclosing,
5547 Block* body_block,
5548 Named_object* range_object,
5549 Temporary_statement* range_temp,
5550 Temporary_statement* index_temp,
5551 Temporary_statement* value_temp,
5552 Block** pinit,
5553 Expression** pcond,
5554 Block** piter_init,
5555 Block** ppost)
5557 Location loc = this->location();
5559 // The loop we generate:
5560 // len_temp := len(range)
5561 // for index_temp = 0; index_temp < len_temp; index_temp++ {
5562 // value_temp = range[index_temp]
5563 // index = index_temp
5564 // value = value_temp
5565 // original body
5566 // }
5568 // Set *PINIT to
5569 // var len_temp int
5570 // len_temp = len(range)
5571 // index_temp = 0
5573 Block* init = new Block(enclosing, loc);
5575 Expression* ref = this->make_range_ref(range_object, range_temp, loc);
5576 Expression* len_call = this->call_builtin(gogo, "len", ref, loc);
5577 Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(),
5578 len_call, loc);
5579 init->add_statement(len_temp);
5581 Expression* zexpr = Expression::make_integer_ul(0, NULL, loc);
5583 Temporary_reference_expression* tref =
5584 Expression::make_temporary_reference(index_temp, loc);
5585 tref->set_is_lvalue();
5586 Statement* s = Statement::make_assignment(tref, zexpr, loc);
5587 init->add_statement(s);
5589 *pinit = init;
5591 // Set *PCOND to
5592 // index_temp < len_temp
5594 ref = Expression::make_temporary_reference(index_temp, loc);
5595 Expression* ref2 = Expression::make_temporary_reference(len_temp, loc);
5596 Expression* lt = Expression::make_binary(OPERATOR_LT, ref, ref2, loc);
5598 *pcond = lt;
5600 // Set *PITER_INIT to
5601 // value_temp = range[index_temp]
5603 Block* iter_init = NULL;
5604 if (value_temp != NULL)
5606 iter_init = new Block(body_block, loc);
5608 ref = this->make_range_ref(range_object, range_temp, loc);
5609 Expression* ref2 = Expression::make_temporary_reference(index_temp, loc);
5610 Expression* index = Expression::make_index(ref, ref2, NULL, NULL, loc);
5612 tref = Expression::make_temporary_reference(value_temp, loc);
5613 tref->set_is_lvalue();
5614 s = Statement::make_assignment(tref, index, loc);
5616 iter_init->add_statement(s);
5618 *piter_init = iter_init;
5620 // Set *PPOST to
5621 // index_temp++
5623 Block* post = new Block(enclosing, loc);
5624 tref = Expression::make_temporary_reference(index_temp, loc);
5625 tref->set_is_lvalue();
5626 s = Statement::make_inc_statement(tref);
5627 post->add_statement(s);
5628 *ppost = post;
5631 // Lower a for range over a slice.
5633 void
5634 For_range_statement::lower_range_slice(Gogo* gogo,
5635 Block* enclosing,
5636 Block* body_block,
5637 Named_object* range_object,
5638 Temporary_statement* range_temp,
5639 Temporary_statement* index_temp,
5640 Temporary_statement* value_temp,
5641 Block** pinit,
5642 Expression** pcond,
5643 Block** piter_init,
5644 Block** ppost)
5646 Location loc = this->location();
5648 // The loop we generate:
5649 // for_temp := range
5650 // len_temp := len(for_temp)
5651 // for index_temp = 0; index_temp < len_temp; index_temp++ {
5652 // value_temp = for_temp[index_temp]
5653 // index = index_temp
5654 // value = value_temp
5655 // original body
5656 // }
5658 // Using for_temp means that we don't need to check bounds when
5659 // fetching range_temp[index_temp].
5661 // Set *PINIT to
5662 // range_temp := range
5663 // var len_temp int
5664 // len_temp = len(range_temp)
5665 // index_temp = 0
5667 Block* init = new Block(enclosing, loc);
5669 Expression* ref = this->make_range_ref(range_object, range_temp, loc);
5670 Temporary_statement* for_temp = Statement::make_temporary(NULL, ref, loc);
5671 init->add_statement(for_temp);
5673 ref = Expression::make_temporary_reference(for_temp, loc);
5674 Expression* len_call = this->call_builtin(gogo, "len", ref, loc);
5675 Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(),
5676 len_call, loc);
5677 init->add_statement(len_temp);
5679 Expression* zexpr = Expression::make_integer_ul(0, NULL, loc);
5681 Temporary_reference_expression* tref =
5682 Expression::make_temporary_reference(index_temp, loc);
5683 tref->set_is_lvalue();
5684 Statement* s = Statement::make_assignment(tref, zexpr, loc);
5685 init->add_statement(s);
5687 *pinit = init;
5689 // Set *PCOND to
5690 // index_temp < len_temp
5692 ref = Expression::make_temporary_reference(index_temp, loc);
5693 Expression* ref2 = Expression::make_temporary_reference(len_temp, loc);
5694 Expression* lt = Expression::make_binary(OPERATOR_LT, ref, ref2, loc);
5696 *pcond = lt;
5698 // Set *PITER_INIT to
5699 // value_temp = range[index_temp]
5701 Block* iter_init = NULL;
5702 if (value_temp != NULL)
5704 iter_init = new Block(body_block, loc);
5706 ref = Expression::make_temporary_reference(for_temp, loc);
5707 Expression* ref2 = Expression::make_temporary_reference(index_temp, loc);
5708 Expression* index = Expression::make_index(ref, ref2, NULL, NULL, loc);
5710 tref = Expression::make_temporary_reference(value_temp, loc);
5711 tref->set_is_lvalue();
5712 s = Statement::make_assignment(tref, index, loc);
5714 iter_init->add_statement(s);
5716 *piter_init = iter_init;
5718 // Set *PPOST to
5719 // index_temp++
5721 Block* post = new Block(enclosing, loc);
5722 tref = Expression::make_temporary_reference(index_temp, loc);
5723 tref->set_is_lvalue();
5724 s = Statement::make_inc_statement(tref);
5725 post->add_statement(s);
5726 *ppost = post;
5729 // Lower a for range over a string.
5731 void
5732 For_range_statement::lower_range_string(Gogo*,
5733 Block* enclosing,
5734 Block* body_block,
5735 Named_object* range_object,
5736 Temporary_statement* range_temp,
5737 Temporary_statement* index_temp,
5738 Temporary_statement* value_temp,
5739 Block** pinit,
5740 Expression** pcond,
5741 Block** piter_init,
5742 Block** ppost)
5744 Location loc = this->location();
5746 // The loop we generate:
5747 // var next_index_temp int
5748 // for index_temp = 0; ; index_temp = next_index_temp {
5749 // next_index_temp, value_temp = stringiter2(range, index_temp)
5750 // if next_index_temp == 0 {
5751 // break
5752 // }
5753 // index = index_temp
5754 // value = value_temp
5755 // original body
5756 // }
5758 // Set *PINIT to
5759 // var next_index_temp int
5760 // index_temp = 0
5762 Block* init = new Block(enclosing, loc);
5764 Temporary_statement* next_index_temp =
5765 Statement::make_temporary(index_temp->type(), NULL, loc);
5766 init->add_statement(next_index_temp);
5768 Expression* zexpr = Expression::make_integer_ul(0, NULL, loc);
5770 Temporary_reference_expression* ref =
5771 Expression::make_temporary_reference(index_temp, loc);
5772 ref->set_is_lvalue();
5773 Statement* s = Statement::make_assignment(ref, zexpr, loc);
5775 init->add_statement(s);
5776 *pinit = init;
5778 // The loop has no condition.
5780 *pcond = NULL;
5782 // Set *PITER_INIT to
5783 // next_index_temp = runtime.stringiter(range, index_temp)
5784 // or
5785 // next_index_temp, value_temp = runtime.stringiter2(range, index_temp)
5786 // followed by
5787 // if next_index_temp == 0 {
5788 // break
5789 // }
5791 Block* iter_init = new Block(body_block, loc);
5793 Expression* p1 = this->make_range_ref(range_object, range_temp, loc);
5794 Expression* p2 = Expression::make_temporary_reference(index_temp, loc);
5795 Call_expression* call = Runtime::make_call((value_temp == NULL
5796 ? Runtime::STRINGITER
5797 : Runtime::STRINGITER2),
5798 loc, 2, p1, p2);
5800 if (value_temp == NULL)
5802 ref = Expression::make_temporary_reference(next_index_temp, loc);
5803 ref->set_is_lvalue();
5804 s = Statement::make_assignment(ref, call, loc);
5806 else
5808 Expression_list* lhs = new Expression_list();
5810 ref = Expression::make_temporary_reference(next_index_temp, loc);
5811 ref->set_is_lvalue();
5812 lhs->push_back(ref);
5814 ref = Expression::make_temporary_reference(value_temp, loc);
5815 ref->set_is_lvalue();
5816 lhs->push_back(ref);
5818 Expression_list* rhs = new Expression_list();
5819 rhs->push_back(Expression::make_call_result(call, 0));
5820 rhs->push_back(Expression::make_call_result(call, 1));
5822 s = Statement::make_tuple_assignment(lhs, rhs, loc);
5824 iter_init->add_statement(s);
5826 ref = Expression::make_temporary_reference(next_index_temp, loc);
5827 zexpr = Expression::make_integer_ul(0, NULL, loc);
5828 Expression* equals = Expression::make_binary(OPERATOR_EQEQ, ref, zexpr, loc);
5830 Block* then_block = new Block(iter_init, loc);
5831 s = Statement::make_break_statement(this->break_label(), loc);
5832 then_block->add_statement(s);
5834 s = Statement::make_if_statement(equals, then_block, NULL, loc);
5835 iter_init->add_statement(s);
5837 *piter_init = iter_init;
5839 // Set *PPOST to
5840 // index_temp = next_index_temp
5842 Block* post = new Block(enclosing, loc);
5844 Temporary_reference_expression* lhs =
5845 Expression::make_temporary_reference(index_temp, loc);
5846 lhs->set_is_lvalue();
5847 Expression* rhs = Expression::make_temporary_reference(next_index_temp, loc);
5848 s = Statement::make_assignment(lhs, rhs, loc);
5850 post->add_statement(s);
5851 *ppost = post;
5854 // Lower a for range over a map.
5856 void
5857 For_range_statement::lower_range_map(Gogo*,
5858 Block* enclosing,
5859 Block* body_block,
5860 Named_object* range_object,
5861 Temporary_statement* range_temp,
5862 Temporary_statement* index_temp,
5863 Temporary_statement* value_temp,
5864 Block** pinit,
5865 Expression** pcond,
5866 Block** piter_init,
5867 Block** ppost)
5869 Location loc = this->location();
5871 // The runtime uses a struct to handle ranges over a map. The
5872 // struct is four pointers long. The first pointer is NULL when we
5873 // have completed the iteration.
5875 // The loop we generate:
5876 // var hiter map_iteration_struct
5877 // for mapiterinit(range, &hiter); hiter[0] != nil; mapiternext(&hiter) {
5878 // mapiter2(hiter, &index_temp, &value_temp)
5879 // index = index_temp
5880 // value = value_temp
5881 // original body
5882 // }
5884 // Set *PINIT to
5885 // var hiter map_iteration_struct
5886 // runtime.mapiterinit(range, &hiter)
5888 Block* init = new Block(enclosing, loc);
5890 Type* map_iteration_type = Runtime::map_iteration_type();
5891 Temporary_statement* hiter = Statement::make_temporary(map_iteration_type,
5892 NULL, loc);
5893 init->add_statement(hiter);
5895 Expression* p1 = this->make_range_ref(range_object, range_temp, loc);
5896 Expression* ref = Expression::make_temporary_reference(hiter, loc);
5897 Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
5898 Expression* call = Runtime::make_call(Runtime::MAPITERINIT, loc, 2, p1, p2);
5899 init->add_statement(Statement::make_statement(call, true));
5901 *pinit = init;
5903 // Set *PCOND to
5904 // hiter[0] != nil
5906 ref = Expression::make_temporary_reference(hiter, loc);
5907 Expression* zexpr = Expression::make_integer_ul(0, NULL, loc);
5908 Expression* index = Expression::make_index(ref, zexpr, NULL, NULL, loc);
5909 Expression* ne = Expression::make_binary(OPERATOR_NOTEQ, index,
5910 Expression::make_nil(loc),
5911 loc);
5912 *pcond = ne;
5914 // Set *PITER_INIT to
5915 // mapiter1(hiter, &index_temp)
5916 // or
5917 // mapiter2(hiter, &index_temp, &value_temp)
5919 Block* iter_init = new Block(body_block, loc);
5921 ref = Expression::make_temporary_reference(hiter, loc);
5922 p1 = Expression::make_unary(OPERATOR_AND, ref, loc);
5923 ref = Expression::make_temporary_reference(index_temp, loc);
5924 p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
5925 if (value_temp == NULL)
5926 call = Runtime::make_call(Runtime::MAPITER1, loc, 2, p1, p2);
5927 else
5929 ref = Expression::make_temporary_reference(value_temp, loc);
5930 Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
5931 call = Runtime::make_call(Runtime::MAPITER2, loc, 3, p1, p2, p3);
5933 iter_init->add_statement(Statement::make_statement(call, true));
5935 *piter_init = iter_init;
5937 // Set *PPOST to
5938 // mapiternext(&hiter)
5940 Block* post = new Block(enclosing, loc);
5942 ref = Expression::make_temporary_reference(hiter, loc);
5943 p1 = Expression::make_unary(OPERATOR_AND, ref, loc);
5944 call = Runtime::make_call(Runtime::MAPITERNEXT, loc, 1, p1);
5945 post->add_statement(Statement::make_statement(call, true));
5947 *ppost = post;
5950 // Lower a for range over a channel.
5952 void
5953 For_range_statement::lower_range_channel(Gogo*,
5954 Block*,
5955 Block* body_block,
5956 Named_object* range_object,
5957 Temporary_statement* range_temp,
5958 Temporary_statement* index_temp,
5959 Temporary_statement* value_temp,
5960 Block** pinit,
5961 Expression** pcond,
5962 Block** piter_init,
5963 Block** ppost)
5965 go_assert(value_temp == NULL);
5967 Location loc = this->location();
5969 // The loop we generate:
5970 // for {
5971 // index_temp, ok_temp = <-range
5972 // if !ok_temp {
5973 // break
5974 // }
5975 // index = index_temp
5976 // original body
5977 // }
5979 // We have no initialization code, no condition, and no post code.
5981 *pinit = NULL;
5982 *pcond = NULL;
5983 *ppost = NULL;
5985 // Set *PITER_INIT to
5986 // index_temp, ok_temp = <-range
5987 // if !ok_temp {
5988 // break
5989 // }
5991 Block* iter_init = new Block(body_block, loc);
5993 Temporary_statement* ok_temp =
5994 Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
5995 iter_init->add_statement(ok_temp);
5997 Expression* cref = this->make_range_ref(range_object, range_temp, loc);
5998 Temporary_reference_expression* iref =
5999 Expression::make_temporary_reference(index_temp, loc);
6000 iref->set_is_lvalue();
6001 Temporary_reference_expression* oref =
6002 Expression::make_temporary_reference(ok_temp, loc);
6003 oref->set_is_lvalue();
6004 Statement* s = Statement::make_tuple_receive_assignment(iref, oref, cref,
6005 loc);
6006 iter_init->add_statement(s);
6008 Block* then_block = new Block(iter_init, loc);
6009 s = Statement::make_break_statement(this->break_label(), loc);
6010 then_block->add_statement(s);
6012 oref = Expression::make_temporary_reference(ok_temp, loc);
6013 Expression* cond = Expression::make_unary(OPERATOR_NOT, oref, loc);
6014 s = Statement::make_if_statement(cond, then_block, NULL, loc);
6015 iter_init->add_statement(s);
6017 *piter_init = iter_init;
6020 // Return the break LABEL_EXPR.
6022 Unnamed_label*
6023 For_range_statement::break_label()
6025 if (this->break_label_ == NULL)
6026 this->break_label_ = new Unnamed_label(this->location());
6027 return this->break_label_;
6030 // Return the continue LABEL_EXPR.
6032 Unnamed_label*
6033 For_range_statement::continue_label()
6035 if (this->continue_label_ == NULL)
6036 this->continue_label_ = new Unnamed_label(this->location());
6037 return this->continue_label_;
6040 // Dump the AST representation for a for range statement.
6042 void
6043 For_range_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
6046 ast_dump_context->print_indent();
6047 ast_dump_context->ostream() << "for ";
6048 ast_dump_context->dump_expression(this->index_var_);
6049 if (this->value_var_ != NULL)
6051 ast_dump_context->ostream() << ", ";
6052 ast_dump_context->dump_expression(this->value_var_);
6055 ast_dump_context->ostream() << " = range ";
6056 ast_dump_context->dump_expression(this->range_);
6057 if (ast_dump_context->dump_subblocks())
6059 ast_dump_context->ostream() << " {" << std::endl;
6061 ast_dump_context->indent();
6063 ast_dump_context->dump_block(this->statements_);
6065 ast_dump_context->unindent();
6066 ast_dump_context->print_indent();
6067 ast_dump_context->ostream() << "}";
6069 ast_dump_context->ostream() << std::endl;
6072 // Make a for statement with a range clause.
6074 For_range_statement*
6075 Statement::make_for_range_statement(Expression* index_var,
6076 Expression* value_var,
6077 Expression* range,
6078 Location location)
6080 return new For_range_statement(index_var, value_var, range, location);