net/internal/socktest: build sys_unix.go on AIX
[official-gcc.git] / gcc / go / gofrontend / statements.cc
blobe59217672866ce70b9501c71d6a7debe158eeb40
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 "go-diagnostics.h"
11 #include "types.h"
12 #include "expressions.h"
13 #include "gogo.h"
14 #include "runtime.h"
15 #include "backend.h"
16 #include "statements.h"
17 #include "ast-dump.h"
19 // Class Statement.
21 Statement::Statement(Statement_classification classification,
22 Location location)
23 : classification_(classification), location_(location)
27 Statement::~Statement()
31 // Traverse the tree. The work of walking the components is handled
32 // by the subclasses.
34 int
35 Statement::traverse(Block* block, size_t* pindex, Traverse* traverse)
37 if (this->classification_ == STATEMENT_ERROR)
38 return TRAVERSE_CONTINUE;
40 unsigned int traverse_mask = traverse->traverse_mask();
42 if ((traverse_mask & Traverse::traverse_statements) != 0)
44 int t = traverse->statement(block, pindex, this);
45 if (t == TRAVERSE_EXIT)
46 return TRAVERSE_EXIT;
47 else if (t == TRAVERSE_SKIP_COMPONENTS)
48 return TRAVERSE_CONTINUE;
51 // No point in checking traverse_mask here--a statement may contain
52 // other blocks or statements, and if we got here we always want to
53 // walk them.
54 return this->do_traverse(traverse);
57 // Traverse the contents of a statement.
59 int
60 Statement::traverse_contents(Traverse* traverse)
62 return this->do_traverse(traverse);
65 // Traverse assignments.
67 bool
68 Statement::traverse_assignments(Traverse_assignments* tassign)
70 if (this->classification_ == STATEMENT_ERROR)
71 return false;
72 return this->do_traverse_assignments(tassign);
75 // Traverse an expression in a statement. This is a helper function
76 // for child classes.
78 int
79 Statement::traverse_expression(Traverse* traverse, Expression** expr)
81 if ((traverse->traverse_mask()
82 & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0)
83 return TRAVERSE_CONTINUE;
84 return Expression::traverse(expr, traverse);
87 // Traverse an expression list in a statement. This is a helper
88 // function for child classes.
90 int
91 Statement::traverse_expression_list(Traverse* traverse,
92 Expression_list* expr_list)
94 if (expr_list == NULL)
95 return TRAVERSE_CONTINUE;
96 if ((traverse->traverse_mask()
97 & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0)
98 return TRAVERSE_CONTINUE;
99 return expr_list->traverse(traverse);
102 // Traverse a type in a statement. This is a helper function for
103 // child classes.
106 Statement::traverse_type(Traverse* traverse, Type* type)
108 if ((traverse->traverse_mask()
109 & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0)
110 return TRAVERSE_CONTINUE;
111 return Type::traverse(type, traverse);
114 // Set type information for unnamed constants. This is really done by
115 // the child class.
117 void
118 Statement::determine_types()
120 this->do_determine_types();
123 // If this is a thunk statement, return it.
125 Thunk_statement*
126 Statement::thunk_statement()
128 Thunk_statement* ret = this->convert<Thunk_statement, STATEMENT_GO>();
129 if (ret == NULL)
130 ret = this->convert<Thunk_statement, STATEMENT_DEFER>();
131 return ret;
134 // Convert a Statement to the backend representation. This is really
135 // done by the child class.
137 Bstatement*
138 Statement::get_backend(Translate_context* context)
140 if (this->classification_ == STATEMENT_ERROR)
141 return context->backend()->error_statement();
142 return this->do_get_backend(context);
145 // Dump AST representation for a statement to a dump context.
147 void
148 Statement::dump_statement(Ast_dump_context* ast_dump_context) const
150 this->do_dump_statement(ast_dump_context);
153 // Note that this statement is erroneous. This is called by children
154 // when they discover an error.
156 void
157 Statement::set_is_error()
159 this->classification_ = STATEMENT_ERROR;
162 // For children to call to report an error conveniently.
164 void
165 Statement::report_error(const char* msg)
167 go_error_at(this->location_, "%s", msg);
168 this->set_is_error();
171 // An error statement, used to avoid crashing after we report an
172 // error.
174 class Error_statement : public Statement
176 public:
177 Error_statement(Location location)
178 : Statement(STATEMENT_ERROR, location)
181 protected:
183 do_traverse(Traverse*)
184 { return TRAVERSE_CONTINUE; }
186 Bstatement*
187 do_get_backend(Translate_context*)
188 { go_unreachable(); }
190 void
191 do_dump_statement(Ast_dump_context*) const;
195 // Helper to tack on available source position information
196 // at the end of a statement.
198 static std::string
199 dsuffix(Location location)
201 std::string lstr = Linemap::location_to_string(location);
202 if (lstr == "")
203 return lstr;
204 std::string rval(" // ");
205 rval += lstr;
206 return rval;
209 // Dump the AST representation for an error statement.
211 void
212 Error_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
214 ast_dump_context->print_indent();
215 ast_dump_context->ostream() << "Error statement" << std::endl;
218 // Make an error statement.
220 Statement*
221 Statement::make_error_statement(Location location)
223 return new Error_statement(location);
226 // Class Variable_declaration_statement.
228 Variable_declaration_statement::Variable_declaration_statement(
229 Named_object* var)
230 : Statement(STATEMENT_VARIABLE_DECLARATION, var->var_value()->location()),
231 var_(var)
235 // We don't actually traverse the variable here; it was traversed
236 // while traversing the Block.
239 Variable_declaration_statement::do_traverse(Traverse*)
241 return TRAVERSE_CONTINUE;
244 // Traverse the assignments in a variable declaration. Note that this
245 // traversal is different from the usual traversal.
247 bool
248 Variable_declaration_statement::do_traverse_assignments(
249 Traverse_assignments* tassign)
251 tassign->initialize_variable(this->var_);
252 return true;
255 // Lower the variable's initialization expression.
257 Statement*
258 Variable_declaration_statement::do_lower(Gogo* gogo, Named_object* function,
259 Block*, Statement_inserter* inserter)
261 this->var_->var_value()->lower_init_expression(gogo, function, inserter);
262 return this;
265 // Flatten the variable's initialization expression.
267 Statement*
268 Variable_declaration_statement::do_flatten(Gogo* gogo, Named_object* function,
269 Block*, Statement_inserter* inserter)
271 Variable* var = this->var_->var_value();
272 if (var->type()->is_error_type()
273 || (var->init() != NULL
274 && var->init()->is_error_expression()))
276 go_assert(saw_errors());
277 return Statement::make_error_statement(this->location());
279 this->var_->var_value()->flatten_init_expression(gogo, function, inserter);
280 return this;
283 // Convert a variable declaration to the backend representation.
285 Bstatement*
286 Variable_declaration_statement::do_get_backend(Translate_context* context)
288 Bfunction* bfunction = context->function()->func_value()->get_decl();
289 Variable* var = this->var_->var_value();
290 Bvariable* bvar = this->var_->get_backend_variable(context->gogo(),
291 context->function());
292 Bexpression* binit = var->get_init(context->gogo(), context->function());
294 if (!var->is_in_heap())
296 go_assert(binit != NULL);
297 return context->backend()->init_statement(bfunction, bvar, binit);
300 // Something takes the address of this variable, so the value is
301 // stored in the heap. Initialize it to newly allocated memory
302 // space, and assign the initial value to the new space.
303 Location loc = this->location();
304 Named_object* newfn = context->gogo()->lookup_global("new");
305 go_assert(newfn != NULL && newfn->is_function_declaration());
306 Expression* func = Expression::make_func_reference(newfn, NULL, loc);
307 Expression_list* params = new Expression_list();
308 params->push_back(Expression::make_type(var->type(), loc));
309 Expression* call = Expression::make_call(func, params, false, loc);
310 context->gogo()->lower_expression(context->function(), NULL, &call);
311 Temporary_statement* temp = Statement::make_temporary(NULL, call, loc);
312 Bstatement* btemp = temp->get_backend(context);
314 Bstatement* set = NULL;
315 if (binit != NULL)
317 Expression* e = Expression::make_temporary_reference(temp, loc);
318 e = Expression::make_unary(OPERATOR_MULT, e, loc);
319 Bexpression* be = e->get_backend(context);
320 set = context->backend()->assignment_statement(bfunction, be, binit, loc);
323 Expression* ref = Expression::make_temporary_reference(temp, loc);
324 Bexpression* bref = ref->get_backend(context);
325 Bstatement* sinit = context->backend()->init_statement(bfunction, bvar, bref);
327 std::vector<Bstatement*> stats;
328 stats.reserve(3);
329 stats.push_back(btemp);
330 if (set != NULL)
331 stats.push_back(set);
332 stats.push_back(sinit);
333 return context->backend()->statement_list(stats);
336 // Dump the AST representation for a variable declaration.
338 void
339 Variable_declaration_statement::do_dump_statement(
340 Ast_dump_context* ast_dump_context) const
342 ast_dump_context->print_indent();
344 go_assert(var_->is_variable());
345 ast_dump_context->ostream() << "var " << this->var_->name() << " ";
346 Variable* var = this->var_->var_value();
347 if (var->has_type())
349 ast_dump_context->dump_type(var->type());
350 ast_dump_context->ostream() << " ";
352 if (var->init() != NULL)
354 ast_dump_context->ostream() << "= ";
355 ast_dump_context->dump_expression(var->init());
357 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
360 // Make a variable declaration.
362 Statement*
363 Statement::make_variable_declaration(Named_object* var)
365 return new Variable_declaration_statement(var);
368 // Class Temporary_statement.
370 // Return the type of the temporary variable.
372 Type*
373 Temporary_statement::type() const
375 Type* type = this->type_ != NULL ? this->type_ : this->init_->type();
377 // Temporary variables cannot have a void type.
378 if (type->is_void_type())
380 go_assert(saw_errors());
381 return Type::make_error_type();
383 return type;
386 // Traversal.
389 Temporary_statement::do_traverse(Traverse* traverse)
391 if (this->type_ != NULL
392 && this->traverse_type(traverse, this->type_) == TRAVERSE_EXIT)
393 return TRAVERSE_EXIT;
394 if (this->init_ == NULL)
395 return TRAVERSE_CONTINUE;
396 else
397 return this->traverse_expression(traverse, &this->init_);
400 // Traverse assignments.
402 bool
403 Temporary_statement::do_traverse_assignments(Traverse_assignments* tassign)
405 if (this->init_ == NULL)
406 return false;
407 tassign->value(&this->init_, true, true);
408 return true;
411 // Determine types.
413 void
414 Temporary_statement::do_determine_types()
416 if (this->type_ != NULL && this->type_->is_abstract())
417 this->type_ = this->type_->make_non_abstract_type();
419 if (this->init_ != NULL)
421 if (this->type_ == NULL)
422 this->init_->determine_type_no_context();
423 else
425 Type_context context(this->type_, false);
426 this->init_->determine_type(&context);
430 if (this->type_ == NULL)
432 this->type_ = this->init_->type();
433 go_assert(!this->type_->is_abstract());
437 // Check types.
439 void
440 Temporary_statement::do_check_types(Gogo*)
442 if (this->type_ != NULL && this->init_ != NULL)
444 std::string reason;
445 if (!Type::are_assignable(this->type_, this->init_->type(), &reason))
447 if (reason.empty())
448 go_error_at(this->location(), "incompatible types in assignment");
449 else
450 go_error_at(this->location(), "incompatible types in assignment (%s)",
451 reason.c_str());
452 this->set_is_error();
457 // Flatten a temporary statement: add another temporary when it might
458 // be needed for interface conversion.
460 Statement*
461 Temporary_statement::do_flatten(Gogo*, Named_object*, Block*,
462 Statement_inserter* inserter)
464 if (this->type()->is_error_type()
465 || (this->init_ != NULL
466 && this->init_->is_error_expression()))
468 go_assert(saw_errors());
469 return Statement::make_error_statement(this->location());
472 if (this->type_ != NULL
473 && this->init_ != NULL
474 && !Type::are_identical(this->type_, this->init_->type(), false, NULL)
475 && this->init_->type()->interface_type() != NULL
476 && !this->init_->is_variable())
478 Temporary_statement *temp =
479 Statement::make_temporary(NULL, this->init_, this->location());
480 inserter->insert(temp);
481 this->init_ = Expression::make_temporary_reference(temp,
482 this->location());
484 return this;
487 // Convert to backend representation.
489 Bstatement*
490 Temporary_statement::do_get_backend(Translate_context* context)
492 go_assert(this->bvariable_ == NULL);
494 Named_object* function = context->function();
495 go_assert(function != NULL);
496 Bfunction* bfunction = function->func_value()->get_decl();
497 Btype* btype = this->type()->get_backend(context->gogo());
499 Bexpression* binit;
500 if (this->init_ == NULL)
501 binit = NULL;
502 else if (this->type_ == NULL)
503 binit = this->init_->get_backend(context);
504 else
506 Expression* init = Expression::convert_for_assignment(context->gogo(),
507 this->type_,
508 this->init_,
509 this->location());
510 binit = init->get_backend(context);
513 if (binit != NULL)
514 binit = context->backend()->convert_expression(btype, binit,
515 this->location());
517 Bstatement* statement;
518 this->bvariable_ =
519 context->backend()->temporary_variable(bfunction, context->bblock(),
520 btype, binit,
521 this->is_address_taken_,
522 this->location(), &statement);
523 return statement;
526 // Return the backend variable.
528 Bvariable*
529 Temporary_statement::get_backend_variable(Translate_context* context) const
531 if (this->bvariable_ == NULL)
533 go_assert(saw_errors());
534 return context->backend()->error_variable();
536 return this->bvariable_;
539 // Dump the AST represemtation for a temporary statement
541 void
542 Temporary_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
544 ast_dump_context->print_indent();
545 ast_dump_context->dump_temp_variable_name(this);
546 if (this->type_ != NULL)
548 ast_dump_context->ostream() << " ";
549 ast_dump_context->dump_type(this->type_);
551 if (this->init_ != NULL)
553 ast_dump_context->ostream() << " = ";
554 ast_dump_context->dump_expression(this->init_);
556 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
559 // Make and initialize a temporary variable in BLOCK.
561 Temporary_statement*
562 Statement::make_temporary(Type* type, Expression* init,
563 Location location)
565 return new Temporary_statement(type, init, location);
568 // The Move_subexpressions class is used to move all top-level
569 // subexpressions of an expression. This is used for things like
570 // index expressions in which we must evaluate the index value before
571 // it can be changed by a multiple assignment.
573 class Move_subexpressions : public Traverse
575 public:
576 Move_subexpressions(int skip, Block* block)
577 : Traverse(traverse_expressions),
578 skip_(skip), block_(block)
581 protected:
583 expression(Expression**);
585 private:
586 // The number of subexpressions to skip moving. This is used to
587 // avoid moving the array itself, as we only need to move the index.
588 int skip_;
589 // The block where new temporary variables should be added.
590 Block* block_;
594 Move_subexpressions::expression(Expression** pexpr)
596 if (this->skip_ > 0)
597 --this->skip_;
598 else if ((*pexpr)->temporary_reference_expression() == NULL
599 && !(*pexpr)->is_nil_expression()
600 && !(*pexpr)->is_constant())
602 Location loc = (*pexpr)->location();
603 Temporary_statement* temp = Statement::make_temporary(NULL, *pexpr, loc);
604 this->block_->add_statement(temp);
605 *pexpr = Expression::make_temporary_reference(temp, loc);
607 // We only need to move top-level subexpressions.
608 return TRAVERSE_SKIP_COMPONENTS;
611 // The Move_ordered_evals class is used to find any subexpressions of
612 // an expression that have an evaluation order dependency. It creates
613 // temporary variables to hold them.
615 class Move_ordered_evals : public Traverse
617 public:
618 Move_ordered_evals(Block* block)
619 : Traverse(traverse_expressions),
620 block_(block)
623 protected:
625 expression(Expression**);
627 private:
628 // The block where new temporary variables should be added.
629 Block* block_;
633 Move_ordered_evals::expression(Expression** pexpr)
635 // We have to look at subexpressions first.
636 if ((*pexpr)->traverse_subexpressions(this) == TRAVERSE_EXIT)
637 return TRAVERSE_EXIT;
639 int i;
640 if ((*pexpr)->must_eval_subexpressions_in_order(&i))
642 Move_subexpressions ms(i, this->block_);
643 if ((*pexpr)->traverse_subexpressions(&ms) == TRAVERSE_EXIT)
644 return TRAVERSE_EXIT;
647 if ((*pexpr)->must_eval_in_order())
649 Call_expression* call = (*pexpr)->call_expression();
650 if (call != NULL && call->is_multi_value_arg())
652 // A call expression which returns multiple results as an argument
653 // to another call must be handled specially. We can't create a
654 // temporary because there is no type to give it. Instead, group
655 // the caller and this multi-valued call argument and use a temporary
656 // variable to hold them.
657 return TRAVERSE_SKIP_COMPONENTS;
660 Location loc = (*pexpr)->location();
661 Temporary_statement* temp = Statement::make_temporary(NULL, *pexpr, loc);
662 this->block_->add_statement(temp);
663 *pexpr = Expression::make_temporary_reference(temp, loc);
665 return TRAVERSE_SKIP_COMPONENTS;
668 // Class Assignment_statement.
670 // Traversal.
673 Assignment_statement::do_traverse(Traverse* traverse)
675 if (this->traverse_expression(traverse, &this->lhs_) == TRAVERSE_EXIT)
676 return TRAVERSE_EXIT;
677 return this->traverse_expression(traverse, &this->rhs_);
680 bool
681 Assignment_statement::do_traverse_assignments(Traverse_assignments* tassign)
683 tassign->assignment(&this->lhs_, &this->rhs_);
684 return true;
687 // Lower an assignment to a map index expression to a runtime function
688 // call.
690 Statement*
691 Assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
692 Statement_inserter*)
694 Map_index_expression* mie = this->lhs_->map_index_expression();
695 if (mie != NULL)
697 Location loc = this->location();
699 Expression* map = mie->map();
700 Map_type* mt = map->type()->map_type();
701 if (mt == NULL)
703 go_assert(saw_errors());
704 return Statement::make_error_statement(loc);
707 Block* b = new Block(enclosing, loc);
709 // Move out any subexpressions on the left hand side to make
710 // sure that functions are called in the required order.
711 Move_ordered_evals moe(b);
712 mie->traverse_subexpressions(&moe);
714 // Copy the key into a temporary so that we can take its address
715 // without pushing the value onto the heap.
717 // var key_temp KEY_TYPE = MAP_INDEX
718 Temporary_statement* key_temp = Statement::make_temporary(mt->key_type(),
719 mie->index(),
720 loc);
721 b->add_statement(key_temp);
723 // Copy the value into a temporary to ensure that it is
724 // evaluated before we add the key to the map. This may matter
725 // if the value is itself a reference to the map.
727 // var val_temp VAL_TYPE = RHS
728 Temporary_statement* val_temp = Statement::make_temporary(mt->val_type(),
729 this->rhs_,
730 loc);
731 b->add_statement(val_temp);
733 // *mapassign(TYPE, MAP, &key_temp) = RHS
734 Expression* a1 = Expression::make_type_descriptor(mt, loc);
735 Expression* a2 = mie->map();
736 Temporary_reference_expression* ref =
737 Expression::make_temporary_reference(key_temp, loc);
738 Expression* a3 = Expression::make_unary(OPERATOR_AND, ref, loc);
739 Expression* call = Runtime::make_call(Runtime::MAPASSIGN, loc, 3,
740 a1, a2, a3);
741 Type* ptrval_type = Type::make_pointer_type(mt->val_type());
742 call = Expression::make_cast(ptrval_type, call, loc);
743 Expression* indir = Expression::make_unary(OPERATOR_MULT, call, loc);
744 ref = Expression::make_temporary_reference(val_temp, loc);
745 b->add_statement(Statement::make_assignment(indir, ref, loc));
747 return Statement::make_block_statement(b, loc);
750 return this;
753 // Set types for the assignment.
755 void
756 Assignment_statement::do_determine_types()
758 this->lhs_->determine_type_no_context();
759 Type* rhs_context_type = this->lhs_->type();
760 if (rhs_context_type->is_sink_type())
761 rhs_context_type = NULL;
762 Type_context context(rhs_context_type, false);
763 this->rhs_->determine_type(&context);
766 // Check types for an assignment.
768 void
769 Assignment_statement::do_check_types(Gogo*)
771 // The left hand side must be either addressable, a map index
772 // expression, or the blank identifier.
773 if (!this->lhs_->is_addressable()
774 && this->lhs_->map_index_expression() == NULL
775 && !this->lhs_->is_sink_expression())
777 if (!this->lhs_->type()->is_error())
778 this->report_error(_("invalid left hand side of assignment"));
779 return;
782 Type* lhs_type = this->lhs_->type();
783 Type* rhs_type = this->rhs_->type();
785 // Invalid assignment of nil to the blank identifier.
786 if (lhs_type->is_sink_type()
787 && rhs_type->is_nil_type())
789 this->report_error(_("use of untyped nil"));
790 return;
793 std::string reason;
794 if (!Type::are_assignable(lhs_type, rhs_type, &reason))
796 if (reason.empty())
797 go_error_at(this->location(), "incompatible types in assignment");
798 else
799 go_error_at(this->location(), "incompatible types in assignment (%s)",
800 reason.c_str());
801 this->set_is_error();
804 if (lhs_type->is_error() || rhs_type->is_error())
805 this->set_is_error();
808 // Flatten an assignment statement. We may need a temporary for
809 // interface conversion.
811 Statement*
812 Assignment_statement::do_flatten(Gogo*, Named_object*, Block*,
813 Statement_inserter* inserter)
815 if (this->lhs_->is_error_expression()
816 || this->lhs_->type()->is_error_type()
817 || this->rhs_->is_error_expression()
818 || this->rhs_->type()->is_error_type())
820 go_assert(saw_errors());
821 return Statement::make_error_statement(this->location());
824 if (!this->lhs_->is_sink_expression()
825 && !Type::are_identical(this->lhs_->type(), this->rhs_->type(),
826 false, NULL)
827 && this->rhs_->type()->interface_type() != NULL
828 && !this->rhs_->is_variable())
830 Temporary_statement* temp =
831 Statement::make_temporary(NULL, this->rhs_, this->location());
832 inserter->insert(temp);
833 this->rhs_ = Expression::make_temporary_reference(temp,
834 this->location());
836 return this;
840 // Helper class to locate a root Var_expression within an expression
841 // tree and mark it as being in an "lvalue" or assignment
842 // context. Examples:
844 // x, y = 40, foo(w)
845 // x[2] = bar(v)
846 // x.z.w[blah(v + u)], y.another = 2, 3
848 // In the code above, vars "x" and "y" appear in lvalue / assignment
849 // context, whereas the other vars "v", "u", etc are in rvalue context.
851 // Note: at the moment the Var_expression version of "do_copy()"
852 // defaults to returning the original object, not a new object,
853 // meaning that a given Var_expression can be referenced from more
854 // than one place in the tree. This means that when we want to mark a
855 // Var_expression as having lvalue semantics, we need to make a copy
856 // of it. Example:
858 // mystruct.myfield += 42
860 // When this is lowered to eliminate the += operator, we get a tree
862 // mystruct.myfield = mystruct.field + 42
864 // in which the "mystruct" same Var_expression is referenced on both
865 // LHS and RHS subtrees. This in turn means that if we try to mark the
866 // LHS Var_expression the RHS Var_expression will also be marked. To
867 // address this issue, the code below clones any var_expression before
868 // applying an lvalue marking.
871 class Mark_lvalue_varexprs : public Traverse
873 public:
874 Mark_lvalue_varexprs()
875 : Traverse(traverse_expressions)
878 protected:
880 expression(Expression**);
882 private:
885 int Mark_lvalue_varexprs::expression(Expression** ppexpr)
887 Expression* e = *ppexpr;
889 Var_expression* ve = e->var_expression();
890 if (ve)
892 ve = new Var_expression(ve->named_object(), ve->location());
893 ve->set_in_lvalue_pos();
894 *ppexpr = ve;
895 return TRAVERSE_EXIT;
898 Field_reference_expression* fre = e->field_reference_expression();
899 if (fre != NULL)
900 return TRAVERSE_CONTINUE;
902 Array_index_expression* aie = e->array_index_expression();
903 if (aie != NULL)
905 Mark_lvalue_varexprs mlve;
906 aie->set_is_lvalue();
907 aie->array()->traverse_subexpressions(&mlve);
908 return TRAVERSE_EXIT;
911 Unary_expression* ue = e->unary_expression();
912 if (ue && ue->op() == OPERATOR_MULT)
913 return TRAVERSE_CONTINUE;
915 Type_conversion_expression* ce = e->conversion_expression();
916 if (ce)
917 return TRAVERSE_CONTINUE;
919 Temporary_reference_expression* tre =
920 e->temporary_reference_expression();
921 if (tre)
923 tre = new Temporary_reference_expression(tre->statement(),
924 tre->location());
925 *ppexpr = tre;
926 tre->set_is_lvalue();
927 return TRAVERSE_EXIT;
930 return TRAVERSE_EXIT;
933 // Convert an assignment statement to the backend representation.
935 Bstatement*
936 Assignment_statement::do_get_backend(Translate_context* context)
938 if (this->lhs_->is_sink_expression())
940 Bexpression* rhs = this->rhs_->get_backend(context);
941 Bfunction* bfunction = context->function()->func_value()->get_decl();
942 return context->backend()->expression_statement(bfunction, rhs);
945 Mark_lvalue_varexprs mlve;
946 Expression::traverse(&this->lhs_, &mlve);
948 Bexpression* lhs = this->lhs_->get_backend(context);
949 Expression* conv =
950 Expression::convert_for_assignment(context->gogo(), this->lhs_->type(),
951 this->rhs_, this->location());
952 Bexpression* rhs = conv->get_backend(context);
953 Bfunction* bfunction = context->function()->func_value()->get_decl();
954 return context->backend()->assignment_statement(bfunction, lhs, rhs,
955 this->location());
958 // Dump the AST representation for an assignment statement.
960 void
961 Assignment_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
962 const
964 ast_dump_context->print_indent();
965 ast_dump_context->dump_expression(this->lhs_);
966 ast_dump_context->ostream() << " = " ;
967 ast_dump_context->dump_expression(this->rhs_);
968 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
971 // Make an assignment statement.
973 Statement*
974 Statement::make_assignment(Expression* lhs, Expression* rhs,
975 Location location)
977 return new Assignment_statement(lhs, rhs, location);
980 // An assignment operation statement.
982 class Assignment_operation_statement : public Statement
984 public:
985 Assignment_operation_statement(Operator op, Expression* lhs, Expression* rhs,
986 Location location)
987 : Statement(STATEMENT_ASSIGNMENT_OPERATION, location),
988 op_(op), lhs_(lhs), rhs_(rhs)
991 protected:
993 do_traverse(Traverse*);
995 bool
996 do_traverse_assignments(Traverse_assignments*)
997 { go_unreachable(); }
999 Statement*
1000 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1002 Bstatement*
1003 do_get_backend(Translate_context*)
1004 { go_unreachable(); }
1006 void
1007 do_dump_statement(Ast_dump_context*) const;
1009 private:
1010 // The operator (OPERATOR_PLUSEQ, etc.).
1011 Operator op_;
1012 // Left hand side.
1013 Expression* lhs_;
1014 // Right hand side.
1015 Expression* rhs_;
1018 // Traversal.
1021 Assignment_operation_statement::do_traverse(Traverse* traverse)
1023 if (this->traverse_expression(traverse, &this->lhs_) == TRAVERSE_EXIT)
1024 return TRAVERSE_EXIT;
1025 return this->traverse_expression(traverse, &this->rhs_);
1028 // Lower an assignment operation statement to a regular assignment
1029 // statement.
1031 Statement*
1032 Assignment_operation_statement::do_lower(Gogo*, Named_object*,
1033 Block* enclosing, Statement_inserter*)
1035 Location loc = this->location();
1037 // We have to evaluate the left hand side expression only once. We
1038 // do this by moving out any expression with side effects.
1039 Block* b = new Block(enclosing, loc);
1040 Move_ordered_evals moe(b);
1041 this->lhs_->traverse_subexpressions(&moe);
1043 Expression* lval = this->lhs_->copy();
1045 Operator op;
1046 switch (this->op_)
1048 case OPERATOR_PLUSEQ:
1049 op = OPERATOR_PLUS;
1050 break;
1051 case OPERATOR_MINUSEQ:
1052 op = OPERATOR_MINUS;
1053 break;
1054 case OPERATOR_OREQ:
1055 op = OPERATOR_OR;
1056 break;
1057 case OPERATOR_XOREQ:
1058 op = OPERATOR_XOR;
1059 break;
1060 case OPERATOR_MULTEQ:
1061 op = OPERATOR_MULT;
1062 break;
1063 case OPERATOR_DIVEQ:
1064 op = OPERATOR_DIV;
1065 break;
1066 case OPERATOR_MODEQ:
1067 op = OPERATOR_MOD;
1068 break;
1069 case OPERATOR_LSHIFTEQ:
1070 op = OPERATOR_LSHIFT;
1071 break;
1072 case OPERATOR_RSHIFTEQ:
1073 op = OPERATOR_RSHIFT;
1074 break;
1075 case OPERATOR_ANDEQ:
1076 op = OPERATOR_AND;
1077 break;
1078 case OPERATOR_BITCLEAREQ:
1079 op = OPERATOR_BITCLEAR;
1080 break;
1081 default:
1082 go_unreachable();
1085 Expression* binop = Expression::make_binary(op, lval, this->rhs_, loc);
1086 Statement* s = Statement::make_assignment(this->lhs_, binop, loc);
1087 if (b->statements()->empty())
1089 delete b;
1090 return s;
1092 else
1094 b->add_statement(s);
1095 return Statement::make_block_statement(b, loc);
1099 // Dump the AST representation for an assignment operation statement
1101 void
1102 Assignment_operation_statement::do_dump_statement(
1103 Ast_dump_context* ast_dump_context) const
1105 ast_dump_context->print_indent();
1106 ast_dump_context->dump_expression(this->lhs_);
1107 ast_dump_context->dump_operator(this->op_);
1108 ast_dump_context->dump_expression(this->rhs_);
1109 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
1112 // Make an assignment operation statement.
1114 Statement*
1115 Statement::make_assignment_operation(Operator op, Expression* lhs,
1116 Expression* rhs, Location location)
1118 return new Assignment_operation_statement(op, lhs, rhs, location);
1121 // A tuple assignment statement. This differs from an assignment
1122 // statement in that the right-hand-side expressions are evaluated in
1123 // parallel.
1125 class Tuple_assignment_statement : public Statement
1127 public:
1128 Tuple_assignment_statement(Expression_list* lhs, Expression_list* rhs,
1129 Location location)
1130 : Statement(STATEMENT_TUPLE_ASSIGNMENT, location),
1131 lhs_(lhs), rhs_(rhs)
1134 protected:
1136 do_traverse(Traverse* traverse);
1138 bool
1139 do_traverse_assignments(Traverse_assignments*)
1140 { go_unreachable(); }
1142 Statement*
1143 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1145 Bstatement*
1146 do_get_backend(Translate_context*)
1147 { go_unreachable(); }
1149 void
1150 do_dump_statement(Ast_dump_context*) const;
1152 private:
1153 // Left hand side--a list of lvalues.
1154 Expression_list* lhs_;
1155 // Right hand side--a list of rvalues.
1156 Expression_list* rhs_;
1159 // Traversal.
1162 Tuple_assignment_statement::do_traverse(Traverse* traverse)
1164 if (this->traverse_expression_list(traverse, this->lhs_) == TRAVERSE_EXIT)
1165 return TRAVERSE_EXIT;
1166 return this->traverse_expression_list(traverse, this->rhs_);
1169 // Lower a tuple assignment. We use temporary variables to split it
1170 // up into a set of single assignments.
1172 Statement*
1173 Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
1174 Statement_inserter*)
1176 Location loc = this->location();
1178 Block* b = new Block(enclosing, loc);
1180 // First move out any subexpressions on the left hand side. The
1181 // right hand side will be evaluated in the required order anyhow.
1182 Move_ordered_evals moe(b);
1183 for (Expression_list::iterator plhs = this->lhs_->begin();
1184 plhs != this->lhs_->end();
1185 ++plhs)
1186 Expression::traverse(&*plhs, &moe);
1188 std::vector<Temporary_statement*> temps;
1189 temps.reserve(this->lhs_->size());
1191 Expression_list::const_iterator prhs = this->rhs_->begin();
1192 for (Expression_list::const_iterator plhs = this->lhs_->begin();
1193 plhs != this->lhs_->end();
1194 ++plhs, ++prhs)
1196 go_assert(prhs != this->rhs_->end());
1198 if ((*plhs)->is_error_expression()
1199 || (*plhs)->type()->is_error()
1200 || (*prhs)->is_error_expression()
1201 || (*prhs)->type()->is_error())
1202 continue;
1204 if ((*plhs)->is_sink_expression())
1206 if ((*prhs)->type()->is_nil_type())
1207 this->report_error(_("use of untyped nil"));
1208 else
1209 b->add_statement(Statement::make_statement(*prhs, true));
1210 continue;
1213 Temporary_statement* temp = Statement::make_temporary((*plhs)->type(),
1214 *prhs, loc);
1215 b->add_statement(temp);
1216 temps.push_back(temp);
1219 go_assert(prhs == this->rhs_->end());
1221 prhs = this->rhs_->begin();
1222 std::vector<Temporary_statement*>::const_iterator ptemp = temps.begin();
1223 for (Expression_list::const_iterator plhs = this->lhs_->begin();
1224 plhs != this->lhs_->end();
1225 ++plhs, ++prhs)
1227 if ((*plhs)->is_error_expression()
1228 || (*plhs)->type()->is_error()
1229 || (*prhs)->is_error_expression()
1230 || (*prhs)->type()->is_error())
1231 continue;
1233 if ((*plhs)->is_sink_expression())
1234 continue;
1236 Expression* ref = Expression::make_temporary_reference(*ptemp, loc);
1237 b->add_statement(Statement::make_assignment(*plhs, ref, loc));
1238 ++ptemp;
1240 go_assert(ptemp == temps.end() || saw_errors());
1242 return Statement::make_block_statement(b, loc);
1245 // Dump the AST representation for a tuple assignment statement.
1247 void
1248 Tuple_assignment_statement::do_dump_statement(
1249 Ast_dump_context* ast_dump_context) const
1251 ast_dump_context->print_indent();
1252 ast_dump_context->dump_expression_list(this->lhs_);
1253 ast_dump_context->ostream() << " = ";
1254 ast_dump_context->dump_expression_list(this->rhs_);
1255 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
1258 // Make a tuple assignment statement.
1260 Statement*
1261 Statement::make_tuple_assignment(Expression_list* lhs, Expression_list* rhs,
1262 Location location)
1264 return new Tuple_assignment_statement(lhs, rhs, location);
1267 // A tuple assignment from a map index expression.
1268 // v, ok = m[k]
1270 class Tuple_map_assignment_statement : public Statement
1272 public:
1273 Tuple_map_assignment_statement(Expression* val, Expression* present,
1274 Expression* map_index,
1275 Location location)
1276 : Statement(STATEMENT_TUPLE_MAP_ASSIGNMENT, location),
1277 val_(val), present_(present), map_index_(map_index)
1280 protected:
1282 do_traverse(Traverse* traverse);
1284 bool
1285 do_traverse_assignments(Traverse_assignments*)
1286 { go_unreachable(); }
1288 Statement*
1289 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1291 Bstatement*
1292 do_get_backend(Translate_context*)
1293 { go_unreachable(); }
1295 void
1296 do_dump_statement(Ast_dump_context*) const;
1298 private:
1299 // Lvalue which receives the value from the map.
1300 Expression* val_;
1301 // Lvalue which receives whether the key value was present.
1302 Expression* present_;
1303 // The map index expression.
1304 Expression* map_index_;
1307 // Traversal.
1310 Tuple_map_assignment_statement::do_traverse(Traverse* traverse)
1312 if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
1313 || this->traverse_expression(traverse, &this->present_) == TRAVERSE_EXIT)
1314 return TRAVERSE_EXIT;
1315 return this->traverse_expression(traverse, &this->map_index_);
1318 // Lower a tuple map assignment.
1320 Statement*
1321 Tuple_map_assignment_statement::do_lower(Gogo* gogo, Named_object*,
1322 Block* enclosing, Statement_inserter*)
1324 Location loc = this->location();
1326 Map_index_expression* map_index = this->map_index_->map_index_expression();
1327 if (map_index == NULL)
1329 this->report_error(_("expected map index on right hand side"));
1330 return Statement::make_error_statement(loc);
1332 Map_type* map_type = map_index->get_map_type();
1333 if (map_type == NULL)
1334 return Statement::make_error_statement(loc);
1336 Block* b = new Block(enclosing, loc);
1338 // Move out any subexpressions to make sure that functions are
1339 // called in the required order.
1340 Move_ordered_evals moe(b);
1341 this->val_->traverse_subexpressions(&moe);
1342 this->present_->traverse_subexpressions(&moe);
1344 // Copy the key value into a temporary so that we can take its
1345 // address without pushing the value onto the heap.
1347 // var key_temp KEY_TYPE = MAP_INDEX
1348 Temporary_statement* key_temp =
1349 Statement::make_temporary(map_type->key_type(), map_index->index(), loc);
1350 b->add_statement(key_temp);
1352 // var val_ptr_temp *VAL_TYPE
1353 Type* val_ptr_type = Type::make_pointer_type(map_type->val_type());
1354 Temporary_statement* val_ptr_temp = Statement::make_temporary(val_ptr_type,
1355 NULL, loc);
1356 b->add_statement(val_ptr_temp);
1358 // var present_temp bool
1359 Temporary_statement* present_temp =
1360 Statement::make_temporary((this->present_->type()->is_sink_type())
1361 ? Type::make_boolean_type()
1362 : this->present_->type(),
1363 NULL, loc);
1364 b->add_statement(present_temp);
1366 // val_ptr_temp, present_temp = mapaccess2(DESCRIPTOR, MAP, &key_temp)
1367 Expression* a1 = Expression::make_type_descriptor(map_type, loc);
1368 Expression* a2 = map_index->map();
1369 Temporary_reference_expression* ref =
1370 Expression::make_temporary_reference(key_temp, loc);
1371 Expression* a3 = Expression::make_unary(OPERATOR_AND, ref, loc);
1372 Expression* a4 = map_type->fat_zero_value(gogo);
1373 Call_expression* call;
1374 if (a4 == NULL)
1375 call = Runtime::make_call(Runtime::MAPACCESS2, loc, 3, a1, a2, a3);
1376 else
1377 call = Runtime::make_call(Runtime::MAPACCESS2_FAT, loc, 4, a1, a2, a3, a4);
1378 ref = Expression::make_temporary_reference(val_ptr_temp, loc);
1379 ref->set_is_lvalue();
1380 Expression* res = Expression::make_call_result(call, 0);
1381 res = Expression::make_unsafe_cast(val_ptr_type, res, loc);
1382 Statement* s = Statement::make_assignment(ref, res, loc);
1383 b->add_statement(s);
1384 ref = Expression::make_temporary_reference(present_temp, loc);
1385 ref->set_is_lvalue();
1386 res = Expression::make_call_result(call, 1);
1387 s = Statement::make_assignment(ref, res, loc);
1388 b->add_statement(s);
1390 // val = *val__ptr_temp
1391 ref = Expression::make_temporary_reference(val_ptr_temp, loc);
1392 Expression* ind = Expression::make_unary(OPERATOR_MULT, ref, loc);
1393 s = Statement::make_assignment(this->val_, ind, loc);
1394 b->add_statement(s);
1396 // present = present_temp
1397 ref = Expression::make_temporary_reference(present_temp, loc);
1398 s = Statement::make_assignment(this->present_, ref, loc);
1399 b->add_statement(s);
1401 return Statement::make_block_statement(b, loc);
1404 // Dump the AST representation for a tuple map assignment statement.
1406 void
1407 Tuple_map_assignment_statement::do_dump_statement(
1408 Ast_dump_context* ast_dump_context) const
1410 ast_dump_context->print_indent();
1411 ast_dump_context->dump_expression(this->val_);
1412 ast_dump_context->ostream() << ", ";
1413 ast_dump_context->dump_expression(this->present_);
1414 ast_dump_context->ostream() << " = ";
1415 ast_dump_context->dump_expression(this->map_index_);
1416 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
1419 // Make a map assignment statement which returns a pair of values.
1421 Statement*
1422 Statement::make_tuple_map_assignment(Expression* val, Expression* present,
1423 Expression* map_index,
1424 Location location)
1426 return new Tuple_map_assignment_statement(val, present, map_index, location);
1429 // A tuple assignment from a receive statement.
1431 class Tuple_receive_assignment_statement : public Statement
1433 public:
1434 Tuple_receive_assignment_statement(Expression* val, Expression* closed,
1435 Expression* channel, Location location)
1436 : Statement(STATEMENT_TUPLE_RECEIVE_ASSIGNMENT, location),
1437 val_(val), closed_(closed), channel_(channel)
1440 protected:
1442 do_traverse(Traverse* traverse);
1444 bool
1445 do_traverse_assignments(Traverse_assignments*)
1446 { go_unreachable(); }
1448 Statement*
1449 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1451 Bstatement*
1452 do_get_backend(Translate_context*)
1453 { go_unreachable(); }
1455 void
1456 do_dump_statement(Ast_dump_context*) const;
1458 private:
1459 // Lvalue which receives the value from the channel.
1460 Expression* val_;
1461 // Lvalue which receives whether the channel is closed.
1462 Expression* closed_;
1463 // The channel on which we receive the value.
1464 Expression* channel_;
1467 // Traversal.
1470 Tuple_receive_assignment_statement::do_traverse(Traverse* traverse)
1472 if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
1473 || this->traverse_expression(traverse, &this->closed_) == TRAVERSE_EXIT)
1474 return TRAVERSE_EXIT;
1475 return this->traverse_expression(traverse, &this->channel_);
1478 // Lower to a function call.
1480 Statement*
1481 Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
1482 Block* enclosing,
1483 Statement_inserter*)
1485 Location loc = this->location();
1487 Channel_type* channel_type = this->channel_->type()->channel_type();
1488 if (channel_type == NULL)
1490 this->report_error(_("expected channel"));
1491 return Statement::make_error_statement(loc);
1493 if (!channel_type->may_receive())
1495 this->report_error(_("invalid receive on send-only channel"));
1496 return Statement::make_error_statement(loc);
1499 Block* b = new Block(enclosing, loc);
1501 // Make sure that any subexpressions on the left hand side are
1502 // evaluated in the right order.
1503 Move_ordered_evals moe(b);
1504 this->val_->traverse_subexpressions(&moe);
1505 this->closed_->traverse_subexpressions(&moe);
1507 // var val_temp ELEMENT_TYPE
1508 Temporary_statement* val_temp =
1509 Statement::make_temporary(channel_type->element_type(), NULL, loc);
1510 b->add_statement(val_temp);
1512 // var closed_temp bool
1513 Temporary_statement* closed_temp =
1514 Statement::make_temporary((this->closed_->type()->is_sink_type())
1515 ? Type::make_boolean_type()
1516 : this->closed_->type(),
1517 NULL, loc);
1518 b->add_statement(closed_temp);
1520 // closed_temp = chanrecv2(type, channel, &val_temp)
1521 Expression* td = Expression::make_type_descriptor(this->channel_->type(),
1522 loc);
1523 Temporary_reference_expression* ref =
1524 Expression::make_temporary_reference(val_temp, loc);
1525 Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
1526 Expression* call = Runtime::make_call(Runtime::CHANRECV2,
1527 loc, 3, td, this->channel_, p2);
1528 ref = Expression::make_temporary_reference(closed_temp, loc);
1529 ref->set_is_lvalue();
1530 Statement* s = Statement::make_assignment(ref, call, loc);
1531 b->add_statement(s);
1533 // val = val_temp
1534 ref = Expression::make_temporary_reference(val_temp, loc);
1535 s = Statement::make_assignment(this->val_, ref, loc);
1536 b->add_statement(s);
1538 // closed = closed_temp
1539 ref = Expression::make_temporary_reference(closed_temp, loc);
1540 s = Statement::make_assignment(this->closed_, ref, loc);
1541 b->add_statement(s);
1543 return Statement::make_block_statement(b, loc);
1546 // Dump the AST representation for a tuple receive statement.
1548 void
1549 Tuple_receive_assignment_statement::do_dump_statement(
1550 Ast_dump_context* ast_dump_context) const
1552 ast_dump_context->print_indent();
1553 ast_dump_context->dump_expression(this->val_);
1554 ast_dump_context->ostream() << ", ";
1555 ast_dump_context->dump_expression(this->closed_);
1556 ast_dump_context->ostream() << " <- ";
1557 ast_dump_context->dump_expression(this->channel_);
1558 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
1561 // Make a nonblocking receive statement.
1563 Statement*
1564 Statement::make_tuple_receive_assignment(Expression* val, Expression* closed,
1565 Expression* channel,
1566 Location location)
1568 return new Tuple_receive_assignment_statement(val, closed, channel,
1569 location);
1572 // An assignment to a pair of values from a type guard. This is a
1573 // conditional type guard. v, ok = i.(type).
1575 class Tuple_type_guard_assignment_statement : public Statement
1577 public:
1578 Tuple_type_guard_assignment_statement(Expression* val, Expression* ok,
1579 Expression* expr, Type* type,
1580 Location location)
1581 : Statement(STATEMENT_TUPLE_TYPE_GUARD_ASSIGNMENT, location),
1582 val_(val), ok_(ok), expr_(expr), type_(type)
1585 protected:
1587 do_traverse(Traverse*);
1589 bool
1590 do_traverse_assignments(Traverse_assignments*)
1591 { go_unreachable(); }
1593 Statement*
1594 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1596 Bstatement*
1597 do_get_backend(Translate_context*)
1598 { go_unreachable(); }
1600 void
1601 do_dump_statement(Ast_dump_context*) const;
1603 private:
1604 Call_expression*
1605 lower_to_type(Runtime::Function);
1607 void
1608 lower_to_object_type(Block*, Runtime::Function);
1610 // The variable which recieves the converted value.
1611 Expression* val_;
1612 // The variable which receives the indication of success.
1613 Expression* ok_;
1614 // The expression being converted.
1615 Expression* expr_;
1616 // The type to which the expression is being converted.
1617 Type* type_;
1620 // Traverse a type guard tuple assignment.
1623 Tuple_type_guard_assignment_statement::do_traverse(Traverse* traverse)
1625 if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
1626 || this->traverse_expression(traverse, &this->ok_) == TRAVERSE_EXIT
1627 || this->traverse_type(traverse, this->type_) == TRAVERSE_EXIT)
1628 return TRAVERSE_EXIT;
1629 return this->traverse_expression(traverse, &this->expr_);
1632 // Lower to a function call.
1634 Statement*
1635 Tuple_type_guard_assignment_statement::do_lower(Gogo*, Named_object*,
1636 Block* enclosing,
1637 Statement_inserter*)
1639 Location loc = this->location();
1641 Type* expr_type = this->expr_->type();
1642 if (expr_type->interface_type() == NULL)
1644 if (!expr_type->is_error() && !this->type_->is_error())
1645 this->report_error(_("type assertion only valid for interface types"));
1646 return Statement::make_error_statement(loc);
1649 Block* b = new Block(enclosing, loc);
1651 // Make sure that any subexpressions on the left hand side are
1652 // evaluated in the right order.
1653 Move_ordered_evals moe(b);
1654 this->val_->traverse_subexpressions(&moe);
1655 this->ok_->traverse_subexpressions(&moe);
1657 bool expr_is_empty = expr_type->interface_type()->is_empty();
1658 Call_expression* call;
1659 if (this->type_->interface_type() != NULL)
1661 if (this->type_->interface_type()->is_empty())
1662 call = Runtime::make_call((expr_is_empty
1663 ? Runtime::IFACEE2E2
1664 : Runtime::IFACEI2E2),
1665 loc, 1, this->expr_);
1666 else
1667 call = this->lower_to_type(expr_is_empty
1668 ? Runtime::IFACEE2I2
1669 : Runtime::IFACEI2I2);
1671 else if (this->type_->points_to() != NULL)
1672 call = this->lower_to_type(expr_is_empty
1673 ? Runtime::IFACEE2T2P
1674 : Runtime::IFACEI2T2P);
1675 else
1677 this->lower_to_object_type(b,
1678 (expr_is_empty
1679 ? Runtime::IFACEE2T2
1680 : Runtime::IFACEI2T2));
1681 call = NULL;
1684 if (call != NULL)
1686 Expression* res = Expression::make_call_result(call, 0);
1687 res = Expression::make_unsafe_cast(this->type_, res, loc);
1688 Statement* s = Statement::make_assignment(this->val_, res, loc);
1689 b->add_statement(s);
1691 res = Expression::make_call_result(call, 1);
1692 s = Statement::make_assignment(this->ok_, res, loc);
1693 b->add_statement(s);
1696 return Statement::make_block_statement(b, loc);
1699 // Lower a conversion to a non-empty interface type or a pointer type.
1701 Call_expression*
1702 Tuple_type_guard_assignment_statement::lower_to_type(Runtime::Function code)
1704 Location loc = this->location();
1705 return Runtime::make_call(code, loc, 2,
1706 Expression::make_type_descriptor(this->type_, loc),
1707 this->expr_);
1710 // Lower a conversion to a non-interface non-pointer type.
1712 void
1713 Tuple_type_guard_assignment_statement::lower_to_object_type(
1714 Block* b,
1715 Runtime::Function code)
1717 Location loc = this->location();
1719 // var val_temp TYPE
1720 Temporary_statement* val_temp = Statement::make_temporary(this->type_,
1721 NULL, loc);
1722 b->add_statement(val_temp);
1724 // ok = CODE(type_descriptor, expr, &val_temp)
1725 Expression* p1 = Expression::make_type_descriptor(this->type_, loc);
1726 Expression* ref = Expression::make_temporary_reference(val_temp, loc);
1727 Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
1728 Expression* call = Runtime::make_call(code, loc, 3, p1, this->expr_, p3);
1729 Statement* s = Statement::make_assignment(this->ok_, call, loc);
1730 b->add_statement(s);
1732 // val = val_temp
1733 ref = Expression::make_temporary_reference(val_temp, loc);
1734 s = Statement::make_assignment(this->val_, ref, loc);
1735 b->add_statement(s);
1738 // Dump the AST representation for a tuple type guard statement.
1740 void
1741 Tuple_type_guard_assignment_statement::do_dump_statement(
1742 Ast_dump_context* ast_dump_context) const
1744 ast_dump_context->print_indent();
1745 ast_dump_context->dump_expression(this->val_);
1746 ast_dump_context->ostream() << ", ";
1747 ast_dump_context->dump_expression(this->ok_);
1748 ast_dump_context->ostream() << " = ";
1749 ast_dump_context->dump_expression(this->expr_);
1750 ast_dump_context->ostream() << " . ";
1751 ast_dump_context->dump_type(this->type_);
1752 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
1755 // Make an assignment from a type guard to a pair of variables.
1757 Statement*
1758 Statement::make_tuple_type_guard_assignment(Expression* val, Expression* ok,
1759 Expression* expr, Type* type,
1760 Location location)
1762 return new Tuple_type_guard_assignment_statement(val, ok, expr, type,
1763 location);
1766 // Class Expression_statement.
1768 // Constructor.
1770 Expression_statement::Expression_statement(Expression* expr, bool is_ignored)
1771 : Statement(STATEMENT_EXPRESSION, expr->location()),
1772 expr_(expr), is_ignored_(is_ignored)
1776 // Determine types.
1778 void
1779 Expression_statement::do_determine_types()
1781 this->expr_->determine_type_no_context();
1784 // Check the types of an expression statement. The only check we do
1785 // is to possibly give an error about discarding the value of the
1786 // expression.
1788 void
1789 Expression_statement::do_check_types(Gogo*)
1791 if (!this->is_ignored_)
1792 this->expr_->discarding_value();
1795 // An expression statement is only a terminating statement if it is
1796 // a call to panic.
1798 bool
1799 Expression_statement::do_may_fall_through() const
1801 const Call_expression* call = this->expr_->call_expression();
1802 if (call != NULL)
1804 const Expression* fn = call->fn();
1805 // panic is still an unknown named object.
1806 const Unknown_expression* ue = fn->unknown_expression();
1807 if (ue != NULL)
1809 Named_object* no = ue->named_object();
1811 if (no->is_unknown())
1812 no = no->unknown_value()->real_named_object();
1813 if (no != NULL)
1815 Function_type* fntype;
1816 if (no->is_function())
1817 fntype = no->func_value()->type();
1818 else if (no->is_function_declaration())
1819 fntype = no->func_declaration_value()->type();
1820 else
1821 fntype = NULL;
1823 // The builtin function panic does not return.
1824 if (fntype != NULL && fntype->is_builtin() && no->name() == "panic")
1825 return false;
1829 return true;
1832 // Convert to backend representation.
1834 Bstatement*
1835 Expression_statement::do_get_backend(Translate_context* context)
1837 Bexpression* bexpr = this->expr_->get_backend(context);
1838 Bfunction* bfunction = context->function()->func_value()->get_decl();
1839 return context->backend()->expression_statement(bfunction, bexpr);
1842 // Dump the AST representation for an expression statement
1844 void
1845 Expression_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
1846 const
1848 ast_dump_context->print_indent();
1849 ast_dump_context->dump_expression(expr_);
1850 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
1853 // Make an expression statement from an Expression.
1855 Statement*
1856 Statement::make_statement(Expression* expr, bool is_ignored)
1858 return new Expression_statement(expr, is_ignored);
1861 // Convert a block to the backend representation of a statement.
1863 Bstatement*
1864 Block_statement::do_get_backend(Translate_context* context)
1866 Bblock* bblock = this->block_->get_backend(context);
1867 return context->backend()->block_statement(bblock);
1870 // Dump the AST for a block statement
1872 void
1873 Block_statement::do_dump_statement(Ast_dump_context*) const
1875 // block statement braces are dumped when traversing.
1878 // Make a block statement.
1880 Statement*
1881 Statement::make_block_statement(Block* block, Location location)
1883 return new Block_statement(block, location);
1886 // An increment or decrement statement.
1888 class Inc_dec_statement : public Statement
1890 public:
1891 Inc_dec_statement(bool is_inc, Expression* expr)
1892 : Statement(STATEMENT_INCDEC, expr->location()),
1893 expr_(expr), is_inc_(is_inc)
1896 protected:
1898 do_traverse(Traverse* traverse)
1899 { return this->traverse_expression(traverse, &this->expr_); }
1901 bool
1902 do_traverse_assignments(Traverse_assignments*)
1903 { go_unreachable(); }
1905 Statement*
1906 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1908 Bstatement*
1909 do_get_backend(Translate_context*)
1910 { go_unreachable(); }
1912 void
1913 do_dump_statement(Ast_dump_context*) const;
1915 private:
1916 // The l-value to increment or decrement.
1917 Expression* expr_;
1918 // Whether to increment or decrement.
1919 bool is_inc_;
1922 // Lower to += or -=.
1924 Statement*
1925 Inc_dec_statement::do_lower(Gogo*, Named_object*, Block*, Statement_inserter*)
1927 Location loc = this->location();
1928 Expression* oexpr = Expression::make_integer_ul(1, this->expr_->type(), loc);
1929 Operator op = this->is_inc_ ? OPERATOR_PLUSEQ : OPERATOR_MINUSEQ;
1930 return Statement::make_assignment_operation(op, this->expr_, oexpr, loc);
1933 // Dump the AST representation for a inc/dec statement.
1935 void
1936 Inc_dec_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
1938 ast_dump_context->print_indent();
1939 ast_dump_context->dump_expression(expr_);
1940 ast_dump_context->ostream() << (is_inc_? "++": "--") << dsuffix(location()) << std::endl;
1943 // Make an increment statement.
1945 Statement*
1946 Statement::make_inc_statement(Expression* expr)
1948 return new Inc_dec_statement(true, expr);
1951 // Make a decrement statement.
1953 Statement*
1954 Statement::make_dec_statement(Expression* expr)
1956 return new Inc_dec_statement(false, expr);
1959 // Class Thunk_statement. This is the base class for go and defer
1960 // statements.
1962 // Constructor.
1964 Thunk_statement::Thunk_statement(Statement_classification classification,
1965 Call_expression* call,
1966 Location location)
1967 : Statement(classification, location),
1968 call_(call), struct_type_(NULL)
1972 // Return whether this is a simple statement which does not require a
1973 // thunk.
1975 bool
1976 Thunk_statement::is_simple(Function_type* fntype) const
1978 // We need a thunk to call a method, or to pass a variable number of
1979 // arguments.
1980 if (fntype->is_method() || fntype->is_varargs())
1981 return false;
1983 // A defer statement requires a thunk to set up for whether the
1984 // function can call recover.
1985 if (this->classification() == STATEMENT_DEFER)
1986 return false;
1988 // We can only permit a single parameter of pointer type.
1989 const Typed_identifier_list* parameters = fntype->parameters();
1990 if (parameters != NULL
1991 && (parameters->size() > 1
1992 || (parameters->size() == 1
1993 && parameters->begin()->type()->points_to() == NULL)))
1994 return false;
1996 // If the function returns multiple values, or returns a type other
1997 // than integer, floating point, or pointer, then it may get a
1998 // hidden first parameter, in which case we need the more
1999 // complicated approach. This is true even though we are going to
2000 // ignore the return value.
2001 const Typed_identifier_list* results = fntype->results();
2002 if (results != NULL
2003 && (results->size() > 1
2004 || (results->size() == 1
2005 && !results->begin()->type()->is_basic_type()
2006 && results->begin()->type()->points_to() == NULL)))
2007 return false;
2009 // If this calls something that is not a simple function, then we
2010 // need a thunk.
2011 Expression* fn = this->call_->call_expression()->fn();
2012 if (fn->func_expression() == NULL)
2013 return false;
2015 // If the function uses a closure, then we need a thunk. FIXME: We
2016 // could accept a zero argument function with a closure.
2017 if (fn->func_expression()->closure() != NULL)
2018 return false;
2020 return true;
2023 // Traverse a thunk statement.
2026 Thunk_statement::do_traverse(Traverse* traverse)
2028 return this->traverse_expression(traverse, &this->call_);
2031 // We implement traverse_assignment for a thunk statement because it
2032 // effectively copies the function call.
2034 bool
2035 Thunk_statement::do_traverse_assignments(Traverse_assignments* tassign)
2037 Expression* fn = this->call_->call_expression()->fn();
2038 Expression* fn2 = fn;
2039 tassign->value(&fn2, true, false);
2040 return true;
2043 // Determine types in a thunk statement.
2045 void
2046 Thunk_statement::do_determine_types()
2048 this->call_->determine_type_no_context();
2050 // Now that we know the types of the call, build the struct used to
2051 // pass parameters.
2052 Call_expression* ce = this->call_->call_expression();
2053 if (ce == NULL)
2054 return;
2055 Function_type* fntype = ce->get_function_type();
2056 if (fntype != NULL && !this->is_simple(fntype))
2057 this->struct_type_ = this->build_struct(fntype);
2060 // Check types in a thunk statement.
2062 void
2063 Thunk_statement::do_check_types(Gogo*)
2065 if (!this->call_->discarding_value())
2066 return;
2067 Call_expression* ce = this->call_->call_expression();
2068 if (ce == NULL)
2070 if (!this->call_->is_error_expression())
2071 this->report_error("expected call expression");
2072 return;
2076 // The Traverse class used to find and simplify thunk statements.
2078 class Simplify_thunk_traverse : public Traverse
2080 public:
2081 Simplify_thunk_traverse(Gogo* gogo)
2082 : Traverse(traverse_functions | traverse_blocks),
2083 gogo_(gogo), function_(NULL)
2087 function(Named_object*);
2090 block(Block*);
2092 private:
2093 // General IR.
2094 Gogo* gogo_;
2095 // The function we are traversing.
2096 Named_object* function_;
2099 // Keep track of the current function while looking for thunks.
2102 Simplify_thunk_traverse::function(Named_object* no)
2104 go_assert(this->function_ == NULL);
2105 this->function_ = no;
2106 int t = no->func_value()->traverse(this);
2107 this->function_ = NULL;
2108 if (t == TRAVERSE_EXIT)
2109 return t;
2110 return TRAVERSE_SKIP_COMPONENTS;
2113 // Look for thunks in a block.
2116 Simplify_thunk_traverse::block(Block* b)
2118 // The parser ensures that thunk statements always appear at the end
2119 // of a block.
2120 if (b->statements()->size() < 1)
2121 return TRAVERSE_CONTINUE;
2122 Thunk_statement* stat = b->statements()->back()->thunk_statement();
2123 if (stat == NULL)
2124 return TRAVERSE_CONTINUE;
2125 if (stat->simplify_statement(this->gogo_, this->function_, b))
2126 return TRAVERSE_SKIP_COMPONENTS;
2127 return TRAVERSE_CONTINUE;
2130 // Simplify all thunk statements.
2132 void
2133 Gogo::simplify_thunk_statements()
2135 Simplify_thunk_traverse thunk_traverse(this);
2136 this->traverse(&thunk_traverse);
2139 // Return true if the thunk function is a constant, which means that
2140 // it does not need to be passed to the thunk routine.
2142 bool
2143 Thunk_statement::is_constant_function() const
2145 Call_expression* ce = this->call_->call_expression();
2146 Function_type* fntype = ce->get_function_type();
2147 if (fntype == NULL)
2149 go_assert(saw_errors());
2150 return false;
2152 if (fntype->is_builtin())
2153 return true;
2154 Expression* fn = ce->fn();
2155 if (fn->func_expression() != NULL)
2156 return fn->func_expression()->closure() == NULL;
2157 if (fn->interface_field_reference_expression() != NULL)
2158 return true;
2159 return false;
2162 // Simplify complex thunk statements into simple ones. A complicated
2163 // thunk statement is one which takes anything other than zero
2164 // parameters or a single pointer parameter. We rewrite it into code
2165 // which allocates a struct, stores the parameter values into the
2166 // struct, and does a simple go or defer statement which passes the
2167 // struct to a thunk. The thunk does the real call.
2169 bool
2170 Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
2171 Block* block)
2173 if (this->classification() == STATEMENT_ERROR)
2174 return false;
2175 if (this->call_->is_error_expression())
2176 return false;
2178 if (this->classification() == STATEMENT_DEFER)
2180 // Make sure that the defer stack exists for the function. We
2181 // will use when converting this statement to the backend
2182 // representation, but we want it to exist when we start
2183 // converting the function.
2184 function->func_value()->defer_stack(this->location());
2187 Call_expression* ce = this->call_->call_expression();
2188 Function_type* fntype = ce->get_function_type();
2189 if (fntype == NULL)
2191 go_assert(saw_errors());
2192 this->set_is_error();
2193 return false;
2195 if (this->is_simple(fntype))
2196 return false;
2198 Expression* fn = ce->fn();
2199 Interface_field_reference_expression* interface_method =
2200 fn->interface_field_reference_expression();
2202 Location location = this->location();
2204 bool is_constant_function = this->is_constant_function();
2205 Temporary_statement* fn_temp = NULL;
2206 if (!is_constant_function)
2208 fn_temp = Statement::make_temporary(NULL, fn, location);
2209 block->insert_statement_before(block->statements()->size() - 1, fn_temp);
2210 fn = Expression::make_temporary_reference(fn_temp, location);
2213 std::string thunk_name = Gogo::thunk_name();
2215 // Build the thunk.
2216 this->build_thunk(gogo, thunk_name);
2218 // Generate code to call the thunk.
2220 // Get the values to store into the struct which is the single
2221 // argument to the thunk.
2223 Expression_list* vals = new Expression_list();
2224 if (!is_constant_function)
2225 vals->push_back(fn);
2227 if (interface_method != NULL)
2228 vals->push_back(interface_method->expr());
2230 if (ce->args() != NULL)
2232 for (Expression_list::const_iterator p = ce->args()->begin();
2233 p != ce->args()->end();
2234 ++p)
2236 if ((*p)->is_constant())
2237 continue;
2238 vals->push_back(*p);
2242 // Build the struct.
2243 Expression* constructor =
2244 Expression::make_struct_composite_literal(this->struct_type_, vals,
2245 location);
2247 // Allocate the initialized struct on the heap.
2248 constructor = Expression::make_heap_expression(constructor, location);
2250 // Throw an error if the function is nil. This is so that for `go
2251 // nil` we get a backtrace from the go statement, rather than a
2252 // useless backtrace from the brand new goroutine.
2253 Expression* param = constructor;
2254 if (!is_constant_function)
2256 fn = Expression::make_temporary_reference(fn_temp, location);
2257 Expression* nil = Expression::make_nil(location);
2258 Expression* isnil = Expression::make_binary(OPERATOR_EQEQ, fn, nil,
2259 location);
2260 Expression* crash = gogo->runtime_error(RUNTIME_ERROR_GO_NIL, location);
2261 crash = Expression::make_conditional(isnil, crash,
2262 Expression::make_nil(location),
2263 location);
2264 param = Expression::make_compound(crash, constructor, location);
2267 // Look up the thunk.
2268 Named_object* named_thunk = gogo->lookup(thunk_name, NULL);
2269 go_assert(named_thunk != NULL && named_thunk->is_function());
2271 // Build the call.
2272 Expression* func = Expression::make_func_reference(named_thunk, NULL,
2273 location);
2274 Expression_list* params = new Expression_list();
2275 params->push_back(param);
2276 Call_expression* call = Expression::make_call(func, params, false, location);
2278 // Build the simple go or defer statement.
2279 Statement* s;
2280 if (this->classification() == STATEMENT_GO)
2281 s = Statement::make_go_statement(call, location);
2282 else if (this->classification() == STATEMENT_DEFER)
2283 s = Statement::make_defer_statement(call, location);
2284 else
2285 go_unreachable();
2287 // The current block should end with the go statement.
2288 go_assert(block->statements()->size() >= 1);
2289 go_assert(block->statements()->back() == this);
2290 block->replace_statement(block->statements()->size() - 1, s);
2292 // We already ran the determine_types pass, so we need to run it now
2293 // for the new statement.
2294 s->determine_types();
2296 // Sanity check.
2297 gogo->check_types_in_block(block);
2299 // Return true to tell the block not to keep looking at statements.
2300 return true;
2303 // Set the name to use for thunk parameter N.
2305 void
2306 Thunk_statement::thunk_field_param(int n, char* buf, size_t buflen)
2308 snprintf(buf, buflen, "a%d", n);
2311 // Build a new struct type to hold the parameters for a complicated
2312 // thunk statement. FNTYPE is the type of the function call.
2314 Struct_type*
2315 Thunk_statement::build_struct(Function_type* fntype)
2317 Location location = this->location();
2319 Struct_field_list* fields = new Struct_field_list();
2321 Call_expression* ce = this->call_->call_expression();
2322 Expression* fn = ce->fn();
2324 if (!this->is_constant_function())
2326 // The function to call.
2327 fields->push_back(Struct_field(Typed_identifier("fn", fntype,
2328 location)));
2331 // If this thunk statement calls a method on an interface, we pass
2332 // the interface object to the thunk.
2333 Interface_field_reference_expression* interface_method =
2334 fn->interface_field_reference_expression();
2335 if (interface_method != NULL)
2337 Typed_identifier tid("object", interface_method->expr()->type(),
2338 location);
2339 fields->push_back(Struct_field(tid));
2342 // The predeclared recover function has no argument. However, we
2343 // add an argument when building recover thunks. Handle that here.
2344 if (ce->is_recover_call())
2346 fields->push_back(Struct_field(Typed_identifier("can_recover",
2347 Type::lookup_bool_type(),
2348 location)));
2351 const Expression_list* args = ce->args();
2352 if (args != NULL)
2354 int i = 0;
2355 for (Expression_list::const_iterator p = args->begin();
2356 p != args->end();
2357 ++p, ++i)
2359 if ((*p)->is_constant())
2360 continue;
2362 char buf[50];
2363 this->thunk_field_param(i, buf, sizeof buf);
2364 fields->push_back(Struct_field(Typed_identifier(buf, (*p)->type(),
2365 location)));
2369 Struct_type *st = Type::make_struct_type(fields, location);
2370 st->set_is_struct_incomparable();
2371 return st;
2374 // Build the thunk we are going to call. This is a brand new, albeit
2375 // artificial, function.
2377 void
2378 Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
2380 Location location = this->location();
2382 Call_expression* ce = this->call_->call_expression();
2384 bool may_call_recover = false;
2385 if (this->classification() == STATEMENT_DEFER)
2387 Func_expression* fn = ce->fn()->func_expression();
2388 if (fn == NULL)
2389 may_call_recover = true;
2390 else
2392 const Named_object* no = fn->named_object();
2393 if (!no->is_function())
2394 may_call_recover = true;
2395 else
2396 may_call_recover = no->func_value()->calls_recover();
2400 // Build the type of the thunk. The thunk takes a single parameter,
2401 // which is a pointer to the special structure we build.
2402 const char* const parameter_name = "__go_thunk_parameter";
2403 Typed_identifier_list* thunk_parameters = new Typed_identifier_list();
2404 Type* pointer_to_struct_type = Type::make_pointer_type(this->struct_type_);
2405 thunk_parameters->push_back(Typed_identifier(parameter_name,
2406 pointer_to_struct_type,
2407 location));
2409 Typed_identifier_list* thunk_results = NULL;
2410 if (may_call_recover)
2412 // When deferring a function which may call recover, add a
2413 // return value, to disable tail call optimizations which will
2414 // break the way we check whether recover is permitted.
2415 thunk_results = new Typed_identifier_list();
2416 thunk_results->push_back(Typed_identifier("", Type::lookup_bool_type(),
2417 location));
2420 Function_type* thunk_type = Type::make_function_type(NULL, thunk_parameters,
2421 thunk_results,
2422 location);
2424 // Start building the thunk.
2425 Named_object* function = gogo->start_function(thunk_name, thunk_type, true,
2426 location);
2428 gogo->start_block(location);
2430 // For a defer statement, start with a call to
2431 // __go_set_defer_retaddr. */
2432 Label* retaddr_label = NULL;
2433 if (may_call_recover)
2435 retaddr_label = gogo->add_label_reference("retaddr", location, false);
2436 Expression* arg = Expression::make_label_addr(retaddr_label, location);
2437 Expression* call = Runtime::make_call(Runtime::SETDEFERRETADDR,
2438 location, 1, arg);
2440 // This is a hack to prevent the middle-end from deleting the
2441 // label.
2442 gogo->start_block(location);
2443 gogo->add_statement(Statement::make_goto_statement(retaddr_label,
2444 location));
2445 Block* then_block = gogo->finish_block(location);
2446 then_block->determine_types();
2448 Statement* s = Statement::make_if_statement(call, then_block, NULL,
2449 location);
2450 s->determine_types();
2451 gogo->add_statement(s);
2453 function->func_value()->set_calls_defer_retaddr();
2456 // Get a reference to the parameter.
2457 Named_object* named_parameter = gogo->lookup(parameter_name, NULL);
2458 go_assert(named_parameter != NULL && named_parameter->is_variable());
2460 // Build the call. Note that the field names are the same as the
2461 // ones used in build_struct.
2462 Expression* thunk_parameter = Expression::make_var_reference(named_parameter,
2463 location);
2464 thunk_parameter = Expression::make_unary(OPERATOR_MULT, thunk_parameter,
2465 location);
2467 Interface_field_reference_expression* interface_method =
2468 ce->fn()->interface_field_reference_expression();
2470 Expression* func_to_call;
2471 unsigned int next_index;
2472 if (this->is_constant_function())
2474 func_to_call = ce->fn();
2475 next_index = 0;
2477 else
2479 func_to_call = Expression::make_field_reference(thunk_parameter,
2480 0, location);
2481 next_index = 1;
2484 if (interface_method != NULL)
2486 // The main program passes the interface object.
2487 go_assert(next_index == 0);
2488 Expression* r = Expression::make_field_reference(thunk_parameter, 0,
2489 location);
2490 const std::string& name(interface_method->name());
2491 func_to_call = Expression::make_interface_field_reference(r, name,
2492 location);
2493 next_index = 1;
2496 Expression_list* call_params = new Expression_list();
2497 const Struct_field_list* fields = this->struct_type_->fields();
2498 Struct_field_list::const_iterator p = fields->begin();
2499 for (unsigned int i = 0; i < next_index; ++i)
2500 ++p;
2501 bool is_recover_call = ce->is_recover_call();
2502 Expression* recover_arg = NULL;
2504 const Expression_list* args = ce->args();
2505 if (args != NULL)
2507 for (Expression_list::const_iterator arg = args->begin();
2508 arg != args->end();
2509 ++arg)
2511 Expression* param;
2512 if ((*arg)->is_constant())
2513 param = *arg;
2514 else
2516 Expression* thunk_param =
2517 Expression::make_var_reference(named_parameter, location);
2518 thunk_param =
2519 Expression::make_unary(OPERATOR_MULT, thunk_param, location);
2520 param = Expression::make_field_reference(thunk_param,
2521 next_index,
2522 location);
2523 ++next_index;
2526 if (!is_recover_call)
2527 call_params->push_back(param);
2528 else
2530 go_assert(call_params->empty());
2531 recover_arg = param;
2536 if (call_params->empty())
2538 delete call_params;
2539 call_params = NULL;
2542 Call_expression* call = Expression::make_call(func_to_call, call_params,
2543 false, location);
2545 // This call expression was already lowered before entering the
2546 // thunk statement. Don't try to lower varargs again, as that will
2547 // cause confusion for, e.g., method calls which already have a
2548 // receiver parameter.
2549 call->set_varargs_are_lowered();
2551 Statement* call_statement = Statement::make_statement(call, true);
2553 gogo->add_statement(call_statement);
2555 // If this is a defer statement, the label comes immediately after
2556 // the call.
2557 if (may_call_recover)
2559 gogo->add_label_definition("retaddr", location);
2561 Expression_list* vals = new Expression_list();
2562 vals->push_back(Expression::make_boolean(false, location));
2563 gogo->add_statement(Statement::make_return_statement(vals, location));
2566 Block* b = gogo->finish_block(location);
2568 gogo->add_block(b, location);
2570 gogo->lower_block(function, b);
2572 // We already ran the determine_types pass, so we need to run it
2573 // just for the call statement now. The other types are known.
2574 call_statement->determine_types();
2576 gogo->flatten_block(function, b);
2578 if (may_call_recover
2579 || recover_arg != NULL
2580 || this->classification() == STATEMENT_GO)
2582 // Dig up the call expression, which may have been changed
2583 // during lowering.
2584 go_assert(call_statement->classification() == STATEMENT_EXPRESSION);
2585 Expression_statement* es =
2586 static_cast<Expression_statement*>(call_statement);
2587 Call_expression* ce = es->expr()->call_expression();
2588 if (ce == NULL)
2589 go_assert(saw_errors());
2590 else
2592 if (may_call_recover)
2593 ce->set_is_deferred();
2594 if (this->classification() == STATEMENT_GO)
2595 ce->set_is_concurrent();
2596 if (recover_arg != NULL)
2597 ce->set_recover_arg(recover_arg);
2601 // That is all the thunk has to do.
2602 gogo->finish_function(location);
2605 // Get the function and argument expressions.
2607 bool
2608 Thunk_statement::get_fn_and_arg(Expression** pfn, Expression** parg)
2610 if (this->call_->is_error_expression())
2611 return false;
2613 Call_expression* ce = this->call_->call_expression();
2615 Expression* fn = ce->fn();
2616 Func_expression* fe = fn->func_expression();
2617 go_assert(fe != NULL);
2618 *pfn = Expression::make_func_code_reference(fe->named_object(),
2619 fe->location());
2621 const Expression_list* args = ce->args();
2622 if (args == NULL || args->empty())
2623 *parg = Expression::make_nil(this->location());
2624 else
2626 go_assert(args->size() == 1);
2627 *parg = args->front();
2630 return true;
2633 // Class Go_statement.
2635 Bstatement*
2636 Go_statement::do_get_backend(Translate_context* context)
2638 Expression* fn;
2639 Expression* arg;
2640 if (!this->get_fn_and_arg(&fn, &arg))
2641 return context->backend()->error_statement();
2643 Expression* call = Runtime::make_call(Runtime::GO, this->location(), 2,
2644 fn, arg);
2645 Bexpression* bcall = call->get_backend(context);
2646 Bfunction* bfunction = context->function()->func_value()->get_decl();
2647 return context->backend()->expression_statement(bfunction, bcall);
2650 // Dump the AST representation for go statement.
2652 void
2653 Go_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
2655 ast_dump_context->print_indent();
2656 ast_dump_context->ostream() << "go ";
2657 ast_dump_context->dump_expression(this->call());
2658 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
2661 // Make a go statement.
2663 Statement*
2664 Statement::make_go_statement(Call_expression* call, Location location)
2666 return new Go_statement(call, location);
2669 // Class Defer_statement.
2671 Bstatement*
2672 Defer_statement::do_get_backend(Translate_context* context)
2674 Expression* fn;
2675 Expression* arg;
2676 if (!this->get_fn_and_arg(&fn, &arg))
2677 return context->backend()->error_statement();
2679 Location loc = this->location();
2680 Expression* ds = context->function()->func_value()->defer_stack(loc);
2682 Expression* call = Runtime::make_call(Runtime::DEFERPROC, loc, 3,
2683 ds, fn, arg);
2684 Bexpression* bcall = call->get_backend(context);
2685 Bfunction* bfunction = context->function()->func_value()->get_decl();
2686 return context->backend()->expression_statement(bfunction, bcall);
2689 // Dump the AST representation for defer statement.
2691 void
2692 Defer_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
2694 ast_dump_context->print_indent();
2695 ast_dump_context->ostream() << "defer ";
2696 ast_dump_context->dump_expression(this->call());
2697 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
2700 // Make a defer statement.
2702 Statement*
2703 Statement::make_defer_statement(Call_expression* call,
2704 Location location)
2706 return new Defer_statement(call, location);
2709 // Class Return_statement.
2711 // Traverse assignments. We treat each return value as a top level
2712 // RHS in an expression.
2714 bool
2715 Return_statement::do_traverse_assignments(Traverse_assignments* tassign)
2717 Expression_list* vals = this->vals_;
2718 if (vals != NULL)
2720 for (Expression_list::iterator p = vals->begin();
2721 p != vals->end();
2722 ++p)
2723 tassign->value(&*p, true, true);
2725 return true;
2728 // Lower a return statement. If we are returning a function call
2729 // which returns multiple values which match the current function,
2730 // split up the call's results. If the return statement lists
2731 // explicit values, implement this statement by assigning the values
2732 // to the result variables and change this statement to a naked
2733 // return. This lets panic/recover work correctly.
2735 Statement*
2736 Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing,
2737 Statement_inserter*)
2739 if (this->is_lowered_)
2740 return this;
2742 Expression_list* vals = this->vals_;
2743 this->vals_ = NULL;
2744 this->is_lowered_ = true;
2746 Location loc = this->location();
2748 size_t vals_count = vals == NULL ? 0 : vals->size();
2749 Function::Results* results = function->func_value()->result_variables();
2750 size_t results_count = results == NULL ? 0 : results->size();
2752 if (vals_count == 0)
2754 if (results_count > 0 && !function->func_value()->results_are_named())
2756 this->report_error(_("not enough arguments to return"));
2757 return this;
2759 return this;
2762 if (results_count == 0)
2764 this->report_error(_("return with value in function "
2765 "with no return type"));
2766 return this;
2769 // If the current function has multiple return values, and we are
2770 // returning a single call expression, split up the call expression.
2771 if (results_count > 1
2772 && vals->size() == 1
2773 && vals->front()->call_expression() != NULL)
2775 Call_expression* call = vals->front()->call_expression();
2776 call->set_expected_result_count(results_count);
2777 delete vals;
2778 vals = new Expression_list;
2779 for (size_t i = 0; i < results_count; ++i)
2780 vals->push_back(Expression::make_call_result(call, i));
2781 vals_count = results_count;
2784 if (vals_count < results_count)
2786 this->report_error(_("not enough arguments to return"));
2787 return this;
2790 if (vals_count > results_count)
2792 this->report_error(_("too many values in return statement"));
2793 return this;
2796 Block* b = new Block(enclosing, loc);
2798 Expression_list* lhs = new Expression_list();
2799 Expression_list* rhs = new Expression_list();
2801 Expression_list::const_iterator pe = vals->begin();
2802 int i = 1;
2803 for (Function::Results::const_iterator pr = results->begin();
2804 pr != results->end();
2805 ++pr, ++pe, ++i)
2807 Named_object* rv = *pr;
2808 Expression* e = *pe;
2810 // Check types now so that we give a good error message. The
2811 // result type is known. We determine the expression type
2812 // early.
2814 Type *rvtype = rv->result_var_value()->type();
2815 Type_context type_context(rvtype, false);
2816 e->determine_type(&type_context);
2818 std::string reason;
2819 if (Type::are_assignable(rvtype, e->type(), &reason))
2821 Expression* ve = Expression::make_var_reference(rv, e->location());
2822 lhs->push_back(ve);
2823 rhs->push_back(e);
2825 else
2827 if (reason.empty())
2828 go_error_at(e->location(),
2829 "incompatible type for return value %d", i);
2830 else
2831 go_error_at(e->location(),
2832 "incompatible type for return value %d (%s)",
2833 i, reason.c_str());
2836 go_assert(lhs->size() == rhs->size());
2838 if (lhs->empty())
2840 else if (lhs->size() == 1)
2842 b->add_statement(Statement::make_assignment(lhs->front(), rhs->front(),
2843 loc));
2844 delete lhs;
2845 delete rhs;
2847 else
2848 b->add_statement(Statement::make_tuple_assignment(lhs, rhs, loc));
2850 b->add_statement(this);
2852 delete vals;
2854 return Statement::make_block_statement(b, loc);
2857 // Convert a return statement to the backend representation.
2859 Bstatement*
2860 Return_statement::do_get_backend(Translate_context* context)
2862 Location loc = this->location();
2864 Function* function = context->function()->func_value();
2865 Function::Results* results = function->result_variables();
2866 std::vector<Bexpression*> retvals;
2867 if (results != NULL && !results->empty())
2869 retvals.reserve(results->size());
2870 for (Function::Results::const_iterator p = results->begin();
2871 p != results->end();
2872 p++)
2874 Expression* vr = Expression::make_var_reference(*p, loc);
2875 retvals.push_back(vr->get_backend(context));
2879 return context->backend()->return_statement(function->get_decl(),
2880 retvals, loc);
2883 // Dump the AST representation for a return statement.
2885 void
2886 Return_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
2888 ast_dump_context->print_indent();
2889 ast_dump_context->ostream() << "return " ;
2890 ast_dump_context->dump_expression_list(this->vals_);
2891 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
2894 // Make a return statement.
2896 Return_statement*
2897 Statement::make_return_statement(Expression_list* vals,
2898 Location location)
2900 return new Return_statement(vals, location);
2903 // Make a statement that returns the result of a call expression.
2905 Statement*
2906 Statement::make_return_from_call(Call_expression* call, Location location)
2908 size_t rc = call->result_count();
2909 if (rc == 0)
2910 return Statement::make_statement(call, true);
2911 else
2913 Expression_list* vals = new Expression_list();
2914 if (rc == 1)
2915 vals->push_back(call);
2916 else
2918 for (size_t i = 0; i < rc; ++i)
2919 vals->push_back(Expression::make_call_result(call, i));
2921 return Statement::make_return_statement(vals, location);
2925 // A break or continue statement.
2927 class Bc_statement : public Statement
2929 public:
2930 Bc_statement(bool is_break, Unnamed_label* label, Location location)
2931 : Statement(STATEMENT_BREAK_OR_CONTINUE, location),
2932 label_(label), is_break_(is_break)
2935 bool
2936 is_break() const
2937 { return this->is_break_; }
2939 protected:
2941 do_traverse(Traverse*)
2942 { return TRAVERSE_CONTINUE; }
2944 bool
2945 do_may_fall_through() const
2946 { return false; }
2948 Bstatement*
2949 do_get_backend(Translate_context* context)
2950 { return this->label_->get_goto(context, this->location()); }
2952 void
2953 do_dump_statement(Ast_dump_context*) const;
2955 private:
2956 // The label that this branches to.
2957 Unnamed_label* label_;
2958 // True if this is "break", false if it is "continue".
2959 bool is_break_;
2962 // Dump the AST representation for a break/continue statement
2964 void
2965 Bc_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
2967 ast_dump_context->print_indent();
2968 ast_dump_context->ostream() << (this->is_break_ ? "break" : "continue");
2969 if (this->label_ != NULL)
2971 ast_dump_context->ostream() << " ";
2972 ast_dump_context->dump_label_name(this->label_);
2974 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
2977 // Make a break statement.
2979 Statement*
2980 Statement::make_break_statement(Unnamed_label* label, Location location)
2982 return new Bc_statement(true, label, location);
2985 // Make a continue statement.
2987 Statement*
2988 Statement::make_continue_statement(Unnamed_label* label,
2989 Location location)
2991 return new Bc_statement(false, label, location);
2994 // Class Goto_statement.
2997 Goto_statement::do_traverse(Traverse*)
2999 return TRAVERSE_CONTINUE;
3002 // Check types for a label. There aren't any types per se, but we use
3003 // this to give an error if the label was never defined.
3005 void
3006 Goto_statement::do_check_types(Gogo*)
3008 if (!this->label_->is_defined())
3010 go_error_at(this->location(), "reference to undefined label %qs",
3011 Gogo::message_name(this->label_->name()).c_str());
3012 this->set_is_error();
3016 // Convert the goto statement to the backend representation.
3018 Bstatement*
3019 Goto_statement::do_get_backend(Translate_context* context)
3021 Blabel* blabel = this->label_->get_backend_label(context);
3022 return context->backend()->goto_statement(blabel, this->location());
3025 // Dump the AST representation for a goto statement.
3027 void
3028 Goto_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3030 ast_dump_context->print_indent();
3031 ast_dump_context->ostream() << "goto " << this->label_->name() << dsuffix(location()) << std::endl;
3034 // Make a goto statement.
3036 Statement*
3037 Statement::make_goto_statement(Label* label, Location location)
3039 return new Goto_statement(label, location);
3042 // Class Goto_unnamed_statement.
3045 Goto_unnamed_statement::do_traverse(Traverse*)
3047 return TRAVERSE_CONTINUE;
3050 // Convert the goto unnamed statement to the backend representation.
3052 Bstatement*
3053 Goto_unnamed_statement::do_get_backend(Translate_context* context)
3055 return this->label_->get_goto(context, this->location());
3058 // Dump the AST representation for an unnamed goto statement
3060 void
3061 Goto_unnamed_statement::do_dump_statement(
3062 Ast_dump_context* ast_dump_context) const
3064 ast_dump_context->print_indent();
3065 ast_dump_context->ostream() << "goto ";
3066 ast_dump_context->dump_label_name(this->label_);
3067 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
3070 // Make a goto statement to an unnamed label.
3072 Statement*
3073 Statement::make_goto_unnamed_statement(Unnamed_label* label,
3074 Location location)
3076 return new Goto_unnamed_statement(label, location);
3079 // Class Label_statement.
3081 // Traversal.
3084 Label_statement::do_traverse(Traverse*)
3086 return TRAVERSE_CONTINUE;
3089 // Return the backend representation of the statement defining this
3090 // label.
3092 Bstatement*
3093 Label_statement::do_get_backend(Translate_context* context)
3095 if (this->label_->is_dummy_label())
3097 Bexpression* bce = context->backend()->boolean_constant_expression(false);
3098 Bfunction* bfunction = context->function()->func_value()->get_decl();
3099 return context->backend()->expression_statement(bfunction, bce);
3101 Blabel* blabel = this->label_->get_backend_label(context);
3102 return context->backend()->label_definition_statement(blabel);
3105 // Dump the AST for a label definition statement.
3107 void
3108 Label_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3110 ast_dump_context->print_indent();
3111 ast_dump_context->ostream() << this->label_->name() << ":" << dsuffix(location()) << std::endl;
3114 // Make a label statement.
3116 Statement*
3117 Statement::make_label_statement(Label* label, Location location)
3119 return new Label_statement(label, location);
3122 // Class Unnamed_label_statement.
3124 Unnamed_label_statement::Unnamed_label_statement(Unnamed_label* label)
3125 : Statement(STATEMENT_UNNAMED_LABEL, label->location()),
3126 label_(label)
3130 Unnamed_label_statement::do_traverse(Traverse*)
3132 return TRAVERSE_CONTINUE;
3135 // Get the backend definition for this unnamed label statement.
3137 Bstatement*
3138 Unnamed_label_statement::do_get_backend(Translate_context* context)
3140 return this->label_->get_definition(context);
3143 // Dump the AST representation for an unnamed label definition statement.
3145 void
3146 Unnamed_label_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
3147 const
3149 ast_dump_context->print_indent();
3150 ast_dump_context->dump_label_name(this->label_);
3151 ast_dump_context->ostream() << ":" << dsuffix(location()) << std::endl;
3154 // Make an unnamed label statement.
3156 Statement*
3157 Statement::make_unnamed_label_statement(Unnamed_label* label)
3159 return new Unnamed_label_statement(label);
3162 // Class If_statement.
3164 // Traversal.
3167 If_statement::do_traverse(Traverse* traverse)
3169 if (this->traverse_expression(traverse, &this->cond_) == TRAVERSE_EXIT
3170 || this->then_block_->traverse(traverse) == TRAVERSE_EXIT)
3171 return TRAVERSE_EXIT;
3172 if (this->else_block_ != NULL)
3174 if (this->else_block_->traverse(traverse) == TRAVERSE_EXIT)
3175 return TRAVERSE_EXIT;
3177 return TRAVERSE_CONTINUE;
3180 void
3181 If_statement::do_determine_types()
3183 Type_context context(Type::lookup_bool_type(), false);
3184 this->cond_->determine_type(&context);
3185 this->then_block_->determine_types();
3186 if (this->else_block_ != NULL)
3187 this->else_block_->determine_types();
3190 // Check types.
3192 void
3193 If_statement::do_check_types(Gogo*)
3195 Type* type = this->cond_->type();
3196 if (type->is_error())
3197 this->set_is_error();
3198 else if (!type->is_boolean_type())
3199 this->report_error(_("expected boolean expression"));
3202 // Whether the overall statement may fall through.
3204 bool
3205 If_statement::do_may_fall_through() const
3207 return (this->else_block_ == NULL
3208 || this->then_block_->may_fall_through()
3209 || this->else_block_->may_fall_through());
3212 // Get the backend representation.
3214 Bstatement*
3215 If_statement::do_get_backend(Translate_context* context)
3217 go_assert(this->cond_->type()->is_boolean_type()
3218 || this->cond_->type()->is_error());
3219 Bexpression* cond = this->cond_->get_backend(context);
3220 Bblock* then_block = this->then_block_->get_backend(context);
3221 Bblock* else_block = (this->else_block_ == NULL
3222 ? NULL
3223 : this->else_block_->get_backend(context));
3224 Bfunction* bfunction = context->function()->func_value()->get_decl();
3225 return context->backend()->if_statement(bfunction,
3226 cond, then_block, else_block,
3227 this->location());
3230 // Dump the AST representation for an if statement
3232 void
3233 If_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3235 ast_dump_context->print_indent();
3236 ast_dump_context->ostream() << "if ";
3237 ast_dump_context->dump_expression(this->cond_);
3238 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
3239 if (ast_dump_context->dump_subblocks())
3241 ast_dump_context->dump_block(this->then_block_);
3242 if (this->else_block_ != NULL)
3244 ast_dump_context->print_indent();
3245 ast_dump_context->ostream() << "else" << std::endl;
3246 ast_dump_context->dump_block(this->else_block_);
3251 // Make an if statement.
3253 Statement*
3254 Statement::make_if_statement(Expression* cond, Block* then_block,
3255 Block* else_block, Location location)
3257 return new If_statement(cond, then_block, else_block, location);
3260 // Class Case_clauses::Hash_integer_value.
3262 class Case_clauses::Hash_integer_value
3264 public:
3265 size_t
3266 operator()(Expression*) const;
3269 size_t
3270 Case_clauses::Hash_integer_value::operator()(Expression* pe) const
3272 Numeric_constant nc;
3273 mpz_t ival;
3274 if (!pe->numeric_constant_value(&nc) || !nc.to_int(&ival))
3275 go_unreachable();
3276 size_t ret = mpz_get_ui(ival);
3277 mpz_clear(ival);
3278 return ret;
3281 // Class Case_clauses::Eq_integer_value.
3283 class Case_clauses::Eq_integer_value
3285 public:
3286 bool
3287 operator()(Expression*, Expression*) const;
3290 bool
3291 Case_clauses::Eq_integer_value::operator()(Expression* a, Expression* b) const
3293 Numeric_constant anc;
3294 mpz_t aval;
3295 Numeric_constant bnc;
3296 mpz_t bval;
3297 if (!a->numeric_constant_value(&anc)
3298 || !anc.to_int(&aval)
3299 || !b->numeric_constant_value(&bnc)
3300 || !bnc.to_int(&bval))
3301 go_unreachable();
3302 bool ret = mpz_cmp(aval, bval) == 0;
3303 mpz_clear(aval);
3304 mpz_clear(bval);
3305 return ret;
3308 // Class Case_clauses::Case_clause.
3310 // Traversal.
3313 Case_clauses::Case_clause::traverse(Traverse* traverse)
3315 if (this->cases_ != NULL
3316 && (traverse->traverse_mask()
3317 & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0)
3319 if (this->cases_->traverse(traverse) == TRAVERSE_EXIT)
3320 return TRAVERSE_EXIT;
3322 if (this->statements_ != NULL)
3324 if (this->statements_->traverse(traverse) == TRAVERSE_EXIT)
3325 return TRAVERSE_EXIT;
3327 return TRAVERSE_CONTINUE;
3330 // Check whether all the case expressions are integer constants.
3332 bool
3333 Case_clauses::Case_clause::is_constant() const
3335 if (this->cases_ != NULL)
3337 for (Expression_list::const_iterator p = this->cases_->begin();
3338 p != this->cases_->end();
3339 ++p)
3340 if (!(*p)->is_constant() || (*p)->type()->integer_type() == NULL)
3341 return false;
3343 return true;
3346 // Lower a case clause for a nonconstant switch. VAL_TEMP is the
3347 // value we are switching on; it may be NULL. If START_LABEL is not
3348 // NULL, it goes at the start of the statements, after the condition
3349 // test. We branch to FINISH_LABEL at the end of the statements.
3351 void
3352 Case_clauses::Case_clause::lower(Block* b, Temporary_statement* val_temp,
3353 Unnamed_label* start_label,
3354 Unnamed_label* finish_label) const
3356 Location loc = this->location_;
3357 Unnamed_label* next_case_label;
3358 if (this->cases_ == NULL || this->cases_->empty())
3360 go_assert(this->is_default_);
3361 next_case_label = NULL;
3363 else
3365 Expression* cond = NULL;
3367 for (Expression_list::const_iterator p = this->cases_->begin();
3368 p != this->cases_->end();
3369 ++p)
3371 Expression* ref = Expression::make_temporary_reference(val_temp,
3372 loc);
3373 Expression* this_cond = Expression::make_binary(OPERATOR_EQEQ, ref,
3374 *p, loc);
3375 if (cond == NULL)
3376 cond = this_cond;
3377 else
3378 cond = Expression::make_binary(OPERATOR_OROR, cond, this_cond, loc);
3381 Block* then_block = new Block(b, loc);
3382 next_case_label = new Unnamed_label(Linemap::unknown_location());
3383 Statement* s = Statement::make_goto_unnamed_statement(next_case_label,
3384 loc);
3385 then_block->add_statement(s);
3387 // if !COND { goto NEXT_CASE_LABEL }
3388 cond = Expression::make_unary(OPERATOR_NOT, cond, loc);
3389 s = Statement::make_if_statement(cond, then_block, NULL, loc);
3390 b->add_statement(s);
3393 if (start_label != NULL)
3394 b->add_statement(Statement::make_unnamed_label_statement(start_label));
3396 if (this->statements_ != NULL)
3397 b->add_statement(Statement::make_block_statement(this->statements_, loc));
3399 Statement* s = Statement::make_goto_unnamed_statement(finish_label, loc);
3400 b->add_statement(s);
3402 if (next_case_label != NULL)
3403 b->add_statement(Statement::make_unnamed_label_statement(next_case_label));
3406 // Determine types.
3408 void
3409 Case_clauses::Case_clause::determine_types(Type* type)
3411 if (this->cases_ != NULL)
3413 Type_context case_context(type, false);
3414 for (Expression_list::iterator p = this->cases_->begin();
3415 p != this->cases_->end();
3416 ++p)
3417 (*p)->determine_type(&case_context);
3419 if (this->statements_ != NULL)
3420 this->statements_->determine_types();
3423 // Check types. Returns false if there was an error.
3425 bool
3426 Case_clauses::Case_clause::check_types(Type* type)
3428 if (this->cases_ != NULL)
3430 for (Expression_list::iterator p = this->cases_->begin();
3431 p != this->cases_->end();
3432 ++p)
3434 if (!Type::are_assignable(type, (*p)->type(), NULL)
3435 && !Type::are_assignable((*p)->type(), type, NULL))
3437 go_error_at((*p)->location(),
3438 "type mismatch between switch value and case clause");
3439 return false;
3443 return true;
3446 // Return true if this clause may fall through to the following
3447 // statements. Note that this is not the same as whether the case
3448 // uses the "fallthrough" keyword.
3450 bool
3451 Case_clauses::Case_clause::may_fall_through() const
3453 if (this->statements_ == NULL)
3454 return true;
3455 return this->statements_->may_fall_through();
3458 // Convert the case values and statements to the backend
3459 // representation. BREAK_LABEL is the label which break statements
3460 // should branch to. CASE_CONSTANTS is used to detect duplicate
3461 // constants. *CASES should be passed as an empty vector; the values
3462 // for this case will be added to it. If this is the default case,
3463 // *CASES will remain empty. This returns the statement to execute if
3464 // one of these cases is selected.
3466 Bstatement*
3467 Case_clauses::Case_clause::get_backend(Translate_context* context,
3468 Unnamed_label* break_label,
3469 Case_constants* case_constants,
3470 std::vector<Bexpression*>* cases) const
3472 if (this->cases_ != NULL)
3474 go_assert(!this->is_default_);
3475 for (Expression_list::const_iterator p = this->cases_->begin();
3476 p != this->cases_->end();
3477 ++p)
3479 Expression* e = *p;
3480 if (e->classification() != Expression::EXPRESSION_INTEGER)
3482 Numeric_constant nc;
3483 mpz_t ival;
3484 if (!(*p)->numeric_constant_value(&nc) || !nc.to_int(&ival))
3486 // Something went wrong. This can happen with a
3487 // negative constant and an unsigned switch value.
3488 go_assert(saw_errors());
3489 continue;
3491 go_assert(nc.type() != NULL);
3492 e = Expression::make_integer_z(&ival, nc.type(), e->location());
3493 mpz_clear(ival);
3496 std::pair<Case_constants::iterator, bool> ins =
3497 case_constants->insert(e);
3498 if (!ins.second)
3500 // Value was already present.
3501 go_error_at(this->location_, "duplicate case in switch");
3502 e = Expression::make_error(this->location_);
3504 cases->push_back(e->get_backend(context));
3508 Bstatement* statements;
3509 if (this->statements_ == NULL)
3510 statements = NULL;
3511 else
3513 Bblock* bblock = this->statements_->get_backend(context);
3514 statements = context->backend()->block_statement(bblock);
3517 Bstatement* break_stat;
3518 if (this->is_fallthrough_)
3519 break_stat = NULL;
3520 else
3521 break_stat = break_label->get_goto(context, this->location_);
3523 if (statements == NULL)
3524 return break_stat;
3525 else if (break_stat == NULL)
3526 return statements;
3527 else
3528 return context->backend()->compound_statement(statements, break_stat);
3531 // Dump the AST representation for a case clause
3533 void
3534 Case_clauses::Case_clause::dump_clause(Ast_dump_context* ast_dump_context)
3535 const
3537 ast_dump_context->print_indent();
3538 if (this->is_default_)
3540 ast_dump_context->ostream() << "default:";
3542 else
3544 ast_dump_context->ostream() << "case ";
3545 ast_dump_context->dump_expression_list(this->cases_);
3546 ast_dump_context->ostream() << ":" ;
3548 ast_dump_context->dump_block(this->statements_);
3549 if (this->is_fallthrough_)
3551 ast_dump_context->print_indent();
3552 ast_dump_context->ostream() << " (fallthrough)" << dsuffix(location()) << std::endl;
3556 // Class Case_clauses.
3558 // Traversal.
3561 Case_clauses::traverse(Traverse* traverse)
3563 for (Clauses::iterator p = this->clauses_.begin();
3564 p != this->clauses_.end();
3565 ++p)
3567 if (p->traverse(traverse) == TRAVERSE_EXIT)
3568 return TRAVERSE_EXIT;
3570 return TRAVERSE_CONTINUE;
3573 // Check whether all the case expressions are constant.
3575 bool
3576 Case_clauses::is_constant() const
3578 for (Clauses::const_iterator p = this->clauses_.begin();
3579 p != this->clauses_.end();
3580 ++p)
3581 if (!p->is_constant())
3582 return false;
3583 return true;
3586 // Lower case clauses for a nonconstant switch.
3588 void
3589 Case_clauses::lower(Block* b, Temporary_statement* val_temp,
3590 Unnamed_label* break_label) const
3592 // The default case.
3593 const Case_clause* default_case = NULL;
3595 // The label for the fallthrough of the previous case.
3596 Unnamed_label* last_fallthrough_label = NULL;
3598 // The label for the start of the default case. This is used if the
3599 // case before the default case falls through.
3600 Unnamed_label* default_start_label = NULL;
3602 // The label for the end of the default case. This normally winds
3603 // up as BREAK_LABEL, but it will be different if the default case
3604 // falls through.
3605 Unnamed_label* default_finish_label = NULL;
3607 for (Clauses::const_iterator p = this->clauses_.begin();
3608 p != this->clauses_.end();
3609 ++p)
3611 // The label to use for the start of the statements for this
3612 // case. This is NULL unless the previous case falls through.
3613 Unnamed_label* start_label = last_fallthrough_label;
3615 // The label to jump to after the end of the statements for this
3616 // case.
3617 Unnamed_label* finish_label = break_label;
3619 last_fallthrough_label = NULL;
3620 if (p->is_fallthrough() && p + 1 != this->clauses_.end())
3622 finish_label = new Unnamed_label(p->location());
3623 last_fallthrough_label = finish_label;
3626 if (!p->is_default())
3627 p->lower(b, val_temp, start_label, finish_label);
3628 else
3630 // We have to move the default case to the end, so that we
3631 // only use it if all the other tests fail.
3632 default_case = &*p;
3633 default_start_label = start_label;
3634 default_finish_label = finish_label;
3638 if (default_case != NULL)
3639 default_case->lower(b, val_temp, default_start_label,
3640 default_finish_label);
3643 // Determine types.
3645 void
3646 Case_clauses::determine_types(Type* type)
3648 for (Clauses::iterator p = this->clauses_.begin();
3649 p != this->clauses_.end();
3650 ++p)
3651 p->determine_types(type);
3654 // Check types. Returns false if there was an error.
3656 bool
3657 Case_clauses::check_types(Type* type)
3659 bool ret = true;
3660 for (Clauses::iterator p = this->clauses_.begin();
3661 p != this->clauses_.end();
3662 ++p)
3664 if (!p->check_types(type))
3665 ret = false;
3667 return ret;
3670 // Return true if these clauses may fall through to the statements
3671 // following the switch statement.
3673 bool
3674 Case_clauses::may_fall_through() const
3676 bool found_default = false;
3677 for (Clauses::const_iterator p = this->clauses_.begin();
3678 p != this->clauses_.end();
3679 ++p)
3681 if (p->may_fall_through() && !p->is_fallthrough())
3682 return true;
3683 if (p->is_default())
3684 found_default = true;
3686 return !found_default;
3689 // Convert the cases to the backend representation. This sets
3690 // *ALL_CASES and *ALL_STATEMENTS.
3692 void
3693 Case_clauses::get_backend(Translate_context* context,
3694 Unnamed_label* break_label,
3695 std::vector<std::vector<Bexpression*> >* all_cases,
3696 std::vector<Bstatement*>* all_statements) const
3698 Case_constants case_constants;
3700 size_t c = this->clauses_.size();
3701 all_cases->resize(c);
3702 all_statements->resize(c);
3704 size_t i = 0;
3705 for (Clauses::const_iterator p = this->clauses_.begin();
3706 p != this->clauses_.end();
3707 ++p, ++i)
3709 std::vector<Bexpression*> cases;
3710 Bstatement* stat = p->get_backend(context, break_label, &case_constants,
3711 &cases);
3712 (*all_cases)[i].swap(cases);
3713 (*all_statements)[i] = stat;
3717 // Dump the AST representation for case clauses (from a switch statement)
3719 void
3720 Case_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
3722 for (Clauses::const_iterator p = this->clauses_.begin();
3723 p != this->clauses_.end();
3724 ++p)
3725 p->dump_clause(ast_dump_context);
3728 // A constant switch statement. A Switch_statement is lowered to this
3729 // when all the cases are constants.
3731 class Constant_switch_statement : public Statement
3733 public:
3734 Constant_switch_statement(Expression* val, Case_clauses* clauses,
3735 Unnamed_label* break_label,
3736 Location location)
3737 : Statement(STATEMENT_CONSTANT_SWITCH, location),
3738 val_(val), clauses_(clauses), break_label_(break_label)
3741 protected:
3743 do_traverse(Traverse*);
3745 void
3746 do_determine_types();
3748 void
3749 do_check_types(Gogo*);
3751 Bstatement*
3752 do_get_backend(Translate_context*);
3754 void
3755 do_dump_statement(Ast_dump_context*) const;
3757 private:
3758 // The value to switch on.
3759 Expression* val_;
3760 // The case clauses.
3761 Case_clauses* clauses_;
3762 // The break label, if needed.
3763 Unnamed_label* break_label_;
3766 // Traversal.
3769 Constant_switch_statement::do_traverse(Traverse* traverse)
3771 if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT)
3772 return TRAVERSE_EXIT;
3773 return this->clauses_->traverse(traverse);
3776 // Determine types.
3778 void
3779 Constant_switch_statement::do_determine_types()
3781 this->val_->determine_type_no_context();
3782 this->clauses_->determine_types(this->val_->type());
3785 // Check types.
3787 void
3788 Constant_switch_statement::do_check_types(Gogo*)
3790 if (!this->clauses_->check_types(this->val_->type()))
3791 this->set_is_error();
3794 // Convert to GENERIC.
3796 Bstatement*
3797 Constant_switch_statement::do_get_backend(Translate_context* context)
3799 Bexpression* switch_val_expr = this->val_->get_backend(context);
3801 Unnamed_label* break_label = this->break_label_;
3802 if (break_label == NULL)
3803 break_label = new Unnamed_label(this->location());
3805 std::vector<std::vector<Bexpression*> > all_cases;
3806 std::vector<Bstatement*> all_statements;
3807 this->clauses_->get_backend(context, break_label, &all_cases,
3808 &all_statements);
3810 Bfunction* bfunction = context->function()->func_value()->get_decl();
3811 Bstatement* switch_statement;
3812 switch_statement = context->backend()->switch_statement(bfunction,
3813 switch_val_expr,
3814 all_cases,
3815 all_statements,
3816 this->location());
3817 Bstatement* ldef = break_label->get_definition(context);
3818 return context->backend()->compound_statement(switch_statement, ldef);
3821 // Dump the AST representation for a constant switch statement.
3823 void
3824 Constant_switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
3825 const
3827 ast_dump_context->print_indent();
3828 ast_dump_context->ostream() << "switch ";
3829 ast_dump_context->dump_expression(this->val_);
3831 if (ast_dump_context->dump_subblocks())
3833 ast_dump_context->ostream() << " {" << std::endl;
3834 this->clauses_->dump_clauses(ast_dump_context);
3835 ast_dump_context->ostream() << "}";
3838 ast_dump_context->ostream() << std::endl;
3841 // Class Switch_statement.
3843 // Traversal.
3846 Switch_statement::do_traverse(Traverse* traverse)
3848 if (this->val_ != NULL)
3850 if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT)
3851 return TRAVERSE_EXIT;
3853 return this->clauses_->traverse(traverse);
3856 // Lower a Switch_statement to a Constant_switch_statement or a series
3857 // of if statements.
3859 Statement*
3860 Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
3861 Statement_inserter*)
3863 Location loc = this->location();
3865 if (this->val_ != NULL
3866 && (this->val_->is_error_expression()
3867 || this->val_->type()->is_error()))
3869 go_assert(saw_errors());
3870 return Statement::make_error_statement(loc);
3873 if (this->val_ != NULL
3874 && this->val_->type()->integer_type() != NULL
3875 && !this->clauses_->empty()
3876 && this->clauses_->is_constant())
3877 return new Constant_switch_statement(this->val_, this->clauses_,
3878 this->break_label_, loc);
3880 if (this->val_ != NULL
3881 && !this->val_->type()->is_comparable()
3882 && !Type::are_compatible_for_comparison(true, this->val_->type(),
3883 Type::make_nil_type(), NULL))
3885 go_error_at(this->val_->location(),
3886 "cannot switch on value whose type that may not be compared");
3887 return Statement::make_error_statement(loc);
3890 Block* b = new Block(enclosing, loc);
3892 if (this->clauses_->empty())
3894 Expression* val = this->val_;
3895 if (val == NULL)
3896 val = Expression::make_boolean(true, loc);
3897 return Statement::make_statement(val, true);
3900 // var val_temp VAL_TYPE = VAL
3901 Expression* val = this->val_;
3902 if (val == NULL)
3903 val = Expression::make_boolean(true, loc);
3905 Type* type = val->type();
3906 if (type->is_abstract())
3907 type = type->make_non_abstract_type();
3908 Temporary_statement* val_temp = Statement::make_temporary(type, val, loc);
3909 b->add_statement(val_temp);
3911 this->clauses_->lower(b, val_temp, this->break_label());
3913 Statement* s = Statement::make_unnamed_label_statement(this->break_label_);
3914 b->add_statement(s);
3916 return Statement::make_block_statement(b, loc);
3919 // Return the break label for this switch statement, creating it if
3920 // necessary.
3922 Unnamed_label*
3923 Switch_statement::break_label()
3925 if (this->break_label_ == NULL)
3926 this->break_label_ = new Unnamed_label(this->location());
3927 return this->break_label_;
3930 // Dump the AST representation for a switch statement.
3932 void
3933 Switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3935 ast_dump_context->print_indent();
3936 ast_dump_context->ostream() << "switch ";
3937 if (this->val_ != NULL)
3939 ast_dump_context->dump_expression(this->val_);
3941 if (ast_dump_context->dump_subblocks())
3943 ast_dump_context->ostream() << " {" << dsuffix(location()) << std::endl;
3944 this->clauses_->dump_clauses(ast_dump_context);
3945 ast_dump_context->print_indent();
3946 ast_dump_context->ostream() << "}";
3948 ast_dump_context->ostream() << std::endl;
3951 // Return whether this switch may fall through.
3953 bool
3954 Switch_statement::do_may_fall_through() const
3956 if (this->clauses_ == NULL)
3957 return true;
3959 // If we have a break label, then some case needed it. That implies
3960 // that the switch statement as a whole can fall through.
3961 if (this->break_label_ != NULL)
3962 return true;
3964 return this->clauses_->may_fall_through();
3967 // Make a switch statement.
3969 Switch_statement*
3970 Statement::make_switch_statement(Expression* val, Location location)
3972 return new Switch_statement(val, location);
3975 // Class Type_case_clauses::Type_case_clause.
3977 // Traversal.
3980 Type_case_clauses::Type_case_clause::traverse(Traverse* traverse)
3982 if (!this->is_default_
3983 && ((traverse->traverse_mask()
3984 & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0)
3985 && Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
3986 return TRAVERSE_EXIT;
3987 if (this->statements_ != NULL)
3988 return this->statements_->traverse(traverse);
3989 return TRAVERSE_CONTINUE;
3992 // Lower one clause in a type switch. Add statements to the block B.
3993 // The type descriptor we are switching on is in DESCRIPTOR_TEMP.
3994 // BREAK_LABEL is the label at the end of the type switch.
3995 // *STMTS_LABEL, if not NULL, is a label to put at the start of the
3996 // statements.
3998 void
3999 Type_case_clauses::Type_case_clause::lower(Type* switch_val_type,
4000 Block* b,
4001 Temporary_statement* descriptor_temp,
4002 Unnamed_label* break_label,
4003 Unnamed_label** stmts_label) const
4005 Location loc = this->location_;
4007 Unnamed_label* next_case_label = NULL;
4008 if (!this->is_default_)
4010 Type* type = this->type_;
4012 std::string reason;
4013 if (switch_val_type->interface_type() != NULL
4014 && !type->is_nil_constant_as_type()
4015 && type->interface_type() == NULL
4016 && !switch_val_type->interface_type()->implements_interface(type,
4017 &reason))
4019 if (reason.empty())
4020 go_error_at(this->location_, "impossible type switch case");
4021 else
4022 go_error_at(this->location_, "impossible type switch case (%s)",
4023 reason.c_str());
4026 Expression* ref = Expression::make_temporary_reference(descriptor_temp,
4027 loc);
4029 Expression* cond;
4030 // The language permits case nil, which is of course a constant
4031 // rather than a type. It will appear here as an invalid
4032 // forwarding type.
4033 if (type->is_nil_constant_as_type())
4034 cond = Expression::make_binary(OPERATOR_EQEQ, ref,
4035 Expression::make_nil(loc),
4036 loc);
4037 else
4038 cond = Runtime::make_call((type->interface_type() == NULL
4039 ? Runtime::IFACETYPEEQ
4040 : Runtime::IFACET2IP),
4041 loc, 2,
4042 Expression::make_type_descriptor(type, loc),
4043 ref);
4045 Unnamed_label* dest;
4046 if (!this->is_fallthrough_)
4048 // if !COND { goto NEXT_CASE_LABEL }
4049 next_case_label = new Unnamed_label(Linemap::unknown_location());
4050 dest = next_case_label;
4051 cond = Expression::make_unary(OPERATOR_NOT, cond, loc);
4053 else
4055 // if COND { goto STMTS_LABEL }
4056 go_assert(stmts_label != NULL);
4057 if (*stmts_label == NULL)
4058 *stmts_label = new Unnamed_label(Linemap::unknown_location());
4059 dest = *stmts_label;
4061 Block* then_block = new Block(b, loc);
4062 Statement* s = Statement::make_goto_unnamed_statement(dest, loc);
4063 then_block->add_statement(s);
4064 s = Statement::make_if_statement(cond, then_block, NULL, loc);
4065 b->add_statement(s);
4068 if (this->statements_ != NULL
4069 || (!this->is_fallthrough_
4070 && stmts_label != NULL
4071 && *stmts_label != NULL))
4073 go_assert(!this->is_fallthrough_);
4074 if (stmts_label != NULL && *stmts_label != NULL)
4076 go_assert(!this->is_default_);
4077 if (this->statements_ != NULL)
4078 (*stmts_label)->set_location(this->statements_->start_location());
4079 Statement* s = Statement::make_unnamed_label_statement(*stmts_label);
4080 b->add_statement(s);
4081 *stmts_label = NULL;
4083 if (this->statements_ != NULL)
4084 b->add_statement(Statement::make_block_statement(this->statements_,
4085 loc));
4088 if (this->is_fallthrough_)
4089 go_assert(next_case_label == NULL);
4090 else
4092 Location gloc = (this->statements_ == NULL
4093 ? loc
4094 : this->statements_->end_location());
4095 b->add_statement(Statement::make_goto_unnamed_statement(break_label,
4096 gloc));
4097 if (next_case_label != NULL)
4099 Statement* s =
4100 Statement::make_unnamed_label_statement(next_case_label);
4101 b->add_statement(s);
4106 // Return true if this type clause may fall through to the statements
4107 // following the switch.
4109 bool
4110 Type_case_clauses::Type_case_clause::may_fall_through() const
4112 if (this->is_fallthrough_)
4114 // This case means that we automatically fall through to the
4115 // next case (it's used for T1 in case T1, T2:). It does not
4116 // mean that we fall through to the end of the type switch as a
4117 // whole. There is sure to be a next case and that next case
4118 // will determine whether we fall through to the statements
4119 // after the type switch.
4120 return false;
4122 if (this->statements_ == NULL)
4123 return true;
4124 return this->statements_->may_fall_through();
4127 // Dump the AST representation for a type case clause
4129 void
4130 Type_case_clauses::Type_case_clause::dump_clause(
4131 Ast_dump_context* ast_dump_context) const
4133 ast_dump_context->print_indent();
4134 if (this->is_default_)
4136 ast_dump_context->ostream() << "default:";
4138 else
4140 ast_dump_context->ostream() << "case ";
4141 ast_dump_context->dump_type(this->type_);
4142 ast_dump_context->ostream() << ":" ;
4144 ast_dump_context->dump_block(this->statements_);
4145 if (this->is_fallthrough_)
4147 ast_dump_context->print_indent();
4148 ast_dump_context->ostream() << " (fallthrough)" << std::endl;
4152 // Class Type_case_clauses.
4154 // Traversal.
4157 Type_case_clauses::traverse(Traverse* traverse)
4159 for (Type_clauses::iterator p = this->clauses_.begin();
4160 p != this->clauses_.end();
4161 ++p)
4163 if (p->traverse(traverse) == TRAVERSE_EXIT)
4164 return TRAVERSE_EXIT;
4166 return TRAVERSE_CONTINUE;
4169 // Check for duplicate types.
4171 void
4172 Type_case_clauses::check_duplicates() const
4174 typedef Unordered_set_hash(const Type*, Type_hash_identical,
4175 Type_identical) Types_seen;
4176 Types_seen types_seen;
4177 for (Type_clauses::const_iterator p = this->clauses_.begin();
4178 p != this->clauses_.end();
4179 ++p)
4181 Type* t = p->type();
4182 if (t == NULL)
4183 continue;
4184 if (t->is_nil_constant_as_type())
4185 t = Type::make_nil_type();
4186 std::pair<Types_seen::iterator, bool> ins = types_seen.insert(t);
4187 if (!ins.second)
4188 go_error_at(p->location(), "duplicate type in switch");
4192 // Lower the clauses in a type switch. Add statements to the block B.
4193 // The type descriptor we are switching on is in DESCRIPTOR_TEMP.
4194 // BREAK_LABEL is the label at the end of the type switch.
4196 void
4197 Type_case_clauses::lower(Type* switch_val_type, Block* b,
4198 Temporary_statement* descriptor_temp,
4199 Unnamed_label* break_label) const
4201 const Type_case_clause* default_case = NULL;
4203 Unnamed_label* stmts_label = NULL;
4204 for (Type_clauses::const_iterator p = this->clauses_.begin();
4205 p != this->clauses_.end();
4206 ++p)
4208 if (!p->is_default())
4209 p->lower(switch_val_type, b, descriptor_temp, break_label,
4210 &stmts_label);
4211 else
4213 // We are generating a series of tests, which means that we
4214 // need to move the default case to the end.
4215 default_case = &*p;
4218 go_assert(stmts_label == NULL);
4220 if (default_case != NULL)
4221 default_case->lower(switch_val_type, b, descriptor_temp, break_label,
4222 NULL);
4225 // Return true if these clauses may fall through to the statements
4226 // following the switch statement.
4228 bool
4229 Type_case_clauses::may_fall_through() const
4231 bool found_default = false;
4232 for (Type_clauses::const_iterator p = this->clauses_.begin();
4233 p != this->clauses_.end();
4234 ++p)
4236 if (p->may_fall_through())
4237 return true;
4238 if (p->is_default())
4239 found_default = true;
4241 return !found_default;
4244 // Dump the AST representation for case clauses (from a switch statement)
4246 void
4247 Type_case_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
4249 for (Type_clauses::const_iterator p = this->clauses_.begin();
4250 p != this->clauses_.end();
4251 ++p)
4252 p->dump_clause(ast_dump_context);
4255 // Class Type_switch_statement.
4257 // Traversal.
4260 Type_switch_statement::do_traverse(Traverse* traverse)
4262 if (this->traverse_expression(traverse, &this->expr_) == TRAVERSE_EXIT)
4263 return TRAVERSE_EXIT;
4264 if (this->clauses_ != NULL)
4265 return this->clauses_->traverse(traverse);
4266 return TRAVERSE_CONTINUE;
4269 // Lower a type switch statement to a series of if statements. The gc
4270 // compiler is able to generate a table in some cases. However, that
4271 // does not work for us because we may have type descriptors in
4272 // different shared libraries, so we can't compare them with simple
4273 // equality testing.
4275 Statement*
4276 Type_switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
4277 Statement_inserter*)
4279 const Location loc = this->location();
4281 if (this->clauses_ != NULL)
4282 this->clauses_->check_duplicates();
4284 Block* b = new Block(enclosing, loc);
4286 Type* val_type = this->expr_->type();
4287 if (val_type->interface_type() == NULL)
4289 if (!val_type->is_error())
4290 this->report_error(_("cannot type switch on non-interface value"));
4291 return Statement::make_error_statement(loc);
4294 // var descriptor_temp DESCRIPTOR_TYPE
4295 Type* descriptor_type = Type::make_type_descriptor_ptr_type();
4296 Temporary_statement* descriptor_temp =
4297 Statement::make_temporary(descriptor_type, NULL, loc);
4298 b->add_statement(descriptor_temp);
4300 // descriptor_temp = ifacetype(val_temp) FIXME: This should be
4301 // inlined.
4302 bool is_empty = val_type->interface_type()->is_empty();
4303 Expression* call = Runtime::make_call((is_empty
4304 ? Runtime::EFACETYPE
4305 : Runtime::IFACETYPE),
4306 loc, 1, this->expr_);
4307 Temporary_reference_expression* lhs =
4308 Expression::make_temporary_reference(descriptor_temp, loc);
4309 lhs->set_is_lvalue();
4310 Statement* s = Statement::make_assignment(lhs, call, loc);
4311 b->add_statement(s);
4313 if (this->clauses_ != NULL)
4314 this->clauses_->lower(val_type, b, descriptor_temp, this->break_label());
4316 s = Statement::make_unnamed_label_statement(this->break_label_);
4317 b->add_statement(s);
4319 return Statement::make_block_statement(b, loc);
4322 // Return whether this switch may fall through.
4324 bool
4325 Type_switch_statement::do_may_fall_through() const
4327 if (this->clauses_ == NULL)
4328 return true;
4330 // If we have a break label, then some case needed it. That implies
4331 // that the switch statement as a whole can fall through.
4332 if (this->break_label_ != NULL)
4333 return true;
4335 return this->clauses_->may_fall_through();
4338 // Return the break label for this type switch statement, creating it
4339 // if necessary.
4341 Unnamed_label*
4342 Type_switch_statement::break_label()
4344 if (this->break_label_ == NULL)
4345 this->break_label_ = new Unnamed_label(this->location());
4346 return this->break_label_;
4349 // Dump the AST representation for a type switch statement
4351 void
4352 Type_switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
4353 const
4355 ast_dump_context->print_indent();
4356 ast_dump_context->ostream() << "switch ";
4357 if (!this->name_.empty())
4358 ast_dump_context->ostream() << this->name_ << " = ";
4359 ast_dump_context->dump_expression(this->expr_);
4360 ast_dump_context->ostream() << " .(type)";
4361 if (ast_dump_context->dump_subblocks())
4363 ast_dump_context->ostream() << " {" << dsuffix(location()) << std::endl;
4364 this->clauses_->dump_clauses(ast_dump_context);
4365 ast_dump_context->ostream() << "}";
4367 ast_dump_context->ostream() << std::endl;
4370 // Make a type switch statement.
4372 Type_switch_statement*
4373 Statement::make_type_switch_statement(const std::string& name, Expression* expr,
4374 Location location)
4376 return new Type_switch_statement(name, expr, location);
4379 // Class Send_statement.
4381 // Traversal.
4384 Send_statement::do_traverse(Traverse* traverse)
4386 if (this->traverse_expression(traverse, &this->channel_) == TRAVERSE_EXIT)
4387 return TRAVERSE_EXIT;
4388 return this->traverse_expression(traverse, &this->val_);
4391 // Determine types.
4393 void
4394 Send_statement::do_determine_types()
4396 this->channel_->determine_type_no_context();
4397 Type* type = this->channel_->type();
4398 Type_context context;
4399 if (type->channel_type() != NULL)
4400 context.type = type->channel_type()->element_type();
4401 this->val_->determine_type(&context);
4404 // Check types.
4406 void
4407 Send_statement::do_check_types(Gogo*)
4409 Type* type = this->channel_->type();
4410 if (type->is_error())
4412 this->set_is_error();
4413 return;
4415 Channel_type* channel_type = type->channel_type();
4416 if (channel_type == NULL)
4418 go_error_at(this->location(), "left operand of %<<-%> must be channel");
4419 this->set_is_error();
4420 return;
4422 Type* element_type = channel_type->element_type();
4423 if (!Type::are_assignable(element_type, this->val_->type(), NULL))
4425 this->report_error(_("incompatible types in send"));
4426 return;
4428 if (!channel_type->may_send())
4430 this->report_error(_("invalid send on receive-only channel"));
4431 return;
4435 // Flatten a send statement. We may need a temporary for interface
4436 // conversion.
4438 Statement*
4439 Send_statement::do_flatten(Gogo*, Named_object*, Block*,
4440 Statement_inserter* inserter)
4442 if (this->channel_->is_error_expression()
4443 || this->channel_->type()->is_error_type())
4445 go_assert(saw_errors());
4446 return Statement::make_error_statement(this->location());
4449 Type* element_type = this->channel_->type()->channel_type()->element_type();
4450 if (!Type::are_identical(element_type, this->val_->type(), false, NULL)
4451 && this->val_->type()->interface_type() != NULL
4452 && !this->val_->is_variable())
4454 Temporary_statement* temp =
4455 Statement::make_temporary(NULL, this->val_, this->location());
4456 inserter->insert(temp);
4457 this->val_ = Expression::make_temporary_reference(temp,
4458 this->location());
4460 return this;
4463 // Convert a send statement to the backend representation.
4465 Bstatement*
4466 Send_statement::do_get_backend(Translate_context* context)
4468 Location loc = this->location();
4470 Channel_type* channel_type = this->channel_->type()->channel_type();
4471 Type* element_type = channel_type->element_type();
4472 Expression* val = Expression::convert_for_assignment(context->gogo(),
4473 element_type,
4474 this->val_, loc);
4476 bool can_take_address;
4477 switch (element_type->base()->classification())
4479 case Type::TYPE_BOOLEAN:
4480 case Type::TYPE_INTEGER:
4481 case Type::TYPE_FUNCTION:
4482 case Type::TYPE_POINTER:
4483 case Type::TYPE_MAP:
4484 case Type::TYPE_CHANNEL:
4485 case Type::TYPE_FLOAT:
4486 case Type::TYPE_COMPLEX:
4487 case Type::TYPE_STRING:
4488 case Type::TYPE_INTERFACE:
4489 can_take_address = false;
4490 break;
4492 case Type::TYPE_STRUCT:
4493 can_take_address = true;
4494 break;
4496 case Type::TYPE_ARRAY:
4497 can_take_address = !element_type->is_slice_type();
4498 break;
4500 default:
4501 case Type::TYPE_ERROR:
4502 case Type::TYPE_VOID:
4503 case Type::TYPE_SINK:
4504 case Type::TYPE_NIL:
4505 case Type::TYPE_NAMED:
4506 case Type::TYPE_FORWARD:
4507 go_assert(saw_errors());
4508 return context->backend()->error_statement();
4511 // Only try to take the address of a variable. We have already
4512 // moved variables to the heap, so this should not cause that to
4513 // happen unnecessarily.
4514 if (can_take_address
4515 && val->var_expression() == NULL
4516 && val->temporary_reference_expression() == NULL)
4517 can_take_address = false;
4519 Expression* td = Expression::make_type_descriptor(this->channel_->type(),
4520 loc);
4522 Bstatement* btemp = NULL;
4523 if (can_take_address)
4525 // The function doesn't change the value, so just take its
4526 // address directly.
4527 val = Expression::make_unary(OPERATOR_AND, val, loc);
4529 else
4531 // The value is not in a variable, or is small enough that it
4532 // might be in a register, and taking the address would push it
4533 // on the stack. Copy it into a temporary variable to take the
4534 // address.
4535 Temporary_statement* temp = Statement::make_temporary(element_type,
4536 val, loc);
4537 Expression* ref = Expression::make_temporary_reference(temp, loc);
4538 val = Expression::make_unary(OPERATOR_AND, ref, loc);
4539 btemp = temp->get_backend(context);
4542 Expression* call = Runtime::make_call(Runtime::CHANSEND, loc, 3, td,
4543 this->channel_, val);
4545 context->gogo()->lower_expression(context->function(), NULL, &call);
4546 Bexpression* bcall = call->get_backend(context);
4547 Bfunction* bfunction = context->function()->func_value()->get_decl();
4548 Bstatement* s = context->backend()->expression_statement(bfunction, bcall);
4550 if (btemp == NULL)
4551 return s;
4552 else
4553 return context->backend()->compound_statement(btemp, s);
4556 // Dump the AST representation for a send statement
4558 void
4559 Send_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
4561 ast_dump_context->print_indent();
4562 ast_dump_context->dump_expression(this->channel_);
4563 ast_dump_context->ostream() << " <- ";
4564 ast_dump_context->dump_expression(this->val_);
4565 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
4568 // Make a send statement.
4570 Send_statement*
4571 Statement::make_send_statement(Expression* channel, Expression* val,
4572 Location location)
4574 return new Send_statement(channel, val, location);
4577 // Class Select_clauses::Select_clause.
4579 // Traversal.
4582 Select_clauses::Select_clause::traverse(Traverse* traverse)
4584 if (!this->is_lowered_
4585 && (traverse->traverse_mask()
4586 & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0)
4588 if (this->channel_ != NULL)
4590 if (Expression::traverse(&this->channel_, traverse) == TRAVERSE_EXIT)
4591 return TRAVERSE_EXIT;
4593 if (this->val_ != NULL)
4595 if (Expression::traverse(&this->val_, traverse) == TRAVERSE_EXIT)
4596 return TRAVERSE_EXIT;
4598 if (this->closed_ != NULL)
4600 if (Expression::traverse(&this->closed_, traverse) == TRAVERSE_EXIT)
4601 return TRAVERSE_EXIT;
4604 if (this->statements_ != NULL)
4606 if (this->statements_->traverse(traverse) == TRAVERSE_EXIT)
4607 return TRAVERSE_EXIT;
4609 return TRAVERSE_CONTINUE;
4612 // Lowering. We call a function to register this clause, and arrange
4613 // to set any variables in any receive clause.
4615 void
4616 Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
4617 Block* b, Temporary_statement* sel)
4619 Location loc = this->location_;
4621 Expression* selref = Expression::make_temporary_reference(sel, loc);
4622 selref = Expression::make_unary(OPERATOR_AND, selref, loc);
4624 Expression* index_expr = Expression::make_integer_ul(this->index_, NULL,
4625 loc);
4627 if (this->is_default_)
4629 go_assert(this->channel_ == NULL && this->val_ == NULL);
4630 this->lower_default(b, selref, index_expr);
4631 this->is_lowered_ = true;
4632 return;
4635 // Evaluate the channel before the select statement.
4636 Temporary_statement* channel_temp = Statement::make_temporary(NULL,
4637 this->channel_,
4638 loc);
4639 b->add_statement(channel_temp);
4640 Expression* chanref = Expression::make_temporary_reference(channel_temp,
4641 loc);
4643 if (this->is_send_)
4644 this->lower_send(b, selref, chanref, index_expr);
4645 else
4646 this->lower_recv(gogo, function, b, selref, chanref, index_expr);
4648 // Now all references should be handled through the statements, not
4649 // through here.
4650 this->is_lowered_ = true;
4651 this->val_ = NULL;
4654 // Lower a default clause in a select statement.
4656 void
4657 Select_clauses::Select_clause::lower_default(Block* b, Expression* selref,
4658 Expression* index_expr)
4660 Location loc = this->location_;
4661 Expression* call = Runtime::make_call(Runtime::SELECTDEFAULT, loc, 2, selref,
4662 index_expr);
4663 b->add_statement(Statement::make_statement(call, true));
4666 // Lower a send clause in a select statement.
4668 void
4669 Select_clauses::Select_clause::lower_send(Block* b, Expression* selref,
4670 Expression* chanref,
4671 Expression* index_expr)
4673 Location loc = this->location_;
4675 Channel_type* ct = this->channel_->type()->channel_type();
4676 if (ct == NULL)
4677 return;
4679 Type* valtype = ct->element_type();
4681 // Note that copying the value to a temporary here means that we
4682 // evaluate the send values in the required order.
4683 Temporary_statement* val = Statement::make_temporary(valtype, this->val_,
4684 loc);
4685 b->add_statement(val);
4687 Expression* valref = Expression::make_temporary_reference(val, loc);
4688 Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc);
4690 Expression* call = Runtime::make_call(Runtime::SELECTSEND, loc, 4, selref,
4691 chanref, valaddr, index_expr);
4692 b->add_statement(Statement::make_statement(call, true));
4695 // Lower a receive clause in a select statement.
4697 void
4698 Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function,
4699 Block* b, Expression* selref,
4700 Expression* chanref,
4701 Expression* index_expr)
4703 Location loc = this->location_;
4705 Channel_type* ct = this->channel_->type()->channel_type();
4706 if (ct == NULL)
4707 return;
4709 Type* valtype = ct->element_type();
4710 Temporary_statement* val = Statement::make_temporary(valtype, NULL, loc);
4711 b->add_statement(val);
4713 Expression* valref = Expression::make_temporary_reference(val, loc);
4714 Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc);
4716 Temporary_statement* closed_temp = NULL;
4718 Expression* call;
4719 if (this->closed_ == NULL && this->closedvar_ == NULL)
4720 call = Runtime::make_call(Runtime::SELECTRECV, loc, 4, selref, chanref,
4721 valaddr, index_expr);
4722 else
4724 closed_temp = Statement::make_temporary(Type::lookup_bool_type(), NULL,
4725 loc);
4726 b->add_statement(closed_temp);
4727 Expression* cref = Expression::make_temporary_reference(closed_temp,
4728 loc);
4729 Expression* caddr = Expression::make_unary(OPERATOR_AND, cref, loc);
4730 call = Runtime::make_call(Runtime::SELECTRECV2, loc, 5, selref, chanref,
4731 valaddr, caddr, index_expr);
4734 b->add_statement(Statement::make_statement(call, true));
4736 // If the block of statements is executed, arrange for the received
4737 // value to move from VAL to the place where the statements expect
4738 // it.
4740 Block* init = NULL;
4742 if (this->var_ != NULL)
4744 go_assert(this->val_ == NULL);
4745 valref = Expression::make_temporary_reference(val, loc);
4746 this->var_->var_value()->set_init(valref);
4747 this->var_->var_value()->clear_type_from_chan_element();
4749 else if (this->val_ != NULL && !this->val_->is_sink_expression())
4751 init = new Block(b, loc);
4752 valref = Expression::make_temporary_reference(val, loc);
4753 init->add_statement(Statement::make_assignment(this->val_, valref, loc));
4756 if (this->closedvar_ != NULL)
4758 go_assert(this->closed_ == NULL);
4759 Expression* cref = Expression::make_temporary_reference(closed_temp,
4760 loc);
4761 this->closedvar_->var_value()->set_init(cref);
4763 else if (this->closed_ != NULL && !this->closed_->is_sink_expression())
4765 if (init == NULL)
4766 init = new Block(b, loc);
4767 Expression* cref = Expression::make_temporary_reference(closed_temp,
4768 loc);
4769 init->add_statement(Statement::make_assignment(this->closed_, cref,
4770 loc));
4773 if (init != NULL)
4775 gogo->lower_block(function, init);
4777 if (this->statements_ != NULL)
4778 init->add_statement(Statement::make_block_statement(this->statements_,
4779 loc));
4780 this->statements_ = init;
4784 // Determine types.
4786 void
4787 Select_clauses::Select_clause::determine_types()
4789 go_assert(this->is_lowered_);
4790 if (this->statements_ != NULL)
4791 this->statements_->determine_types();
4794 // Check types.
4796 void
4797 Select_clauses::Select_clause::check_types()
4799 if (this->is_default_)
4800 return;
4802 Channel_type* ct = this->channel_->type()->channel_type();
4803 if (ct == NULL)
4805 go_error_at(this->channel_->location(), "expected channel");
4806 return;
4809 if (this->is_send_ && !ct->may_send())
4810 go_error_at(this->location(), "invalid send on receive-only channel");
4811 else if (!this->is_send_ && !ct->may_receive())
4812 go_error_at(this->location(), "invalid receive on send-only channel");
4815 // Whether this clause may fall through to the statement which follows
4816 // the overall select statement.
4818 bool
4819 Select_clauses::Select_clause::may_fall_through() const
4821 if (this->statements_ == NULL)
4822 return true;
4823 return this->statements_->may_fall_through();
4826 // Return the backend representation for the statements to execute.
4828 Bstatement*
4829 Select_clauses::Select_clause::get_statements_backend(
4830 Translate_context* context)
4832 if (this->statements_ == NULL)
4833 return NULL;
4834 Bblock* bblock = this->statements_->get_backend(context);
4835 return context->backend()->block_statement(bblock);
4838 // Dump the AST representation for a select case clause
4840 void
4841 Select_clauses::Select_clause::dump_clause(
4842 Ast_dump_context* ast_dump_context) const
4844 ast_dump_context->print_indent();
4845 if (this->is_default_)
4847 ast_dump_context->ostream() << "default:";
4849 else
4851 ast_dump_context->ostream() << "case " ;
4852 if (this->is_send_)
4854 ast_dump_context->dump_expression(this->channel_);
4855 ast_dump_context->ostream() << " <- " ;
4856 if (this->val_ != NULL)
4857 ast_dump_context->dump_expression(this->val_);
4859 else
4861 if (this->val_ != NULL)
4862 ast_dump_context->dump_expression(this->val_);
4863 if (this->closed_ != NULL)
4865 // FIXME: can val_ == NULL and closed_ ! = NULL?
4866 ast_dump_context->ostream() << " , " ;
4867 ast_dump_context->dump_expression(this->closed_);
4869 if (this->closedvar_ != NULL || this->var_ != NULL)
4870 ast_dump_context->ostream() << " := " ;
4872 ast_dump_context->ostream() << " <- " ;
4873 ast_dump_context->dump_expression(this->channel_);
4875 ast_dump_context->ostream() << ":" ;
4877 ast_dump_context->dump_block(this->statements_);
4880 // Class Select_clauses.
4882 // Traversal.
4885 Select_clauses::traverse(Traverse* traverse)
4887 for (Clauses::iterator p = this->clauses_.begin();
4888 p != this->clauses_.end();
4889 ++p)
4891 if (p->traverse(traverse) == TRAVERSE_EXIT)
4892 return TRAVERSE_EXIT;
4894 return TRAVERSE_CONTINUE;
4897 // Lowering. Here we pull out the channel and the send values, to
4898 // enforce the order of evaluation. We also add explicit send and
4899 // receive statements to the clauses.
4901 void
4902 Select_clauses::lower(Gogo* gogo, Named_object* function, Block* b,
4903 Temporary_statement* sel)
4905 for (Clauses::iterator p = this->clauses_.begin();
4906 p != this->clauses_.end();
4907 ++p)
4908 p->lower(gogo, function, b, sel);
4911 // Determine types.
4913 void
4914 Select_clauses::determine_types()
4916 for (Clauses::iterator p = this->clauses_.begin();
4917 p != this->clauses_.end();
4918 ++p)
4919 p->determine_types();
4922 // Check types.
4924 void
4925 Select_clauses::check_types()
4927 for (Clauses::iterator p = this->clauses_.begin();
4928 p != this->clauses_.end();
4929 ++p)
4930 p->check_types();
4933 // Return whether these select clauses fall through to the statement
4934 // following the overall select statement.
4936 bool
4937 Select_clauses::may_fall_through() const
4939 for (Clauses::const_iterator p = this->clauses_.begin();
4940 p != this->clauses_.end();
4941 ++p)
4942 if (p->may_fall_through())
4943 return true;
4944 return false;
4947 // Convert to the backend representation. We have already accumulated
4948 // all the select information. Now we call selectgo, which will
4949 // return the index of the clause to execute.
4951 Bstatement*
4952 Select_clauses::get_backend(Translate_context* context,
4953 Temporary_statement* sel,
4954 Unnamed_label *break_label,
4955 Location location)
4957 size_t count = this->clauses_.size();
4958 std::vector<std::vector<Bexpression*> > cases(count);
4959 std::vector<Bstatement*> clauses(count);
4961 Type* int32_type = Type::lookup_integer_type("int32");
4963 int i = 0;
4964 for (Clauses::iterator p = this->clauses_.begin();
4965 p != this->clauses_.end();
4966 ++p, ++i)
4968 int index = p->index();
4969 Expression* index_expr = Expression::make_integer_ul(index, int32_type,
4970 location);
4971 cases[i].push_back(index_expr->get_backend(context));
4973 Bstatement* s = p->get_statements_backend(context);
4974 Location gloc = (p->statements() == NULL
4975 ? p->location()
4976 : p->statements()->end_location());
4977 Bstatement* g = break_label->get_goto(context, gloc);
4979 if (s == NULL)
4980 clauses[i] = g;
4981 else
4982 clauses[i] = context->backend()->compound_statement(s, g);
4985 Expression* selref = Expression::make_temporary_reference(sel, location);
4986 selref = Expression::make_unary(OPERATOR_AND, selref, location);
4987 Expression* call = Runtime::make_call(Runtime::SELECTGO, location, 1,
4988 selref);
4989 context->gogo()->lower_expression(context->function(), NULL, &call);
4990 Bexpression* bcall = call->get_backend(context);
4992 if (count == 0)
4994 Bfunction* bfunction = context->function()->func_value()->get_decl();
4995 return context->backend()->expression_statement(bfunction, bcall);
4998 std::vector<Bstatement*> statements;
4999 statements.reserve(2);
5001 Bfunction* bfunction = context->function()->func_value()->get_decl();
5002 Bstatement* switch_stmt = context->backend()->switch_statement(bfunction,
5003 bcall,
5004 cases,
5005 clauses,
5006 location);
5007 statements.push_back(switch_stmt);
5009 Bstatement* ldef = break_label->get_definition(context);
5010 statements.push_back(ldef);
5012 return context->backend()->statement_list(statements);
5014 // Dump the AST representation for select clauses.
5016 void
5017 Select_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
5019 for (Clauses::const_iterator p = this->clauses_.begin();
5020 p != this->clauses_.end();
5021 ++p)
5022 p->dump_clause(ast_dump_context);
5025 // Class Select_statement.
5027 // Return the break label for this switch statement, creating it if
5028 // necessary.
5030 Unnamed_label*
5031 Select_statement::break_label()
5033 if (this->break_label_ == NULL)
5034 this->break_label_ = new Unnamed_label(this->location());
5035 return this->break_label_;
5038 // Lower a select statement. This will still return a select
5039 // statement, but it will be modified to implement the order of
5040 // evaluation rules, and to include the send and receive statements as
5041 // explicit statements in the clauses.
5043 Statement*
5044 Select_statement::do_lower(Gogo* gogo, Named_object* function,
5045 Block* enclosing, Statement_inserter*)
5047 if (this->is_lowered_)
5048 return this;
5050 Location loc = this->location();
5052 Block* b = new Block(enclosing, loc);
5054 go_assert(this->sel_ == NULL);
5056 int ncases = this->clauses_->size();
5057 Type* selstruct_type = Channel_type::select_type(ncases);
5058 this->sel_ = Statement::make_temporary(selstruct_type, NULL, loc);
5059 b->add_statement(this->sel_);
5061 int64_t selstruct_size;
5062 if (!selstruct_type->backend_type_size(gogo, &selstruct_size))
5064 go_assert(saw_errors());
5065 return Statement::make_error_statement(loc);
5068 Expression* ref = Expression::make_temporary_reference(this->sel_, loc);
5069 ref = Expression::make_unary(OPERATOR_AND, ref, loc);
5070 Expression* selstruct_size_expr =
5071 Expression::make_integer_int64(selstruct_size, NULL, loc);
5072 Expression* size_expr = Expression::make_integer_ul(ncases, NULL, loc);
5073 Expression* call = Runtime::make_call(Runtime::NEWSELECT, loc, 3,
5074 ref, selstruct_size_expr, size_expr);
5075 b->add_statement(Statement::make_statement(call, true));
5077 this->clauses_->lower(gogo, function, b, this->sel_);
5078 this->is_lowered_ = true;
5079 b->add_statement(this);
5081 return Statement::make_block_statement(b, loc);
5084 // Whether the select statement itself may fall through to the following
5085 // statement.
5087 bool
5088 Select_statement::do_may_fall_through() const
5090 // A select statement is terminating if no break statement
5091 // refers to it and all of its clauses are terminating.
5092 if (this->break_label_ != NULL)
5093 return true;
5094 return this->clauses_->may_fall_through();
5097 // Return the backend representation for a select statement.
5099 Bstatement*
5100 Select_statement::do_get_backend(Translate_context* context)
5102 return this->clauses_->get_backend(context, this->sel_, this->break_label(),
5103 this->location());
5106 // Dump the AST representation for a select statement.
5108 void
5109 Select_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
5111 ast_dump_context->print_indent();
5112 ast_dump_context->ostream() << "select";
5113 if (ast_dump_context->dump_subblocks())
5115 ast_dump_context->ostream() << " {" << dsuffix(location()) << std::endl;
5116 this->clauses_->dump_clauses(ast_dump_context);
5117 ast_dump_context->ostream() << "}";
5119 ast_dump_context->ostream() << std::endl;
5122 // Make a select statement.
5124 Select_statement*
5125 Statement::make_select_statement(Location location)
5127 return new Select_statement(location);
5130 // Class For_statement.
5132 // Traversal.
5135 For_statement::do_traverse(Traverse* traverse)
5137 if (this->init_ != NULL)
5139 if (this->init_->traverse(traverse) == TRAVERSE_EXIT)
5140 return TRAVERSE_EXIT;
5142 if (this->cond_ != NULL)
5144 if (this->traverse_expression(traverse, &this->cond_) == TRAVERSE_EXIT)
5145 return TRAVERSE_EXIT;
5147 if (this->post_ != NULL)
5149 if (this->post_->traverse(traverse) == TRAVERSE_EXIT)
5150 return TRAVERSE_EXIT;
5152 return this->statements_->traverse(traverse);
5155 // Lower a For_statement into if statements and gotos. Getting rid of
5156 // complex statements make it easier to handle garbage collection.
5158 Statement*
5159 For_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
5160 Statement_inserter*)
5162 Statement* s;
5163 Location loc = this->location();
5165 Block* b = new Block(enclosing, this->location());
5166 if (this->init_ != NULL)
5168 s = Statement::make_block_statement(this->init_,
5169 this->init_->start_location());
5170 b->add_statement(s);
5173 Unnamed_label* entry = NULL;
5174 if (this->cond_ != NULL)
5176 entry = new Unnamed_label(this->location());
5177 b->add_statement(Statement::make_goto_unnamed_statement(entry, loc));
5180 Unnamed_label* top = new Unnamed_label(this->location());
5181 top->set_derived_from(this);
5182 b->add_statement(Statement::make_unnamed_label_statement(top));
5184 s = Statement::make_block_statement(this->statements_,
5185 this->statements_->start_location());
5186 b->add_statement(s);
5188 Location end_loc = this->statements_->end_location();
5190 Unnamed_label* cont = this->continue_label_;
5191 if (cont != NULL)
5192 b->add_statement(Statement::make_unnamed_label_statement(cont));
5194 if (this->post_ != NULL)
5196 s = Statement::make_block_statement(this->post_,
5197 this->post_->start_location());
5198 b->add_statement(s);
5199 end_loc = this->post_->end_location();
5202 if (this->cond_ == NULL)
5203 b->add_statement(Statement::make_goto_unnamed_statement(top, end_loc));
5204 else
5206 b->add_statement(Statement::make_unnamed_label_statement(entry));
5208 Location cond_loc = this->cond_->location();
5209 Block* then_block = new Block(b, cond_loc);
5210 s = Statement::make_goto_unnamed_statement(top, cond_loc);
5211 then_block->add_statement(s);
5213 s = Statement::make_if_statement(this->cond_, then_block, NULL, cond_loc);
5214 b->add_statement(s);
5217 Unnamed_label* brk = this->break_label_;
5218 if (brk != NULL)
5219 b->add_statement(Statement::make_unnamed_label_statement(brk));
5221 b->set_end_location(end_loc);
5223 Statement* bs = Statement::make_block_statement(b, loc);
5224 bs->block_statement()->set_is_lowered_for_statement();
5225 return bs;
5228 // Return the break label, creating it if necessary.
5230 Unnamed_label*
5231 For_statement::break_label()
5233 if (this->break_label_ == NULL)
5234 this->break_label_ = new Unnamed_label(this->location());
5235 return this->break_label_;
5238 // Return the continue LABEL_EXPR.
5240 Unnamed_label*
5241 For_statement::continue_label()
5243 if (this->continue_label_ == NULL)
5244 this->continue_label_ = new Unnamed_label(this->location());
5245 return this->continue_label_;
5248 // Set the break and continue labels a for statement. This is used
5249 // when lowering a for range statement.
5251 void
5252 For_statement::set_break_continue_labels(Unnamed_label* break_label,
5253 Unnamed_label* continue_label)
5255 go_assert(this->break_label_ == NULL && this->continue_label_ == NULL);
5256 this->break_label_ = break_label;
5257 this->continue_label_ = continue_label;
5260 // Whether the overall statement may fall through.
5262 bool
5263 For_statement::do_may_fall_through() const
5265 // A for loop is terminating if it has no condition and
5266 // no break statement.
5267 if(this->cond_ != NULL)
5268 return true;
5269 if(this->break_label_ != NULL)
5270 return true;
5271 return false;
5274 // Dump the AST representation for a for statement.
5276 void
5277 For_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
5279 if (this->init_ != NULL && ast_dump_context->dump_subblocks())
5281 ast_dump_context->print_indent();
5282 ast_dump_context->indent();
5283 ast_dump_context->ostream() << "// INIT " << std::endl;
5284 ast_dump_context->dump_block(this->init_);
5285 ast_dump_context->unindent();
5287 ast_dump_context->print_indent();
5288 ast_dump_context->ostream() << "for ";
5289 if (this->cond_ != NULL)
5290 ast_dump_context->dump_expression(this->cond_);
5292 if (ast_dump_context->dump_subblocks())
5294 ast_dump_context->ostream() << " {" << std::endl;
5295 ast_dump_context->dump_block(this->statements_);
5296 if (this->init_ != NULL)
5298 ast_dump_context->print_indent();
5299 ast_dump_context->ostream() << "// POST " << std::endl;
5300 ast_dump_context->dump_block(this->post_);
5302 ast_dump_context->unindent();
5304 ast_dump_context->print_indent();
5305 ast_dump_context->ostream() << "}";
5308 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
5311 // Make a for statement.
5313 For_statement*
5314 Statement::make_for_statement(Block* init, Expression* cond, Block* post,
5315 Location location)
5317 return new For_statement(init, cond, post, location);
5320 // Class For_range_statement.
5322 // Traversal.
5325 For_range_statement::do_traverse(Traverse* traverse)
5327 if (this->index_var_ != NULL)
5329 if (this->traverse_expression(traverse, &this->index_var_)
5330 == TRAVERSE_EXIT)
5331 return TRAVERSE_EXIT;
5333 if (this->value_var_ != NULL)
5335 if (this->traverse_expression(traverse, &this->value_var_)
5336 == TRAVERSE_EXIT)
5337 return TRAVERSE_EXIT;
5339 if (this->traverse_expression(traverse, &this->range_) == TRAVERSE_EXIT)
5340 return TRAVERSE_EXIT;
5341 return this->statements_->traverse(traverse);
5344 // Lower a for range statement. For simplicity we lower this into a
5345 // for statement, which will then be lowered in turn to goto
5346 // statements.
5348 Statement*
5349 For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
5350 Statement_inserter*)
5352 Type* range_type = this->range_->type();
5353 if (range_type->points_to() != NULL
5354 && range_type->points_to()->array_type() != NULL
5355 && !range_type->points_to()->is_slice_type())
5356 range_type = range_type->points_to();
5358 Type* index_type;
5359 Type* value_type = NULL;
5360 if (range_type->array_type() != NULL)
5362 index_type = Type::lookup_integer_type("int");
5363 value_type = range_type->array_type()->element_type();
5365 else if (range_type->is_string_type())
5367 index_type = Type::lookup_integer_type("int");
5368 value_type = gogo->lookup_global("rune")->type_value();
5370 else if (range_type->map_type() != NULL)
5372 index_type = range_type->map_type()->key_type();
5373 value_type = range_type->map_type()->val_type();
5375 else if (range_type->channel_type() != NULL)
5377 index_type = range_type->channel_type()->element_type();
5378 if (this->value_var_ != NULL)
5380 if (!this->value_var_->type()->is_error())
5381 this->report_error(_("too many variables for range clause "
5382 "with channel"));
5383 return Statement::make_error_statement(this->location());
5386 else
5388 this->report_error(_("range clause must have "
5389 "array, slice, string, map, or channel type"));
5390 return Statement::make_error_statement(this->location());
5393 Location loc = this->location();
5394 Block* temp_block = new Block(enclosing, loc);
5396 Named_object* range_object = NULL;
5397 Temporary_statement* range_temp = NULL;
5398 Var_expression* ve = this->range_->var_expression();
5399 if (ve != NULL)
5400 range_object = ve->named_object();
5401 else
5403 range_temp = Statement::make_temporary(NULL, this->range_, loc);
5404 temp_block->add_statement(range_temp);
5405 this->range_ = NULL;
5408 Temporary_statement* index_temp = Statement::make_temporary(index_type,
5409 NULL, loc);
5410 temp_block->add_statement(index_temp);
5412 Temporary_statement* value_temp = NULL;
5413 if (this->value_var_ != NULL)
5415 value_temp = Statement::make_temporary(value_type, NULL, loc);
5416 temp_block->add_statement(value_temp);
5419 Block* body = new Block(temp_block, loc);
5421 Block* init;
5422 Expression* cond;
5423 Block* iter_init;
5424 Block* post;
5426 // Arrange to do a loop appropriate for the type. We will produce
5427 // for INIT ; COND ; POST {
5428 // ITER_INIT
5429 // INDEX = INDEX_TEMP
5430 // VALUE = VALUE_TEMP // If there is a value
5431 // original statements
5432 // }
5434 if (range_type->is_slice_type())
5435 this->lower_range_slice(gogo, temp_block, body, range_object, range_temp,
5436 index_temp, value_temp, &init, &cond, &iter_init,
5437 &post);
5438 else if (range_type->array_type() != NULL)
5439 this->lower_range_array(gogo, temp_block, body, range_object, range_temp,
5440 index_temp, value_temp, &init, &cond, &iter_init,
5441 &post);
5442 else if (range_type->is_string_type())
5443 this->lower_range_string(gogo, temp_block, body, range_object, range_temp,
5444 index_temp, value_temp, &init, &cond, &iter_init,
5445 &post);
5446 else if (range_type->map_type() != NULL)
5447 this->lower_range_map(gogo, range_type->map_type(), temp_block, body,
5448 range_object, range_temp, index_temp, value_temp,
5449 &init, &cond, &iter_init, &post);
5450 else if (range_type->channel_type() != NULL)
5451 this->lower_range_channel(gogo, temp_block, body, range_object, range_temp,
5452 index_temp, value_temp, &init, &cond, &iter_init,
5453 &post);
5454 else
5455 go_unreachable();
5457 if (iter_init != NULL)
5458 body->add_statement(Statement::make_block_statement(iter_init, loc));
5460 if (this->index_var_ != NULL)
5462 Statement* assign;
5463 Expression* index_ref =
5464 Expression::make_temporary_reference(index_temp, loc);
5465 if (this->value_var_ == NULL)
5466 assign = Statement::make_assignment(this->index_var_, index_ref, loc);
5467 else
5469 Expression_list* lhs = new Expression_list();
5470 lhs->push_back(this->index_var_);
5471 lhs->push_back(this->value_var_);
5473 Expression_list* rhs = new Expression_list();
5474 rhs->push_back(index_ref);
5475 rhs->push_back(Expression::make_temporary_reference(value_temp, loc));
5477 assign = Statement::make_tuple_assignment(lhs, rhs, loc);
5479 body->add_statement(assign);
5482 body->add_statement(Statement::make_block_statement(this->statements_, loc));
5484 body->set_end_location(this->statements_->end_location());
5486 For_statement* loop = Statement::make_for_statement(init, cond, post,
5487 this->location());
5488 loop->add_statements(body);
5489 loop->set_break_continue_labels(this->break_label_, this->continue_label_);
5491 temp_block->add_statement(loop);
5493 return Statement::make_block_statement(temp_block, loc);
5496 // Return a reference to the range, which may be in RANGE_OBJECT or in
5497 // RANGE_TEMP.
5499 Expression*
5500 For_range_statement::make_range_ref(Named_object* range_object,
5501 Temporary_statement* range_temp,
5502 Location loc)
5504 if (range_object != NULL)
5505 return Expression::make_var_reference(range_object, loc);
5506 else
5507 return Expression::make_temporary_reference(range_temp, loc);
5510 // Return a call to the predeclared function FUNCNAME passing a
5511 // reference to the temporary variable ARG.
5513 Call_expression*
5514 For_range_statement::call_builtin(Gogo* gogo, const char* funcname,
5515 Expression* arg,
5516 Location loc)
5518 Named_object* no = gogo->lookup_global(funcname);
5519 go_assert(no != NULL && no->is_function_declaration());
5520 Expression* func = Expression::make_func_reference(no, NULL, loc);
5521 Expression_list* params = new Expression_list();
5522 params->push_back(arg);
5523 return Expression::make_call(func, params, false, loc);
5526 // Lower a for range over an array.
5528 void
5529 For_range_statement::lower_range_array(Gogo* gogo,
5530 Block* enclosing,
5531 Block* body_block,
5532 Named_object* range_object,
5533 Temporary_statement* range_temp,
5534 Temporary_statement* index_temp,
5535 Temporary_statement* value_temp,
5536 Block** pinit,
5537 Expression** pcond,
5538 Block** piter_init,
5539 Block** ppost)
5541 Location loc = this->location();
5543 // The loop we generate:
5544 // len_temp := len(range)
5545 // range_temp := range
5546 // for index_temp = 0; index_temp < len_temp; index_temp++ {
5547 // value_temp = range_temp[index_temp]
5548 // index = index_temp
5549 // value = value_temp
5550 // original body
5551 // }
5553 // Set *PINIT to
5554 // var len_temp int
5555 // len_temp = len(range)
5556 // index_temp = 0
5558 Block* init = new Block(enclosing, loc);
5560 Expression* ref = this->make_range_ref(range_object, range_temp, loc);
5561 range_temp = Statement::make_temporary(NULL, ref, loc);
5562 Expression* len_call = this->call_builtin(gogo, "len", ref, loc);
5563 Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(),
5564 len_call, loc);
5565 init->add_statement(range_temp);
5566 init->add_statement(len_temp);
5568 Expression* zexpr = Expression::make_integer_ul(0, NULL, loc);
5570 Temporary_reference_expression* tref =
5571 Expression::make_temporary_reference(index_temp, loc);
5572 tref->set_is_lvalue();
5573 Statement* s = Statement::make_assignment(tref, zexpr, loc);
5574 init->add_statement(s);
5576 *pinit = init;
5578 // Set *PCOND to
5579 // index_temp < len_temp
5581 ref = Expression::make_temporary_reference(index_temp, loc);
5582 Expression* ref2 = Expression::make_temporary_reference(len_temp, loc);
5583 Expression* lt = Expression::make_binary(OPERATOR_LT, ref, ref2, loc);
5585 *pcond = lt;
5587 // Set *PITER_INIT to
5588 // value_temp = range[index_temp]
5590 Block* iter_init = NULL;
5591 if (value_temp != NULL)
5593 iter_init = new Block(body_block, loc);
5595 ref = Expression::make_temporary_reference(range_temp, loc);
5596 Expression* ref2 = Expression::make_temporary_reference(index_temp, loc);
5597 Expression* index = Expression::make_index(ref, ref2, NULL, NULL, loc);
5599 tref = Expression::make_temporary_reference(value_temp, loc);
5600 tref->set_is_lvalue();
5601 s = Statement::make_assignment(tref, index, loc);
5603 iter_init->add_statement(s);
5605 *piter_init = iter_init;
5607 // Set *PPOST to
5608 // index_temp++
5610 Block* post = new Block(enclosing, loc);
5611 tref = Expression::make_temporary_reference(index_temp, loc);
5612 tref->set_is_lvalue();
5613 s = Statement::make_inc_statement(tref);
5614 post->add_statement(s);
5615 *ppost = post;
5618 // Lower a for range over a slice.
5620 void
5621 For_range_statement::lower_range_slice(Gogo* gogo,
5622 Block* enclosing,
5623 Block* body_block,
5624 Named_object* range_object,
5625 Temporary_statement* range_temp,
5626 Temporary_statement* index_temp,
5627 Temporary_statement* value_temp,
5628 Block** pinit,
5629 Expression** pcond,
5630 Block** piter_init,
5631 Block** ppost)
5633 Location loc = this->location();
5635 // The loop we generate:
5636 // for_temp := range
5637 // len_temp := len(for_temp)
5638 // for index_temp = 0; index_temp < len_temp; index_temp++ {
5639 // value_temp = for_temp[index_temp]
5640 // index = index_temp
5641 // value = value_temp
5642 // original body
5643 // }
5645 // Using for_temp means that we don't need to check bounds when
5646 // fetching range_temp[index_temp].
5648 // Set *PINIT to
5649 // range_temp := range
5650 // var len_temp int
5651 // len_temp = len(range_temp)
5652 // index_temp = 0
5654 Block* init = new Block(enclosing, loc);
5656 Expression* ref = this->make_range_ref(range_object, range_temp, loc);
5657 Temporary_statement* for_temp = Statement::make_temporary(NULL, ref, loc);
5658 init->add_statement(for_temp);
5660 ref = Expression::make_temporary_reference(for_temp, loc);
5661 Expression* len_call = this->call_builtin(gogo, "len", ref, loc);
5662 Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(),
5663 len_call, loc);
5664 init->add_statement(len_temp);
5666 Expression* zexpr = Expression::make_integer_ul(0, NULL, loc);
5668 Temporary_reference_expression* tref =
5669 Expression::make_temporary_reference(index_temp, loc);
5670 tref->set_is_lvalue();
5671 Statement* s = Statement::make_assignment(tref, zexpr, loc);
5672 init->add_statement(s);
5674 *pinit = init;
5676 // Set *PCOND to
5677 // index_temp < len_temp
5679 ref = Expression::make_temporary_reference(index_temp, loc);
5680 Expression* ref2 = Expression::make_temporary_reference(len_temp, loc);
5681 Expression* lt = Expression::make_binary(OPERATOR_LT, ref, ref2, loc);
5683 *pcond = lt;
5685 // Set *PITER_INIT to
5686 // value_temp = range[index_temp]
5688 Block* iter_init = NULL;
5689 if (value_temp != NULL)
5691 iter_init = new Block(body_block, loc);
5693 ref = Expression::make_temporary_reference(for_temp, loc);
5694 Expression* ref2 = Expression::make_temporary_reference(index_temp, loc);
5695 Expression* index = Expression::make_index(ref, ref2, NULL, NULL, loc);
5697 tref = Expression::make_temporary_reference(value_temp, loc);
5698 tref->set_is_lvalue();
5699 s = Statement::make_assignment(tref, index, loc);
5701 iter_init->add_statement(s);
5703 *piter_init = iter_init;
5705 // Set *PPOST to
5706 // index_temp++
5708 Block* post = new Block(enclosing, loc);
5709 tref = Expression::make_temporary_reference(index_temp, loc);
5710 tref->set_is_lvalue();
5711 s = Statement::make_inc_statement(tref);
5712 post->add_statement(s);
5713 *ppost = post;
5716 // Lower a for range over a string.
5718 void
5719 For_range_statement::lower_range_string(Gogo* gogo,
5720 Block* enclosing,
5721 Block* body_block,
5722 Named_object* range_object,
5723 Temporary_statement* range_temp,
5724 Temporary_statement* index_temp,
5725 Temporary_statement* value_temp,
5726 Block** pinit,
5727 Expression** pcond,
5728 Block** piter_init,
5729 Block** ppost)
5731 Location loc = this->location();
5733 // The loop we generate:
5734 // len_temp := len(range)
5735 // var next_index_temp int
5736 // for index_temp = 0; index_temp < len_temp; index_temp = next_index_temp {
5737 // value_temp = rune(range[index_temp])
5738 // if value_temp < utf8.RuneSelf {
5739 // next_index_temp = index_temp + 1
5740 // } else {
5741 // value_temp, next_index_temp = decoderune(range, index_temp)
5742 // }
5743 // index = index_temp
5744 // value = value_temp
5745 // // original body
5746 // }
5748 // Set *PINIT to
5749 // len_temp := len(range)
5750 // var next_index_temp int
5751 // index_temp = 0
5752 // var value_temp rune // if value_temp not passed in
5754 Block* init = new Block(enclosing, loc);
5756 Expression* ref = this->make_range_ref(range_object, range_temp, loc);
5757 Call_expression* call = this->call_builtin(gogo, "len", ref, loc);
5758 Temporary_statement* len_temp =
5759 Statement::make_temporary(index_temp->type(), call, loc);
5760 init->add_statement(len_temp);
5762 Temporary_statement* next_index_temp =
5763 Statement::make_temporary(index_temp->type(), NULL, loc);
5764 init->add_statement(next_index_temp);
5766 Temporary_reference_expression* index_ref =
5767 Expression::make_temporary_reference(index_temp, loc);
5768 index_ref->set_is_lvalue();
5769 Expression* zexpr = Expression::make_integer_ul(0, index_temp->type(), loc);
5770 Statement* s = Statement::make_assignment(index_ref, zexpr, loc);
5771 init->add_statement(s);
5773 Type* rune_type;
5774 if (value_temp != NULL)
5775 rune_type = value_temp->type();
5776 else
5778 rune_type = gogo->lookup_global("rune")->type_value();
5779 value_temp = Statement::make_temporary(rune_type, NULL, loc);
5780 init->add_statement(value_temp);
5783 *pinit = init;
5785 // Set *PCOND to
5786 // index_temp < len_temp
5788 index_ref = Expression::make_temporary_reference(index_temp, loc);
5789 Expression* len_ref =
5790 Expression::make_temporary_reference(len_temp, loc);
5791 *pcond = Expression::make_binary(OPERATOR_LT, index_ref, len_ref, loc);
5793 // Set *PITER_INIT to
5794 // value_temp = rune(range[index_temp])
5795 // if value_temp < utf8.RuneSelf {
5796 // next_index_temp = index_temp + 1
5797 // } else {
5798 // value_temp, next_index_temp = decoderune(range, index_temp)
5799 // }
5801 Block* iter_init = new Block(body_block, loc);
5803 ref = this->make_range_ref(range_object, range_temp, loc);
5804 index_ref = Expression::make_temporary_reference(index_temp, loc);
5805 ref = Expression::make_string_index(ref, index_ref, NULL, loc);
5806 ref = Expression::make_cast(rune_type, ref, loc);
5807 Temporary_reference_expression* value_ref =
5808 Expression::make_temporary_reference(value_temp, loc);
5809 value_ref->set_is_lvalue();
5810 s = Statement::make_assignment(value_ref, ref, loc);
5811 iter_init->add_statement(s);
5813 value_ref = Expression::make_temporary_reference(value_temp, loc);
5814 Expression* rune_self = Expression::make_integer_ul(0x80, rune_type, loc);
5815 Expression* cond = Expression::make_binary(OPERATOR_LT, value_ref, rune_self,
5816 loc);
5818 Block* then_block = new Block(iter_init, loc);
5820 Temporary_reference_expression* lhs =
5821 Expression::make_temporary_reference(next_index_temp, loc);
5822 lhs->set_is_lvalue();
5823 index_ref = Expression::make_temporary_reference(index_temp, loc);
5824 Expression* one = Expression::make_integer_ul(1, index_temp->type(), loc);
5825 Expression* sum = Expression::make_binary(OPERATOR_PLUS, index_ref, one,
5826 loc);
5827 s = Statement::make_assignment(lhs, sum, loc);
5828 then_block->add_statement(s);
5830 Block* else_block = new Block(iter_init, loc);
5832 ref = this->make_range_ref(range_object, range_temp, loc);
5833 index_ref = Expression::make_temporary_reference(index_temp, loc);
5834 call = Runtime::make_call(Runtime::DECODERUNE, loc, 2, ref, index_ref);
5836 value_ref = Expression::make_temporary_reference(value_temp, loc);
5837 value_ref->set_is_lvalue();
5838 Expression* res = Expression::make_call_result(call, 0);
5839 s = Statement::make_assignment(value_ref, res, loc);
5840 else_block->add_statement(s);
5842 lhs = Expression::make_temporary_reference(next_index_temp, loc);
5843 lhs->set_is_lvalue();
5844 res = Expression::make_call_result(call, 1);
5845 s = Statement::make_assignment(lhs, res, loc);
5846 else_block->add_statement(s);
5848 s = Statement::make_if_statement(cond, then_block, else_block, loc);
5849 iter_init->add_statement(s);
5851 *piter_init = iter_init;
5853 // Set *PPOST to
5854 // index_temp = next_index_temp
5856 Block* post = new Block(enclosing, loc);
5858 index_ref = Expression::make_temporary_reference(index_temp, loc);
5859 index_ref->set_is_lvalue();
5860 ref = Expression::make_temporary_reference(next_index_temp, loc);
5861 s = Statement::make_assignment(index_ref, ref, loc);
5863 post->add_statement(s);
5864 *ppost = post;
5867 // Lower a for range over a map.
5869 void
5870 For_range_statement::lower_range_map(Gogo* gogo,
5871 Map_type* map_type,
5872 Block* enclosing,
5873 Block* body_block,
5874 Named_object* range_object,
5875 Temporary_statement* range_temp,
5876 Temporary_statement* index_temp,
5877 Temporary_statement* value_temp,
5878 Block** pinit,
5879 Expression** pcond,
5880 Block** piter_init,
5881 Block** ppost)
5883 Location loc = this->location();
5885 // The runtime uses a struct to handle ranges over a map. The
5886 // struct is built by Map_type::hiter_type for a specific map type.
5888 // The loop we generate:
5889 // var hiter map_iteration_struct
5890 // for mapiterinit(type, range, &hiter); hiter.key != nil; mapiternext(&hiter) {
5891 // index_temp = *hiter.key
5892 // value_temp = *hiter.val
5893 // index = index_temp
5894 // value = value_temp
5895 // original body
5896 // }
5898 // Set *PINIT to
5899 // var hiter map_iteration_struct
5900 // runtime.mapiterinit(type, range, &hiter)
5902 Block* init = new Block(enclosing, loc);
5904 Type* map_iteration_type = map_type->hiter_type(gogo);
5905 Temporary_statement* hiter = Statement::make_temporary(map_iteration_type,
5906 NULL, loc);
5907 init->add_statement(hiter);
5909 Expression* p1 = Expression::make_type_descriptor(map_type, loc);
5910 Expression* p2 = this->make_range_ref(range_object, range_temp, loc);
5911 Expression* ref = Expression::make_temporary_reference(hiter, loc);
5912 Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
5913 Expression* call = Runtime::make_call(Runtime::MAPITERINIT, loc, 3,
5914 p1, p2, p3);
5915 init->add_statement(Statement::make_statement(call, true));
5917 *pinit = init;
5919 // Set *PCOND to
5920 // hiter.key != nil
5922 ref = Expression::make_temporary_reference(hiter, loc);
5923 ref = Expression::make_field_reference(ref, 0, loc);
5924 Expression* ne = Expression::make_binary(OPERATOR_NOTEQ, ref,
5925 Expression::make_nil(loc),
5926 loc);
5927 *pcond = ne;
5929 // Set *PITER_INIT to
5930 // index_temp = *hiter.key
5931 // value_temp = *hiter.val
5933 Block* iter_init = new Block(body_block, loc);
5935 Expression* lhs = Expression::make_temporary_reference(index_temp, loc);
5936 Expression* rhs = Expression::make_temporary_reference(hiter, loc);
5937 rhs = Expression::make_field_reference(ref, 0, loc);
5938 rhs = Expression::make_unary(OPERATOR_MULT, ref, loc);
5939 Statement* set = Statement::make_assignment(lhs, rhs, loc);
5940 iter_init->add_statement(set);
5942 if (value_temp != NULL)
5944 lhs = Expression::make_temporary_reference(value_temp, loc);
5945 rhs = Expression::make_temporary_reference(hiter, loc);
5946 rhs = Expression::make_field_reference(rhs, 1, loc);
5947 rhs = Expression::make_unary(OPERATOR_MULT, rhs, loc);
5948 set = Statement::make_assignment(lhs, rhs, loc);
5949 iter_init->add_statement(set);
5952 *piter_init = iter_init;
5954 // Set *PPOST to
5955 // mapiternext(&hiter)
5957 Block* post = new Block(enclosing, loc);
5959 ref = Expression::make_temporary_reference(hiter, loc);
5960 p1 = Expression::make_unary(OPERATOR_AND, ref, loc);
5961 call = Runtime::make_call(Runtime::MAPITERNEXT, loc, 1, p1);
5962 post->add_statement(Statement::make_statement(call, true));
5964 *ppost = post;
5967 // Lower a for range over a channel.
5969 void
5970 For_range_statement::lower_range_channel(Gogo*,
5971 Block*,
5972 Block* body_block,
5973 Named_object* range_object,
5974 Temporary_statement* range_temp,
5975 Temporary_statement* index_temp,
5976 Temporary_statement* value_temp,
5977 Block** pinit,
5978 Expression** pcond,
5979 Block** piter_init,
5980 Block** ppost)
5982 go_assert(value_temp == NULL);
5984 Location loc = this->location();
5986 // The loop we generate:
5987 // for {
5988 // index_temp, ok_temp = <-range
5989 // if !ok_temp {
5990 // break
5991 // }
5992 // index = index_temp
5993 // original body
5994 // }
5996 // We have no initialization code, no condition, and no post code.
5998 *pinit = NULL;
5999 *pcond = NULL;
6000 *ppost = NULL;
6002 // Set *PITER_INIT to
6003 // index_temp, ok_temp = <-range
6004 // if !ok_temp {
6005 // break
6006 // }
6008 Block* iter_init = new Block(body_block, loc);
6010 Temporary_statement* ok_temp =
6011 Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
6012 iter_init->add_statement(ok_temp);
6014 Expression* cref = this->make_range_ref(range_object, range_temp, loc);
6015 Temporary_reference_expression* iref =
6016 Expression::make_temporary_reference(index_temp, loc);
6017 iref->set_is_lvalue();
6018 Temporary_reference_expression* oref =
6019 Expression::make_temporary_reference(ok_temp, loc);
6020 oref->set_is_lvalue();
6021 Statement* s = Statement::make_tuple_receive_assignment(iref, oref, cref,
6022 loc);
6023 iter_init->add_statement(s);
6025 Block* then_block = new Block(iter_init, loc);
6026 s = Statement::make_break_statement(this->break_label(), loc);
6027 then_block->add_statement(s);
6029 oref = Expression::make_temporary_reference(ok_temp, loc);
6030 Expression* cond = Expression::make_unary(OPERATOR_NOT, oref, loc);
6031 s = Statement::make_if_statement(cond, then_block, NULL, loc);
6032 iter_init->add_statement(s);
6034 *piter_init = iter_init;
6037 // Return the break LABEL_EXPR.
6039 Unnamed_label*
6040 For_range_statement::break_label()
6042 if (this->break_label_ == NULL)
6043 this->break_label_ = new Unnamed_label(this->location());
6044 return this->break_label_;
6047 // Return the continue LABEL_EXPR.
6049 Unnamed_label*
6050 For_range_statement::continue_label()
6052 if (this->continue_label_ == NULL)
6053 this->continue_label_ = new Unnamed_label(this->location());
6054 return this->continue_label_;
6057 // Dump the AST representation for a for range statement.
6059 void
6060 For_range_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
6063 ast_dump_context->print_indent();
6064 ast_dump_context->ostream() << "for ";
6065 ast_dump_context->dump_expression(this->index_var_);
6066 if (this->value_var_ != NULL)
6068 ast_dump_context->ostream() << ", ";
6069 ast_dump_context->dump_expression(this->value_var_);
6072 ast_dump_context->ostream() << " = range ";
6073 ast_dump_context->dump_expression(this->range_);
6074 if (ast_dump_context->dump_subblocks())
6076 ast_dump_context->ostream() << " {" << std::endl;
6078 ast_dump_context->indent();
6080 ast_dump_context->dump_block(this->statements_);
6082 ast_dump_context->unindent();
6083 ast_dump_context->print_indent();
6084 ast_dump_context->ostream() << "}";
6086 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
6089 // Make a for statement with a range clause.
6091 For_range_statement*
6092 Statement::make_for_range_statement(Expression* index_var,
6093 Expression* value_var,
6094 Expression* range,
6095 Location location)
6097 return new For_range_statement(index_var, value_var, range, location);