1 // statements.cc -- Go frontend statements.
2
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.
6
7 #include "go-system.h"
8
9 #include "go-c.h"
10 #include "types.h"
11 #include "expressions.h"
12 #include "gogo.h"
13 #include "runtime.h"
14 #include "backend.h"
15 #include "statements.h"
16 #include "ast-dump.h"
17
18 // Class Statement.
19
Statement(Statement_classification classification,Location location)20 Statement::Statement(Statement_classification classification,
21 Location location)
22 : classification_(classification), location_(location)
23 {
24 }
25
~Statement()26 Statement::~Statement()
27 {
28 }
29
30 // Traverse the tree. The work of walking the components is handled
31 // by the subclasses.
32
33 int
traverse(Block * block,size_t * pindex,Traverse * traverse)34 Statement::traverse(Block* block, size_t* pindex, Traverse* traverse)
35 {
36 if (this->classification_ == STATEMENT_ERROR)
37 return TRAVERSE_CONTINUE;
38
39 unsigned int traverse_mask = traverse->traverse_mask();
40
41 if ((traverse_mask & Traverse::traverse_statements) != 0)
42 {
43 int t = traverse->statement(block, pindex, this);
44 if (t == TRAVERSE_EXIT)
45 return TRAVERSE_EXIT;
46 else if (t == TRAVERSE_SKIP_COMPONENTS)
47 return TRAVERSE_CONTINUE;
48 }
49
50 // No point in checking traverse_mask here--a statement may contain
51 // other blocks or statements, and if we got here we always want to
52 // walk them.
53 return this->do_traverse(traverse);
54 }
55
56 // Traverse the contents of a statement.
57
58 int
traverse_contents(Traverse * traverse)59 Statement::traverse_contents(Traverse* traverse)
60 {
61 return this->do_traverse(traverse);
62 }
63
64 // Traverse assignments.
65
66 bool
traverse_assignments(Traverse_assignments * tassign)67 Statement::traverse_assignments(Traverse_assignments* tassign)
68 {
69 if (this->classification_ == STATEMENT_ERROR)
70 return false;
71 return this->do_traverse_assignments(tassign);
72 }
73
74 // Traverse an expression in a statement. This is a helper function
75 // for child classes.
76
77 int
traverse_expression(Traverse * traverse,Expression ** expr)78 Statement::traverse_expression(Traverse* traverse, Expression** expr)
79 {
80 if ((traverse->traverse_mask()
81 & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0)
82 return TRAVERSE_CONTINUE;
83 return Expression::traverse(expr, traverse);
84 }
85
86 // Traverse an expression list in a statement. This is a helper
87 // function for child classes.
88
89 int
traverse_expression_list(Traverse * traverse,Expression_list * expr_list)90 Statement::traverse_expression_list(Traverse* traverse,
91 Expression_list* expr_list)
92 {
93 if (expr_list == NULL)
94 return TRAVERSE_CONTINUE;
95 if ((traverse->traverse_mask()
96 & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0)
97 return TRAVERSE_CONTINUE;
98 return expr_list->traverse(traverse);
99 }
100
101 // Traverse a type in a statement. This is a helper function for
102 // child classes.
103
104 int
traverse_type(Traverse * traverse,Type * type)105 Statement::traverse_type(Traverse* traverse, Type* type)
106 {
107 if ((traverse->traverse_mask()
108 & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0)
109 return TRAVERSE_CONTINUE;
110 return Type::traverse(type, traverse);
111 }
112
113 // Set type information for unnamed constants. This is really done by
114 // the child class.
115
116 void
determine_types()117 Statement::determine_types()
118 {
119 this->do_determine_types();
120 }
121
122 // If this is a thunk statement, return it.
123
124 Thunk_statement*
thunk_statement()125 Statement::thunk_statement()
126 {
127 Thunk_statement* ret = this->convert<Thunk_statement, STATEMENT_GO>();
128 if (ret == NULL)
129 ret = this->convert<Thunk_statement, STATEMENT_DEFER>();
130 return ret;
131 }
132
133 // Convert a Statement to the backend representation. This is really
134 // done by the child class.
135
136 Bstatement*
get_backend(Translate_context * context)137 Statement::get_backend(Translate_context* context)
138 {
139 if (this->classification_ == STATEMENT_ERROR)
140 return context->backend()->error_statement();
141 return this->do_get_backend(context);
142 }
143
144 // Dump AST representation for a statement to a dump context.
145
146 void
dump_statement(Ast_dump_context * ast_dump_context) const147 Statement::dump_statement(Ast_dump_context* ast_dump_context) const
148 {
149 this->do_dump_statement(ast_dump_context);
150 }
151
152 // Note that this statement is erroneous. This is called by children
153 // when they discover an error.
154
155 void
set_is_error()156 Statement::set_is_error()
157 {
158 this->classification_ = STATEMENT_ERROR;
159 }
160
161 // For children to call to report an error conveniently.
162
163 void
report_error(const char * msg)164 Statement::report_error(const char* msg)
165 {
166 error_at(this->location_, "%s", msg);
167 this->set_is_error();
168 }
169
170 // An error statement, used to avoid crashing after we report an
171 // error.
172
173 class Error_statement : public Statement
174 {
175 public:
Error_statement(Location location)176 Error_statement(Location location)
177 : Statement(STATEMENT_ERROR, location)
178 { }
179
180 protected:
181 int
do_traverse(Traverse *)182 do_traverse(Traverse*)
183 { return TRAVERSE_CONTINUE; }
184
185 Bstatement*
do_get_backend(Translate_context *)186 do_get_backend(Translate_context*)
187 { go_unreachable(); }
188
189 void
190 do_dump_statement(Ast_dump_context*) const;
191 };
192
193 // Dump the AST representation for an error statement.
194
195 void
do_dump_statement(Ast_dump_context * ast_dump_context) const196 Error_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
197 {
198 ast_dump_context->print_indent();
199 ast_dump_context->ostream() << "Error statement" << std::endl;
200 }
201
202 // Make an error statement.
203
204 Statement*
make_error_statement(Location location)205 Statement::make_error_statement(Location location)
206 {
207 return new Error_statement(location);
208 }
209
210 // Class Variable_declaration_statement.
211
Variable_declaration_statement(Named_object * var)212 Variable_declaration_statement::Variable_declaration_statement(
213 Named_object* var)
214 : Statement(STATEMENT_VARIABLE_DECLARATION, var->var_value()->location()),
215 var_(var)
216 {
217 }
218
219 // We don't actually traverse the variable here; it was traversed
220 // while traversing the Block.
221
222 int
do_traverse(Traverse *)223 Variable_declaration_statement::do_traverse(Traverse*)
224 {
225 return TRAVERSE_CONTINUE;
226 }
227
228 // Traverse the assignments in a variable declaration. Note that this
229 // traversal is different from the usual traversal.
230
231 bool
do_traverse_assignments(Traverse_assignments * tassign)232 Variable_declaration_statement::do_traverse_assignments(
233 Traverse_assignments* tassign)
234 {
235 tassign->initialize_variable(this->var_);
236 return true;
237 }
238
239 // Lower the variable's initialization expression.
240
241 Statement*
do_lower(Gogo * gogo,Named_object * function,Block *,Statement_inserter * inserter)242 Variable_declaration_statement::do_lower(Gogo* gogo, Named_object* function,
243 Block*, Statement_inserter* inserter)
244 {
245 this->var_->var_value()->lower_init_expression(gogo, function, inserter);
246 return this;
247 }
248
249 // Flatten the variable's initialization expression.
250
251 Statement*
do_flatten(Gogo * gogo,Named_object * function,Block *,Statement_inserter * inserter)252 Variable_declaration_statement::do_flatten(Gogo* gogo, Named_object* function,
253 Block*, Statement_inserter* inserter)
254 {
255 this->var_->var_value()->flatten_init_expression(gogo, function, inserter);
256 return this;
257 }
258
259 // Convert a variable declaration to the backend representation.
260
261 Bstatement*
do_get_backend(Translate_context * context)262 Variable_declaration_statement::do_get_backend(Translate_context* context)
263 {
264 Variable* var = this->var_->var_value();
265 Bvariable* bvar = this->var_->get_backend_variable(context->gogo(),
266 context->function());
267 tree init = var->get_init_tree(context->gogo(), context->function());
268 Bexpression* binit = init == NULL ? NULL : tree_to_expr(init);
269
270 if (!var->is_in_heap())
271 {
272 go_assert(binit != NULL);
273 return context->backend()->init_statement(bvar, binit);
274 }
275
276 // Something takes the address of this variable, so the value is
277 // stored in the heap. Initialize it to newly allocated memory
278 // space, and assign the initial value to the new space.
279 Location loc = this->location();
280 Named_object* newfn = context->gogo()->lookup_global("new");
281 go_assert(newfn != NULL && newfn->is_function_declaration());
282 Expression* func = Expression::make_func_reference(newfn, NULL, loc);
283 Expression_list* params = new Expression_list();
284 params->push_back(Expression::make_type(var->type(), loc));
285 Expression* call = Expression::make_call(func, params, false, loc);
286 context->gogo()->lower_expression(context->function(), NULL, &call);
287 Temporary_statement* temp = Statement::make_temporary(NULL, call, loc);
288 Bstatement* btemp = temp->get_backend(context);
289
290 Bstatement* set = NULL;
291 if (binit != NULL)
292 {
293 Expression* e = Expression::make_temporary_reference(temp, loc);
294 e = Expression::make_unary(OPERATOR_MULT, e, loc);
295 Bexpression* be = tree_to_expr(e->get_tree(context));
296 set = context->backend()->assignment_statement(be, binit, loc);
297 }
298
299 Expression* ref = Expression::make_temporary_reference(temp, loc);
300 Bexpression* bref = tree_to_expr(ref->get_tree(context));
301 Bstatement* sinit = context->backend()->init_statement(bvar, bref);
302
303 std::vector<Bstatement*> stats;
304 stats.reserve(3);
305 stats.push_back(btemp);
306 if (set != NULL)
307 stats.push_back(set);
308 stats.push_back(sinit);
309 return context->backend()->statement_list(stats);
310 }
311
312 // Dump the AST representation for a variable declaration.
313
314 void
do_dump_statement(Ast_dump_context * ast_dump_context) const315 Variable_declaration_statement::do_dump_statement(
316 Ast_dump_context* ast_dump_context) const
317 {
318 ast_dump_context->print_indent();
319
320 go_assert(var_->is_variable());
321 ast_dump_context->ostream() << "var " << this->var_->name() << " ";
322 Variable* var = this->var_->var_value();
323 if (var->has_type())
324 {
325 ast_dump_context->dump_type(var->type());
326 ast_dump_context->ostream() << " ";
327 }
328 if (var->init() != NULL)
329 {
330 ast_dump_context->ostream() << "= ";
331 ast_dump_context->dump_expression(var->init());
332 }
333 ast_dump_context->ostream() << std::endl;
334 }
335
336 // Make a variable declaration.
337
338 Statement*
make_variable_declaration(Named_object * var)339 Statement::make_variable_declaration(Named_object* var)
340 {
341 return new Variable_declaration_statement(var);
342 }
343
344 // Class Temporary_statement.
345
346 // Return the type of the temporary variable.
347
348 Type*
type() const349 Temporary_statement::type() const
350 {
351 return this->type_ != NULL ? this->type_ : this->init_->type();
352 }
353
354 // Traversal.
355
356 int
do_traverse(Traverse * traverse)357 Temporary_statement::do_traverse(Traverse* traverse)
358 {
359 if (this->type_ != NULL
360 && this->traverse_type(traverse, this->type_) == TRAVERSE_EXIT)
361 return TRAVERSE_EXIT;
362 if (this->init_ == NULL)
363 return TRAVERSE_CONTINUE;
364 else
365 return this->traverse_expression(traverse, &this->init_);
366 }
367
368 // Traverse assignments.
369
370 bool
do_traverse_assignments(Traverse_assignments * tassign)371 Temporary_statement::do_traverse_assignments(Traverse_assignments* tassign)
372 {
373 if (this->init_ == NULL)
374 return false;
375 tassign->value(&this->init_, true, true);
376 return true;
377 }
378
379 // Determine types.
380
381 void
do_determine_types()382 Temporary_statement::do_determine_types()
383 {
384 if (this->type_ != NULL && this->type_->is_abstract())
385 this->type_ = this->type_->make_non_abstract_type();
386
387 if (this->init_ != NULL)
388 {
389 if (this->type_ == NULL)
390 this->init_->determine_type_no_context();
391 else
392 {
393 Type_context context(this->type_, false);
394 this->init_->determine_type(&context);
395 }
396 }
397
398 if (this->type_ == NULL)
399 {
400 this->type_ = this->init_->type();
401 go_assert(!this->type_->is_abstract());
402 }
403 }
404
405 // Check types.
406
407 void
do_check_types(Gogo *)408 Temporary_statement::do_check_types(Gogo*)
409 {
410 if (this->type_ != NULL && this->init_ != NULL)
411 {
412 std::string reason;
413 bool ok;
414 if (this->are_hidden_fields_ok_)
415 ok = Type::are_assignable_hidden_ok(this->type_, this->init_->type(),
416 &reason);
417 else
418 ok = Type::are_assignable(this->type_, this->init_->type(), &reason);
419 if (!ok)
420 {
421 if (reason.empty())
422 error_at(this->location(), "incompatible types in assignment");
423 else
424 error_at(this->location(), "incompatible types in assignment (%s)",
425 reason.c_str());
426 this->set_is_error();
427 }
428 }
429 }
430
431 // Convert to backend representation.
432
433 Bstatement*
do_get_backend(Translate_context * context)434 Temporary_statement::do_get_backend(Translate_context* context)
435 {
436 go_assert(this->bvariable_ == NULL);
437
438 // FIXME: Permitting FUNCTION to be NULL here is a temporary measure
439 // until we have a better representation of the init function.
440 Named_object* function = context->function();
441 Bfunction* bfunction;
442 if (function == NULL)
443 bfunction = NULL;
444 else
445 bfunction = tree_to_function(function->func_value()->get_decl());
446
447 Btype* btype = this->type()->get_backend(context->gogo());
448
449 Bexpression* binit;
450 if (this->init_ == NULL)
451 binit = NULL;
452 else if (this->type_ == NULL)
453 binit = tree_to_expr(this->init_->get_tree(context));
454 else
455 {
456 Expression* init = Expression::make_cast(this->type_, this->init_,
457 this->location());
458 context->gogo()->lower_expression(context->function(), NULL, &init);
459 binit = tree_to_expr(init->get_tree(context));
460 }
461
462 Bstatement* statement;
463 this->bvariable_ =
464 context->backend()->temporary_variable(bfunction, context->bblock(),
465 btype, binit,
466 this->is_address_taken_,
467 this->location(), &statement);
468 return statement;
469 }
470
471 // Return the backend variable.
472
473 Bvariable*
get_backend_variable(Translate_context * context) const474 Temporary_statement::get_backend_variable(Translate_context* context) const
475 {
476 if (this->bvariable_ == NULL)
477 {
478 go_assert(saw_errors());
479 return context->backend()->error_variable();
480 }
481 return this->bvariable_;
482 }
483
484 // Dump the AST represemtation for a temporary statement
485
486 void
do_dump_statement(Ast_dump_context * ast_dump_context) const487 Temporary_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
488 {
489 ast_dump_context->print_indent();
490 ast_dump_context->dump_temp_variable_name(this);
491 if (this->type_ != NULL)
492 {
493 ast_dump_context->ostream() << " ";
494 ast_dump_context->dump_type(this->type_);
495 }
496 if (this->init_ != NULL)
497 {
498 ast_dump_context->ostream() << " = ";
499 ast_dump_context->dump_expression(this->init_);
500 }
501 ast_dump_context->ostream() << std::endl;
502 }
503
504 // Make and initialize a temporary variable in BLOCK.
505
506 Temporary_statement*
make_temporary(Type * type,Expression * init,Location location)507 Statement::make_temporary(Type* type, Expression* init,
508 Location location)
509 {
510 return new Temporary_statement(type, init, location);
511 }
512
513 // An assignment statement.
514
515 class Assignment_statement : public Statement
516 {
517 public:
Assignment_statement(Expression * lhs,Expression * rhs,Location location)518 Assignment_statement(Expression* lhs, Expression* rhs,
519 Location location)
520 : Statement(STATEMENT_ASSIGNMENT, location),
521 lhs_(lhs), rhs_(rhs), are_hidden_fields_ok_(false)
522 { }
523
524 // Note that it is OK for this assignment statement to set hidden
525 // fields.
526 void
set_hidden_fields_are_ok()527 set_hidden_fields_are_ok()
528 { this->are_hidden_fields_ok_ = true; }
529
530 protected:
531 int
532 do_traverse(Traverse* traverse);
533
534 bool
535 do_traverse_assignments(Traverse_assignments*);
536
537 void
538 do_determine_types();
539
540 void
541 do_check_types(Gogo*);
542
543 Bstatement*
544 do_get_backend(Translate_context*);
545
546 void
547 do_dump_statement(Ast_dump_context*) const;
548
549 private:
550 // Left hand side--the lvalue.
551 Expression* lhs_;
552 // Right hand side--the rvalue.
553 Expression* rhs_;
554 // True if this statement may set hidden fields in the assignment
555 // statement. This is used for generated method stubs.
556 bool are_hidden_fields_ok_;
557 };
558
559 // Traversal.
560
561 int
do_traverse(Traverse * traverse)562 Assignment_statement::do_traverse(Traverse* traverse)
563 {
564 if (this->traverse_expression(traverse, &this->lhs_) == TRAVERSE_EXIT)
565 return TRAVERSE_EXIT;
566 return this->traverse_expression(traverse, &this->rhs_);
567 }
568
569 bool
do_traverse_assignments(Traverse_assignments * tassign)570 Assignment_statement::do_traverse_assignments(Traverse_assignments* tassign)
571 {
572 tassign->assignment(&this->lhs_, &this->rhs_);
573 return true;
574 }
575
576 // Set types for the assignment.
577
578 void
do_determine_types()579 Assignment_statement::do_determine_types()
580 {
581 this->lhs_->determine_type_no_context();
582 Type* rhs_context_type = this->lhs_->type();
583 if (rhs_context_type->is_sink_type())
584 rhs_context_type = NULL;
585 Type_context context(rhs_context_type, false);
586 this->rhs_->determine_type(&context);
587 }
588
589 // Check types for an assignment.
590
591 void
do_check_types(Gogo *)592 Assignment_statement::do_check_types(Gogo*)
593 {
594 // The left hand side must be either addressable, a map index
595 // expression, or the blank identifier.
596 if (!this->lhs_->is_addressable()
597 && this->lhs_->map_index_expression() == NULL
598 && !this->lhs_->is_sink_expression())
599 {
600 if (!this->lhs_->type()->is_error())
601 this->report_error(_("invalid left hand side of assignment"));
602 return;
603 }
604
605 Type* lhs_type = this->lhs_->type();
606 Type* rhs_type = this->rhs_->type();
607
608 // Invalid assignment of nil to the blank identifier.
609 if (lhs_type->is_sink_type()
610 && rhs_type->is_nil_type())
611 {
612 this->report_error(_("use of untyped nil"));
613 return;
614 }
615
616 std::string reason;
617 bool ok;
618 if (this->are_hidden_fields_ok_)
619 ok = Type::are_assignable_hidden_ok(lhs_type, rhs_type, &reason);
620 else
621 ok = Type::are_assignable(lhs_type, rhs_type, &reason);
622 if (!ok)
623 {
624 if (reason.empty())
625 error_at(this->location(), "incompatible types in assignment");
626 else
627 error_at(this->location(), "incompatible types in assignment (%s)",
628 reason.c_str());
629 this->set_is_error();
630 }
631
632 if (lhs_type->is_error() || rhs_type->is_error())
633 this->set_is_error();
634 }
635
636 // Convert an assignment statement to the backend representation.
637
638 Bstatement*
do_get_backend(Translate_context * context)639 Assignment_statement::do_get_backend(Translate_context* context)
640 {
641 tree rhs_tree = this->rhs_->get_tree(context);
642 if (this->lhs_->is_sink_expression())
643 return context->backend()->expression_statement(tree_to_expr(rhs_tree));
644 tree lhs_tree = this->lhs_->get_tree(context);
645 rhs_tree = Expression::convert_for_assignment(context, this->lhs_->type(),
646 this->rhs_->type(), rhs_tree,
647 this->location());
648 return context->backend()->assignment_statement(tree_to_expr(lhs_tree),
649 tree_to_expr(rhs_tree),
650 this->location());
651 }
652
653 // Dump the AST representation for an assignment statement.
654
655 void
do_dump_statement(Ast_dump_context * ast_dump_context) const656 Assignment_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
657 const
658 {
659 ast_dump_context->print_indent();
660 ast_dump_context->dump_expression(this->lhs_);
661 ast_dump_context->ostream() << " = " ;
662 ast_dump_context->dump_expression(this->rhs_);
663 ast_dump_context->ostream() << std::endl;
664 }
665
666 // Make an assignment statement.
667
668 Statement*
make_assignment(Expression * lhs,Expression * rhs,Location location)669 Statement::make_assignment(Expression* lhs, Expression* rhs,
670 Location location)
671 {
672 return new Assignment_statement(lhs, rhs, location);
673 }
674
675 // The Move_subexpressions class is used to move all top-level
676 // subexpressions of an expression. This is used for things like
677 // index expressions in which we must evaluate the index value before
678 // it can be changed by a multiple assignment.
679
680 class Move_subexpressions : public Traverse
681 {
682 public:
Move_subexpressions(int skip,Block * block)683 Move_subexpressions(int skip, Block* block)
684 : Traverse(traverse_expressions),
685 skip_(skip), block_(block)
686 { }
687
688 protected:
689 int
690 expression(Expression**);
691
692 private:
693 // The number of subexpressions to skip moving. This is used to
694 // avoid moving the array itself, as we only need to move the index.
695 int skip_;
696 // The block where new temporary variables should be added.
697 Block* block_;
698 };
699
700 int
expression(Expression ** pexpr)701 Move_subexpressions::expression(Expression** pexpr)
702 {
703 if (this->skip_ > 0)
704 --this->skip_;
705 else if ((*pexpr)->temporary_reference_expression() == NULL)
706 {
707 Location loc = (*pexpr)->location();
708 Temporary_statement* temp = Statement::make_temporary(NULL, *pexpr, loc);
709 this->block_->add_statement(temp);
710 *pexpr = Expression::make_temporary_reference(temp, loc);
711 }
712 // We only need to move top-level subexpressions.
713 return TRAVERSE_SKIP_COMPONENTS;
714 }
715
716 // The Move_ordered_evals class is used to find any subexpressions of
717 // an expression that have an evaluation order dependency. It creates
718 // temporary variables to hold them.
719
720 class Move_ordered_evals : public Traverse
721 {
722 public:
Move_ordered_evals(Block * block)723 Move_ordered_evals(Block* block)
724 : Traverse(traverse_expressions),
725 block_(block)
726 { }
727
728 protected:
729 int
730 expression(Expression**);
731
732 private:
733 // The block where new temporary variables should be added.
734 Block* block_;
735 };
736
737 int
expression(Expression ** pexpr)738 Move_ordered_evals::expression(Expression** pexpr)
739 {
740 // We have to look at subexpressions first.
741 if ((*pexpr)->traverse_subexpressions(this) == TRAVERSE_EXIT)
742 return TRAVERSE_EXIT;
743
744 int i;
745 if ((*pexpr)->must_eval_subexpressions_in_order(&i))
746 {
747 Move_subexpressions ms(i, this->block_);
748 if ((*pexpr)->traverse_subexpressions(&ms) == TRAVERSE_EXIT)
749 return TRAVERSE_EXIT;
750 }
751
752 if ((*pexpr)->must_eval_in_order())
753 {
754 Location loc = (*pexpr)->location();
755 Temporary_statement* temp = Statement::make_temporary(NULL, *pexpr, loc);
756 this->block_->add_statement(temp);
757 *pexpr = Expression::make_temporary_reference(temp, loc);
758 }
759 return TRAVERSE_SKIP_COMPONENTS;
760 }
761
762 // An assignment operation statement.
763
764 class Assignment_operation_statement : public Statement
765 {
766 public:
Assignment_operation_statement(Operator op,Expression * lhs,Expression * rhs,Location location)767 Assignment_operation_statement(Operator op, Expression* lhs, Expression* rhs,
768 Location location)
769 : Statement(STATEMENT_ASSIGNMENT_OPERATION, location),
770 op_(op), lhs_(lhs), rhs_(rhs)
771 { }
772
773 protected:
774 int
775 do_traverse(Traverse*);
776
777 bool
do_traverse_assignments(Traverse_assignments *)778 do_traverse_assignments(Traverse_assignments*)
779 { go_unreachable(); }
780
781 Statement*
782 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
783
784 Bstatement*
do_get_backend(Translate_context *)785 do_get_backend(Translate_context*)
786 { go_unreachable(); }
787
788 void
789 do_dump_statement(Ast_dump_context*) const;
790
791 private:
792 // The operator (OPERATOR_PLUSEQ, etc.).
793 Operator op_;
794 // Left hand side.
795 Expression* lhs_;
796 // Right hand side.
797 Expression* rhs_;
798 };
799
800 // Traversal.
801
802 int
do_traverse(Traverse * traverse)803 Assignment_operation_statement::do_traverse(Traverse* traverse)
804 {
805 if (this->traverse_expression(traverse, &this->lhs_) == TRAVERSE_EXIT)
806 return TRAVERSE_EXIT;
807 return this->traverse_expression(traverse, &this->rhs_);
808 }
809
810 // Lower an assignment operation statement to a regular assignment
811 // statement.
812
813 Statement*
do_lower(Gogo *,Named_object *,Block * enclosing,Statement_inserter *)814 Assignment_operation_statement::do_lower(Gogo*, Named_object*,
815 Block* enclosing, Statement_inserter*)
816 {
817 Location loc = this->location();
818
819 // We have to evaluate the left hand side expression only once. We
820 // do this by moving out any expression with side effects.
821 Block* b = new Block(enclosing, loc);
822 Move_ordered_evals moe(b);
823 this->lhs_->traverse_subexpressions(&moe);
824
825 Expression* lval = this->lhs_->copy();
826
827 Operator op;
828 switch (this->op_)
829 {
830 case OPERATOR_PLUSEQ:
831 op = OPERATOR_PLUS;
832 break;
833 case OPERATOR_MINUSEQ:
834 op = OPERATOR_MINUS;
835 break;
836 case OPERATOR_OREQ:
837 op = OPERATOR_OR;
838 break;
839 case OPERATOR_XOREQ:
840 op = OPERATOR_XOR;
841 break;
842 case OPERATOR_MULTEQ:
843 op = OPERATOR_MULT;
844 break;
845 case OPERATOR_DIVEQ:
846 op = OPERATOR_DIV;
847 break;
848 case OPERATOR_MODEQ:
849 op = OPERATOR_MOD;
850 break;
851 case OPERATOR_LSHIFTEQ:
852 op = OPERATOR_LSHIFT;
853 break;
854 case OPERATOR_RSHIFTEQ:
855 op = OPERATOR_RSHIFT;
856 break;
857 case OPERATOR_ANDEQ:
858 op = OPERATOR_AND;
859 break;
860 case OPERATOR_BITCLEAREQ:
861 op = OPERATOR_BITCLEAR;
862 break;
863 default:
864 go_unreachable();
865 }
866
867 Expression* binop = Expression::make_binary(op, lval, this->rhs_, loc);
868 Statement* s = Statement::make_assignment(this->lhs_, binop, loc);
869 if (b->statements()->empty())
870 {
871 delete b;
872 return s;
873 }
874 else
875 {
876 b->add_statement(s);
877 return Statement::make_block_statement(b, loc);
878 }
879 }
880
881 // Dump the AST representation for an assignment operation statement
882
883 void
do_dump_statement(Ast_dump_context * ast_dump_context) const884 Assignment_operation_statement::do_dump_statement(
885 Ast_dump_context* ast_dump_context) const
886 {
887 ast_dump_context->print_indent();
888 ast_dump_context->dump_expression(this->lhs_);
889 ast_dump_context->dump_operator(this->op_);
890 ast_dump_context->dump_expression(this->rhs_);
891 ast_dump_context->ostream() << std::endl;
892 }
893
894 // Make an assignment operation statement.
895
896 Statement*
make_assignment_operation(Operator op,Expression * lhs,Expression * rhs,Location location)897 Statement::make_assignment_operation(Operator op, Expression* lhs,
898 Expression* rhs, Location location)
899 {
900 return new Assignment_operation_statement(op, lhs, rhs, location);
901 }
902
903 // A tuple assignment statement. This differs from an assignment
904 // statement in that the right-hand-side expressions are evaluated in
905 // parallel.
906
907 class Tuple_assignment_statement : public Statement
908 {
909 public:
Tuple_assignment_statement(Expression_list * lhs,Expression_list * rhs,Location location)910 Tuple_assignment_statement(Expression_list* lhs, Expression_list* rhs,
911 Location location)
912 : Statement(STATEMENT_TUPLE_ASSIGNMENT, location),
913 lhs_(lhs), rhs_(rhs), are_hidden_fields_ok_(false)
914 { }
915
916 // Note that it is OK for this assignment statement to set hidden
917 // fields.
918 void
set_hidden_fields_are_ok()919 set_hidden_fields_are_ok()
920 { this->are_hidden_fields_ok_ = true; }
921
922 protected:
923 int
924 do_traverse(Traverse* traverse);
925
926 bool
do_traverse_assignments(Traverse_assignments *)927 do_traverse_assignments(Traverse_assignments*)
928 { go_unreachable(); }
929
930 Statement*
931 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
932
933 Bstatement*
do_get_backend(Translate_context *)934 do_get_backend(Translate_context*)
935 { go_unreachable(); }
936
937 void
938 do_dump_statement(Ast_dump_context*) const;
939
940 private:
941 // Left hand side--a list of lvalues.
942 Expression_list* lhs_;
943 // Right hand side--a list of rvalues.
944 Expression_list* rhs_;
945 // True if this statement may set hidden fields in the assignment
946 // statement. This is used for generated method stubs.
947 bool are_hidden_fields_ok_;
948 };
949
950 // Traversal.
951
952 int
do_traverse(Traverse * traverse)953 Tuple_assignment_statement::do_traverse(Traverse* traverse)
954 {
955 if (this->traverse_expression_list(traverse, this->lhs_) == TRAVERSE_EXIT)
956 return TRAVERSE_EXIT;
957 return this->traverse_expression_list(traverse, this->rhs_);
958 }
959
960 // Lower a tuple assignment. We use temporary variables to split it
961 // up into a set of single assignments.
962
963 Statement*
do_lower(Gogo *,Named_object *,Block * enclosing,Statement_inserter *)964 Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
965 Statement_inserter*)
966 {
967 Location loc = this->location();
968
969 Block* b = new Block(enclosing, loc);
970
971 // First move out any subexpressions on the left hand side. The
972 // right hand side will be evaluated in the required order anyhow.
973 Move_ordered_evals moe(b);
974 for (Expression_list::iterator plhs = this->lhs_->begin();
975 plhs != this->lhs_->end();
976 ++plhs)
977 Expression::traverse(&*plhs, &moe);
978
979 std::vector<Temporary_statement*> temps;
980 temps.reserve(this->lhs_->size());
981
982 Expression_list::const_iterator prhs = this->rhs_->begin();
983 for (Expression_list::const_iterator plhs = this->lhs_->begin();
984 plhs != this->lhs_->end();
985 ++plhs, ++prhs)
986 {
987 go_assert(prhs != this->rhs_->end());
988
989 if ((*plhs)->is_error_expression()
990 || (*plhs)->type()->is_error()
991 || (*prhs)->is_error_expression()
992 || (*prhs)->type()->is_error())
993 continue;
994
995 if ((*plhs)->is_sink_expression())
996 {
997 if ((*prhs)->type()->is_nil_type())
998 this->report_error(_("use of untyped nil"));
999 else
1000 b->add_statement(Statement::make_statement(*prhs, true));
1001 continue;
1002 }
1003
1004 Temporary_statement* temp = Statement::make_temporary((*plhs)->type(),
1005 *prhs, loc);
1006 if (this->are_hidden_fields_ok_)
1007 temp->set_hidden_fields_are_ok();
1008 b->add_statement(temp);
1009 temps.push_back(temp);
1010
1011 }
1012 go_assert(prhs == this->rhs_->end());
1013
1014 prhs = this->rhs_->begin();
1015 std::vector<Temporary_statement*>::const_iterator ptemp = temps.begin();
1016 for (Expression_list::const_iterator plhs = this->lhs_->begin();
1017 plhs != this->lhs_->end();
1018 ++plhs, ++prhs)
1019 {
1020 if ((*plhs)->is_error_expression()
1021 || (*plhs)->type()->is_error()
1022 || (*prhs)->is_error_expression()
1023 || (*prhs)->type()->is_error())
1024 continue;
1025
1026 if ((*plhs)->is_sink_expression())
1027 continue;
1028
1029 Expression* ref = Expression::make_temporary_reference(*ptemp, loc);
1030 Statement* s = Statement::make_assignment(*plhs, ref, loc);
1031 if (this->are_hidden_fields_ok_)
1032 {
1033 Assignment_statement* as = static_cast<Assignment_statement*>(s);
1034 as->set_hidden_fields_are_ok();
1035 }
1036 b->add_statement(s);
1037 ++ptemp;
1038 }
1039 go_assert(ptemp == temps.end() || saw_errors());
1040
1041 return Statement::make_block_statement(b, loc);
1042 }
1043
1044 // Dump the AST representation for a tuple assignment statement.
1045
1046 void
do_dump_statement(Ast_dump_context * ast_dump_context) const1047 Tuple_assignment_statement::do_dump_statement(
1048 Ast_dump_context* ast_dump_context) const
1049 {
1050 ast_dump_context->print_indent();
1051 ast_dump_context->dump_expression_list(this->lhs_);
1052 ast_dump_context->ostream() << " = ";
1053 ast_dump_context->dump_expression_list(this->rhs_);
1054 ast_dump_context->ostream() << std::endl;
1055 }
1056
1057 // Make a tuple assignment statement.
1058
1059 Statement*
make_tuple_assignment(Expression_list * lhs,Expression_list * rhs,Location location)1060 Statement::make_tuple_assignment(Expression_list* lhs, Expression_list* rhs,
1061 Location location)
1062 {
1063 return new Tuple_assignment_statement(lhs, rhs, location);
1064 }
1065
1066 // A tuple assignment from a map index expression.
1067 // v, ok = m[k]
1068
1069 class Tuple_map_assignment_statement : public Statement
1070 {
1071 public:
Tuple_map_assignment_statement(Expression * val,Expression * present,Expression * map_index,Location location)1072 Tuple_map_assignment_statement(Expression* val, Expression* present,
1073 Expression* map_index,
1074 Location location)
1075 : Statement(STATEMENT_TUPLE_MAP_ASSIGNMENT, location),
1076 val_(val), present_(present), map_index_(map_index)
1077 { }
1078
1079 protected:
1080 int
1081 do_traverse(Traverse* traverse);
1082
1083 bool
do_traverse_assignments(Traverse_assignments *)1084 do_traverse_assignments(Traverse_assignments*)
1085 { go_unreachable(); }
1086
1087 Statement*
1088 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1089
1090 Bstatement*
do_get_backend(Translate_context *)1091 do_get_backend(Translate_context*)
1092 { go_unreachable(); }
1093
1094 void
1095 do_dump_statement(Ast_dump_context*) const;
1096
1097 private:
1098 // Lvalue which receives the value from the map.
1099 Expression* val_;
1100 // Lvalue which receives whether the key value was present.
1101 Expression* present_;
1102 // The map index expression.
1103 Expression* map_index_;
1104 };
1105
1106 // Traversal.
1107
1108 int
do_traverse(Traverse * traverse)1109 Tuple_map_assignment_statement::do_traverse(Traverse* traverse)
1110 {
1111 if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
1112 || this->traverse_expression(traverse, &this->present_) == TRAVERSE_EXIT)
1113 return TRAVERSE_EXIT;
1114 return this->traverse_expression(traverse, &this->map_index_);
1115 }
1116
1117 // Lower a tuple map assignment.
1118
1119 Statement*
do_lower(Gogo *,Named_object *,Block * enclosing,Statement_inserter *)1120 Tuple_map_assignment_statement::do_lower(Gogo*, Named_object*,
1121 Block* enclosing, Statement_inserter*)
1122 {
1123 Location loc = this->location();
1124
1125 Map_index_expression* map_index = this->map_index_->map_index_expression();
1126 if (map_index == NULL)
1127 {
1128 this->report_error(_("expected map index on right hand side"));
1129 return Statement::make_error_statement(loc);
1130 }
1131 Map_type* map_type = map_index->get_map_type();
1132 if (map_type == NULL)
1133 return Statement::make_error_statement(loc);
1134
1135 Block* b = new Block(enclosing, loc);
1136
1137 // Move out any subexpressions to make sure that functions are
1138 // called in the required order.
1139 Move_ordered_evals moe(b);
1140 this->val_->traverse_subexpressions(&moe);
1141 this->present_->traverse_subexpressions(&moe);
1142
1143 // Copy the key value into a temporary so that we can take its
1144 // address without pushing the value onto the heap.
1145
1146 // var key_temp KEY_TYPE = MAP_INDEX
1147 Temporary_statement* key_temp =
1148 Statement::make_temporary(map_type->key_type(), map_index->index(), loc);
1149 b->add_statement(key_temp);
1150
1151 // var val_temp VAL_TYPE
1152 Temporary_statement* val_temp =
1153 Statement::make_temporary(map_type->val_type(), NULL, loc);
1154 b->add_statement(val_temp);
1155
1156 // var present_temp bool
1157 Temporary_statement* present_temp =
1158 Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
1159 b->add_statement(present_temp);
1160
1161 // present_temp = mapaccess2(DESCRIPTOR, MAP, &key_temp, &val_temp)
1162 Expression* a1 = Expression::make_type_descriptor(map_type, loc);
1163 Expression* a2 = map_index->map();
1164 Temporary_reference_expression* ref =
1165 Expression::make_temporary_reference(key_temp, loc);
1166 Expression* a3 = Expression::make_unary(OPERATOR_AND, ref, loc);
1167 ref = Expression::make_temporary_reference(val_temp, loc);
1168 Expression* a4 = Expression::make_unary(OPERATOR_AND, ref, loc);
1169 Expression* call = Runtime::make_call(Runtime::MAPACCESS2, loc, 4,
1170 a1, a2, a3, a4);
1171
1172 ref = Expression::make_temporary_reference(present_temp, loc);
1173 ref->set_is_lvalue();
1174 Statement* s = Statement::make_assignment(ref, call, loc);
1175 b->add_statement(s);
1176
1177 // val = val_temp
1178 ref = Expression::make_temporary_reference(val_temp, loc);
1179 s = Statement::make_assignment(this->val_, ref, loc);
1180 b->add_statement(s);
1181
1182 // present = present_temp
1183 ref = Expression::make_temporary_reference(present_temp, loc);
1184 s = Statement::make_assignment(this->present_, ref, loc);
1185 b->add_statement(s);
1186
1187 return Statement::make_block_statement(b, loc);
1188 }
1189
1190 // Dump the AST representation for a tuple map assignment statement.
1191
1192 void
do_dump_statement(Ast_dump_context * ast_dump_context) const1193 Tuple_map_assignment_statement::do_dump_statement(
1194 Ast_dump_context* ast_dump_context) const
1195 {
1196 ast_dump_context->print_indent();
1197 ast_dump_context->dump_expression(this->val_);
1198 ast_dump_context->ostream() << ", ";
1199 ast_dump_context->dump_expression(this->present_);
1200 ast_dump_context->ostream() << " = ";
1201 ast_dump_context->dump_expression(this->map_index_);
1202 ast_dump_context->ostream() << std::endl;
1203 }
1204
1205 // Make a map assignment statement which returns a pair of values.
1206
1207 Statement*
make_tuple_map_assignment(Expression * val,Expression * present,Expression * map_index,Location location)1208 Statement::make_tuple_map_assignment(Expression* val, Expression* present,
1209 Expression* map_index,
1210 Location location)
1211 {
1212 return new Tuple_map_assignment_statement(val, present, map_index, location);
1213 }
1214
1215 // Assign a pair of entries to a map.
1216 // m[k] = v, p
1217
1218 class Map_assignment_statement : public Statement
1219 {
1220 public:
Map_assignment_statement(Expression * map_index,Expression * val,Expression * should_set,Location location)1221 Map_assignment_statement(Expression* map_index,
1222 Expression* val, Expression* should_set,
1223 Location location)
1224 : Statement(STATEMENT_MAP_ASSIGNMENT, location),
1225 map_index_(map_index), val_(val), should_set_(should_set)
1226 { }
1227
1228 protected:
1229 int
1230 do_traverse(Traverse* traverse);
1231
1232 bool
do_traverse_assignments(Traverse_assignments *)1233 do_traverse_assignments(Traverse_assignments*)
1234 { go_unreachable(); }
1235
1236 Statement*
1237 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1238
1239 Bstatement*
do_get_backend(Translate_context *)1240 do_get_backend(Translate_context*)
1241 { go_unreachable(); }
1242
1243 void
1244 do_dump_statement(Ast_dump_context*) const;
1245
1246 private:
1247 // A reference to the map index which should be set or deleted.
1248 Expression* map_index_;
1249 // The value to add to the map.
1250 Expression* val_;
1251 // Whether or not to add the value.
1252 Expression* should_set_;
1253 };
1254
1255 // Traverse a map assignment.
1256
1257 int
do_traverse(Traverse * traverse)1258 Map_assignment_statement::do_traverse(Traverse* traverse)
1259 {
1260 if (this->traverse_expression(traverse, &this->map_index_) == TRAVERSE_EXIT
1261 || this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT)
1262 return TRAVERSE_EXIT;
1263 return this->traverse_expression(traverse, &this->should_set_);
1264 }
1265
1266 // Lower a map assignment to a function call.
1267
1268 Statement*
do_lower(Gogo *,Named_object *,Block * enclosing,Statement_inserter *)1269 Map_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
1270 Statement_inserter*)
1271 {
1272 Location loc = this->location();
1273
1274 Map_index_expression* map_index = this->map_index_->map_index_expression();
1275 if (map_index == NULL)
1276 {
1277 this->report_error(_("expected map index on left hand side"));
1278 return Statement::make_error_statement(loc);
1279 }
1280 Map_type* map_type = map_index->get_map_type();
1281 if (map_type == NULL)
1282 return Statement::make_error_statement(loc);
1283
1284 Block* b = new Block(enclosing, loc);
1285
1286 // Evaluate the map first to get order of evaluation right.
1287 // map_temp := m // we are evaluating m[k] = v, p
1288 Temporary_statement* map_temp = Statement::make_temporary(map_type,
1289 map_index->map(),
1290 loc);
1291 b->add_statement(map_temp);
1292
1293 // var key_temp MAP_KEY_TYPE = k
1294 Temporary_statement* key_temp =
1295 Statement::make_temporary(map_type->key_type(), map_index->index(), loc);
1296 b->add_statement(key_temp);
1297
1298 // var val_temp MAP_VAL_TYPE = v
1299 Temporary_statement* val_temp =
1300 Statement::make_temporary(map_type->val_type(), this->val_, loc);
1301 b->add_statement(val_temp);
1302
1303 // var insert_temp bool = p
1304 Temporary_statement* insert_temp =
1305 Statement::make_temporary(Type::lookup_bool_type(), this->should_set_,
1306 loc);
1307 b->add_statement(insert_temp);
1308
1309 // mapassign2(map_temp, &key_temp, &val_temp, p)
1310 Expression* p1 = Expression::make_temporary_reference(map_temp, loc);
1311 Expression* ref = Expression::make_temporary_reference(key_temp, loc);
1312 Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
1313 ref = Expression::make_temporary_reference(val_temp, loc);
1314 Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
1315 Expression* p4 = Expression::make_temporary_reference(insert_temp, loc);
1316 Expression* call = Runtime::make_call(Runtime::MAPASSIGN2, loc, 4,
1317 p1, p2, p3, p4);
1318 Statement* s = Statement::make_statement(call, true);
1319 b->add_statement(s);
1320
1321 return Statement::make_block_statement(b, loc);
1322 }
1323
1324 // Dump the AST representation for a map assignment statement.
1325
1326 void
do_dump_statement(Ast_dump_context * ast_dump_context) const1327 Map_assignment_statement::do_dump_statement(
1328 Ast_dump_context* ast_dump_context) const
1329 {
1330 ast_dump_context->print_indent();
1331 ast_dump_context->dump_expression(this->map_index_);
1332 ast_dump_context->ostream() << " = ";
1333 ast_dump_context->dump_expression(this->val_);
1334 ast_dump_context->ostream() << ", ";
1335 ast_dump_context->dump_expression(this->should_set_);
1336 ast_dump_context->ostream() << std::endl;
1337 }
1338
1339 // Make a statement which assigns a pair of entries to a map.
1340
1341 Statement*
make_map_assignment(Expression * map_index,Expression * val,Expression * should_set,Location location)1342 Statement::make_map_assignment(Expression* map_index,
1343 Expression* val, Expression* should_set,
1344 Location location)
1345 {
1346 return new Map_assignment_statement(map_index, val, should_set, location);
1347 }
1348
1349 // A tuple assignment from a receive statement.
1350
1351 class Tuple_receive_assignment_statement : public Statement
1352 {
1353 public:
Tuple_receive_assignment_statement(Expression * val,Expression * closed,Expression * channel,Location location)1354 Tuple_receive_assignment_statement(Expression* val, Expression* closed,
1355 Expression* channel, Location location)
1356 : Statement(STATEMENT_TUPLE_RECEIVE_ASSIGNMENT, location),
1357 val_(val), closed_(closed), channel_(channel)
1358 { }
1359
1360 protected:
1361 int
1362 do_traverse(Traverse* traverse);
1363
1364 bool
do_traverse_assignments(Traverse_assignments *)1365 do_traverse_assignments(Traverse_assignments*)
1366 { go_unreachable(); }
1367
1368 Statement*
1369 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1370
1371 Bstatement*
do_get_backend(Translate_context *)1372 do_get_backend(Translate_context*)
1373 { go_unreachable(); }
1374
1375 void
1376 do_dump_statement(Ast_dump_context*) const;
1377
1378 private:
1379 // Lvalue which receives the value from the channel.
1380 Expression* val_;
1381 // Lvalue which receives whether the channel is closed.
1382 Expression* closed_;
1383 // The channel on which we receive the value.
1384 Expression* channel_;
1385 };
1386
1387 // Traversal.
1388
1389 int
do_traverse(Traverse * traverse)1390 Tuple_receive_assignment_statement::do_traverse(Traverse* traverse)
1391 {
1392 if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
1393 || this->traverse_expression(traverse, &this->closed_) == TRAVERSE_EXIT)
1394 return TRAVERSE_EXIT;
1395 return this->traverse_expression(traverse, &this->channel_);
1396 }
1397
1398 // Lower to a function call.
1399
1400 Statement*
do_lower(Gogo *,Named_object *,Block * enclosing,Statement_inserter *)1401 Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
1402 Block* enclosing,
1403 Statement_inserter*)
1404 {
1405 Location loc = this->location();
1406
1407 Channel_type* channel_type = this->channel_->type()->channel_type();
1408 if (channel_type == NULL)
1409 {
1410 this->report_error(_("expected channel"));
1411 return Statement::make_error_statement(loc);
1412 }
1413 if (!channel_type->may_receive())
1414 {
1415 this->report_error(_("invalid receive on send-only channel"));
1416 return Statement::make_error_statement(loc);
1417 }
1418
1419 Block* b = new Block(enclosing, loc);
1420
1421 // Make sure that any subexpressions on the left hand side are
1422 // evaluated in the right order.
1423 Move_ordered_evals moe(b);
1424 this->val_->traverse_subexpressions(&moe);
1425 this->closed_->traverse_subexpressions(&moe);
1426
1427 // var val_temp ELEMENT_TYPE
1428 Temporary_statement* val_temp =
1429 Statement::make_temporary(channel_type->element_type(), NULL, loc);
1430 b->add_statement(val_temp);
1431
1432 // var closed_temp bool
1433 Temporary_statement* closed_temp =
1434 Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
1435 b->add_statement(closed_temp);
1436
1437 // closed_temp = chanrecv2(type, channel, &val_temp)
1438 Expression* td = Expression::make_type_descriptor(this->channel_->type(),
1439 loc);
1440 Temporary_reference_expression* ref =
1441 Expression::make_temporary_reference(val_temp, loc);
1442 Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
1443 Expression* call = Runtime::make_call(Runtime::CHANRECV2,
1444 loc, 3, td, this->channel_, p2);
1445 ref = Expression::make_temporary_reference(closed_temp, loc);
1446 ref->set_is_lvalue();
1447 Statement* s = Statement::make_assignment(ref, call, loc);
1448 b->add_statement(s);
1449
1450 // val = val_temp
1451 ref = Expression::make_temporary_reference(val_temp, loc);
1452 s = Statement::make_assignment(this->val_, ref, loc);
1453 b->add_statement(s);
1454
1455 // closed = closed_temp
1456 ref = Expression::make_temporary_reference(closed_temp, loc);
1457 s = Statement::make_assignment(this->closed_, ref, loc);
1458 b->add_statement(s);
1459
1460 return Statement::make_block_statement(b, loc);
1461 }
1462
1463 // Dump the AST representation for a tuple receive statement.
1464
1465 void
do_dump_statement(Ast_dump_context * ast_dump_context) const1466 Tuple_receive_assignment_statement::do_dump_statement(
1467 Ast_dump_context* ast_dump_context) const
1468 {
1469 ast_dump_context->print_indent();
1470 ast_dump_context->dump_expression(this->val_);
1471 ast_dump_context->ostream() << ", ";
1472 ast_dump_context->dump_expression(this->closed_);
1473 ast_dump_context->ostream() << " <- ";
1474 ast_dump_context->dump_expression(this->channel_);
1475 ast_dump_context->ostream() << std::endl;
1476 }
1477
1478 // Make a nonblocking receive statement.
1479
1480 Statement*
make_tuple_receive_assignment(Expression * val,Expression * closed,Expression * channel,Location location)1481 Statement::make_tuple_receive_assignment(Expression* val, Expression* closed,
1482 Expression* channel,
1483 Location location)
1484 {
1485 return new Tuple_receive_assignment_statement(val, closed, channel,
1486 location);
1487 }
1488
1489 // An assignment to a pair of values from a type guard. This is a
1490 // conditional type guard. v, ok = i.(type).
1491
1492 class Tuple_type_guard_assignment_statement : public Statement
1493 {
1494 public:
Tuple_type_guard_assignment_statement(Expression * val,Expression * ok,Expression * expr,Type * type,Location location)1495 Tuple_type_guard_assignment_statement(Expression* val, Expression* ok,
1496 Expression* expr, Type* type,
1497 Location location)
1498 : Statement(STATEMENT_TUPLE_TYPE_GUARD_ASSIGNMENT, location),
1499 val_(val), ok_(ok), expr_(expr), type_(type)
1500 { }
1501
1502 protected:
1503 int
1504 do_traverse(Traverse*);
1505
1506 bool
do_traverse_assignments(Traverse_assignments *)1507 do_traverse_assignments(Traverse_assignments*)
1508 { go_unreachable(); }
1509
1510 Statement*
1511 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1512
1513 Bstatement*
do_get_backend(Translate_context *)1514 do_get_backend(Translate_context*)
1515 { go_unreachable(); }
1516
1517 void
1518 do_dump_statement(Ast_dump_context*) const;
1519
1520 private:
1521 Call_expression*
1522 lower_to_type(Runtime::Function);
1523
1524 void
1525 lower_to_object_type(Block*, Runtime::Function);
1526
1527 // The variable which recieves the converted value.
1528 Expression* val_;
1529 // The variable which receives the indication of success.
1530 Expression* ok_;
1531 // The expression being converted.
1532 Expression* expr_;
1533 // The type to which the expression is being converted.
1534 Type* type_;
1535 };
1536
1537 // Traverse a type guard tuple assignment.
1538
1539 int
do_traverse(Traverse * traverse)1540 Tuple_type_guard_assignment_statement::do_traverse(Traverse* traverse)
1541 {
1542 if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
1543 || this->traverse_expression(traverse, &this->ok_) == TRAVERSE_EXIT
1544 || this->traverse_type(traverse, this->type_) == TRAVERSE_EXIT)
1545 return TRAVERSE_EXIT;
1546 return this->traverse_expression(traverse, &this->expr_);
1547 }
1548
1549 // Lower to a function call.
1550
1551 Statement*
do_lower(Gogo *,Named_object *,Block * enclosing,Statement_inserter *)1552 Tuple_type_guard_assignment_statement::do_lower(Gogo*, Named_object*,
1553 Block* enclosing,
1554 Statement_inserter*)
1555 {
1556 Location loc = this->location();
1557
1558 Type* expr_type = this->expr_->type();
1559 if (expr_type->interface_type() == NULL)
1560 {
1561 if (!expr_type->is_error() && !this->type_->is_error())
1562 this->report_error(_("type assertion only valid for interface types"));
1563 return Statement::make_error_statement(loc);
1564 }
1565
1566 Block* b = new Block(enclosing, loc);
1567
1568 // Make sure that any subexpressions on the left hand side are
1569 // evaluated in the right order.
1570 Move_ordered_evals moe(b);
1571 this->val_->traverse_subexpressions(&moe);
1572 this->ok_->traverse_subexpressions(&moe);
1573
1574 bool expr_is_empty = expr_type->interface_type()->is_empty();
1575 Call_expression* call;
1576 if (this->type_->interface_type() != NULL)
1577 {
1578 if (this->type_->interface_type()->is_empty())
1579 call = Runtime::make_call((expr_is_empty
1580 ? Runtime::IFACEE2E2
1581 : Runtime::IFACEI2E2),
1582 loc, 1, this->expr_);
1583 else
1584 call = this->lower_to_type(expr_is_empty
1585 ? Runtime::IFACEE2I2
1586 : Runtime::IFACEI2I2);
1587 }
1588 else if (this->type_->points_to() != NULL)
1589 call = this->lower_to_type(expr_is_empty
1590 ? Runtime::IFACEE2T2P
1591 : Runtime::IFACEI2T2P);
1592 else
1593 {
1594 this->lower_to_object_type(b,
1595 (expr_is_empty
1596 ? Runtime::IFACEE2T2
1597 : Runtime::IFACEI2T2));
1598 call = NULL;
1599 }
1600
1601 if (call != NULL)
1602 {
1603 Expression* res = Expression::make_call_result(call, 0);
1604 res = Expression::make_unsafe_cast(this->type_, res, loc);
1605 Statement* s = Statement::make_assignment(this->val_, res, loc);
1606 b->add_statement(s);
1607
1608 res = Expression::make_call_result(call, 1);
1609 s = Statement::make_assignment(this->ok_, res, loc);
1610 b->add_statement(s);
1611 }
1612
1613 return Statement::make_block_statement(b, loc);
1614 }
1615
1616 // Lower a conversion to a non-empty interface type or a pointer type.
1617
1618 Call_expression*
lower_to_type(Runtime::Function code)1619 Tuple_type_guard_assignment_statement::lower_to_type(Runtime::Function code)
1620 {
1621 Location loc = this->location();
1622 return Runtime::make_call(code, loc, 2,
1623 Expression::make_type_descriptor(this->type_, loc),
1624 this->expr_);
1625 }
1626
1627 // Lower a conversion to a non-interface non-pointer type.
1628
1629 void
lower_to_object_type(Block * b,Runtime::Function code)1630 Tuple_type_guard_assignment_statement::lower_to_object_type(
1631 Block* b,
1632 Runtime::Function code)
1633 {
1634 Location loc = this->location();
1635
1636 // var val_temp TYPE
1637 Temporary_statement* val_temp = Statement::make_temporary(this->type_,
1638 NULL, loc);
1639 b->add_statement(val_temp);
1640
1641 // ok = CODE(type_descriptor, expr, &val_temp)
1642 Expression* p1 = Expression::make_type_descriptor(this->type_, loc);
1643 Expression* ref = Expression::make_temporary_reference(val_temp, loc);
1644 Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
1645 Expression* call = Runtime::make_call(code, loc, 3, p1, this->expr_, p3);
1646 Statement* s = Statement::make_assignment(this->ok_, call, loc);
1647 b->add_statement(s);
1648
1649 // val = val_temp
1650 ref = Expression::make_temporary_reference(val_temp, loc);
1651 s = Statement::make_assignment(this->val_, ref, loc);
1652 b->add_statement(s);
1653 }
1654
1655 // Dump the AST representation for a tuple type guard statement.
1656
1657 void
do_dump_statement(Ast_dump_context * ast_dump_context) const1658 Tuple_type_guard_assignment_statement::do_dump_statement(
1659 Ast_dump_context* ast_dump_context) const
1660 {
1661 ast_dump_context->print_indent();
1662 ast_dump_context->dump_expression(this->val_);
1663 ast_dump_context->ostream() << ", ";
1664 ast_dump_context->dump_expression(this->ok_);
1665 ast_dump_context->ostream() << " = ";
1666 ast_dump_context->dump_expression(this->expr_);
1667 ast_dump_context->ostream() << " . ";
1668 ast_dump_context->dump_type(this->type_);
1669 ast_dump_context->ostream() << std::endl;
1670 }
1671
1672 // Make an assignment from a type guard to a pair of variables.
1673
1674 Statement*
make_tuple_type_guard_assignment(Expression * val,Expression * ok,Expression * expr,Type * type,Location location)1675 Statement::make_tuple_type_guard_assignment(Expression* val, Expression* ok,
1676 Expression* expr, Type* type,
1677 Location location)
1678 {
1679 return new Tuple_type_guard_assignment_statement(val, ok, expr, type,
1680 location);
1681 }
1682
1683 // Class Expression_statement.
1684
1685 // Constructor.
1686
Expression_statement(Expression * expr,bool is_ignored)1687 Expression_statement::Expression_statement(Expression* expr, bool is_ignored)
1688 : Statement(STATEMENT_EXPRESSION, expr->location()),
1689 expr_(expr), is_ignored_(is_ignored)
1690 {
1691 }
1692
1693 // Determine types.
1694
1695 void
do_determine_types()1696 Expression_statement::do_determine_types()
1697 {
1698 this->expr_->determine_type_no_context();
1699 }
1700
1701 // Check the types of an expression statement. The only check we do
1702 // is to possibly give an error about discarding the value of the
1703 // expression.
1704
1705 void
do_check_types(Gogo *)1706 Expression_statement::do_check_types(Gogo*)
1707 {
1708 if (!this->is_ignored_)
1709 this->expr_->discarding_value();
1710 }
1711
1712 // An expression statement is only a terminating statement if it is
1713 // a call to panic.
1714
1715 bool
do_may_fall_through() const1716 Expression_statement::do_may_fall_through() const
1717 {
1718 const Call_expression* call = this->expr_->call_expression();
1719 if (call != NULL)
1720 {
1721 const Expression* fn = call->fn();
1722 // panic is still an unknown named object.
1723 const Unknown_expression* ue = fn->unknown_expression();
1724 if (ue != NULL)
1725 {
1726 Named_object* no = ue->named_object();
1727
1728 if (no->is_unknown())
1729 no = no->unknown_value()->real_named_object();
1730 if (no != NULL)
1731 {
1732 Function_type* fntype;
1733 if (no->is_function())
1734 fntype = no->func_value()->type();
1735 else if (no->is_function_declaration())
1736 fntype = no->func_declaration_value()->type();
1737 else
1738 fntype = NULL;
1739
1740 // The builtin function panic does not return.
1741 if (fntype != NULL && fntype->is_builtin() && no->name() == "panic")
1742 return false;
1743 }
1744 }
1745 }
1746 return true;
1747 }
1748
1749 // Convert to backend representation.
1750
1751 Bstatement*
do_get_backend(Translate_context * context)1752 Expression_statement::do_get_backend(Translate_context* context)
1753 {
1754 tree expr_tree = this->expr_->get_tree(context);
1755 return context->backend()->expression_statement(tree_to_expr(expr_tree));
1756 }
1757
1758 // Dump the AST representation for an expression statement
1759
1760 void
do_dump_statement(Ast_dump_context * ast_dump_context) const1761 Expression_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
1762 const
1763 {
1764 ast_dump_context->print_indent();
1765 ast_dump_context->dump_expression(expr_);
1766 ast_dump_context->ostream() << std::endl;
1767 }
1768
1769 // Make an expression statement from an Expression.
1770
1771 Statement*
make_statement(Expression * expr,bool is_ignored)1772 Statement::make_statement(Expression* expr, bool is_ignored)
1773 {
1774 return new Expression_statement(expr, is_ignored);
1775 }
1776
1777 // A block statement--a list of statements which may include variable
1778 // definitions.
1779
1780 class Block_statement : public Statement
1781 {
1782 public:
Block_statement(Block * block,Location location)1783 Block_statement(Block* block, Location location)
1784 : Statement(STATEMENT_BLOCK, location),
1785 block_(block)
1786 { }
1787
1788 protected:
1789 int
do_traverse(Traverse * traverse)1790 do_traverse(Traverse* traverse)
1791 { return this->block_->traverse(traverse); }
1792
1793 void
do_determine_types()1794 do_determine_types()
1795 { this->block_->determine_types(); }
1796
1797 bool
do_may_fall_through() const1798 do_may_fall_through() const
1799 { return this->block_->may_fall_through(); }
1800
1801 Bstatement*
1802 do_get_backend(Translate_context* context);
1803
1804 void
1805 do_dump_statement(Ast_dump_context*) const;
1806
1807 private:
1808 Block* block_;
1809 };
1810
1811 // Convert a block to the backend representation of a statement.
1812
1813 Bstatement*
do_get_backend(Translate_context * context)1814 Block_statement::do_get_backend(Translate_context* context)
1815 {
1816 Bblock* bblock = this->block_->get_backend(context);
1817 return context->backend()->block_statement(bblock);
1818 }
1819
1820 // Dump the AST for a block statement
1821
1822 void
do_dump_statement(Ast_dump_context *) const1823 Block_statement::do_dump_statement(Ast_dump_context*) const
1824 {
1825 // block statement braces are dumped when traversing.
1826 }
1827
1828 // Make a block statement.
1829
1830 Statement*
make_block_statement(Block * block,Location location)1831 Statement::make_block_statement(Block* block, Location location)
1832 {
1833 return new Block_statement(block, location);
1834 }
1835
1836 // An increment or decrement statement.
1837
1838 class Inc_dec_statement : public Statement
1839 {
1840 public:
Inc_dec_statement(bool is_inc,Expression * expr)1841 Inc_dec_statement(bool is_inc, Expression* expr)
1842 : Statement(STATEMENT_INCDEC, expr->location()),
1843 expr_(expr), is_inc_(is_inc)
1844 { }
1845
1846 protected:
1847 int
do_traverse(Traverse * traverse)1848 do_traverse(Traverse* traverse)
1849 { return this->traverse_expression(traverse, &this->expr_); }
1850
1851 bool
do_traverse_assignments(Traverse_assignments *)1852 do_traverse_assignments(Traverse_assignments*)
1853 { go_unreachable(); }
1854
1855 Statement*
1856 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1857
1858 Bstatement*
do_get_backend(Translate_context *)1859 do_get_backend(Translate_context*)
1860 { go_unreachable(); }
1861
1862 void
1863 do_dump_statement(Ast_dump_context*) const;
1864
1865 private:
1866 // The l-value to increment or decrement.
1867 Expression* expr_;
1868 // Whether to increment or decrement.
1869 bool is_inc_;
1870 };
1871
1872 // Lower to += or -=.
1873
1874 Statement*
do_lower(Gogo *,Named_object *,Block *,Statement_inserter *)1875 Inc_dec_statement::do_lower(Gogo*, Named_object*, Block*, Statement_inserter*)
1876 {
1877 Location loc = this->location();
1878
1879 mpz_t oval;
1880 mpz_init_set_ui(oval, 1UL);
1881 Expression* oexpr = Expression::make_integer(&oval, NULL, loc);
1882 mpz_clear(oval);
1883
1884 Operator op = this->is_inc_ ? OPERATOR_PLUSEQ : OPERATOR_MINUSEQ;
1885 return Statement::make_assignment_operation(op, this->expr_, oexpr, loc);
1886 }
1887
1888 // Dump the AST representation for a inc/dec statement.
1889
1890 void
do_dump_statement(Ast_dump_context * ast_dump_context) const1891 Inc_dec_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
1892 {
1893 ast_dump_context->print_indent();
1894 ast_dump_context->dump_expression(expr_);
1895 ast_dump_context->ostream() << (is_inc_? "++": "--") << std::endl;
1896 }
1897
1898 // Make an increment statement.
1899
1900 Statement*
make_inc_statement(Expression * expr)1901 Statement::make_inc_statement(Expression* expr)
1902 {
1903 return new Inc_dec_statement(true, expr);
1904 }
1905
1906 // Make a decrement statement.
1907
1908 Statement*
make_dec_statement(Expression * expr)1909 Statement::make_dec_statement(Expression* expr)
1910 {
1911 return new Inc_dec_statement(false, expr);
1912 }
1913
1914 // Class Thunk_statement. This is the base class for go and defer
1915 // statements.
1916
1917 // Constructor.
1918
Thunk_statement(Statement_classification classification,Call_expression * call,Location location)1919 Thunk_statement::Thunk_statement(Statement_classification classification,
1920 Call_expression* call,
1921 Location location)
1922 : Statement(classification, location),
1923 call_(call), struct_type_(NULL)
1924 {
1925 }
1926
1927 // Return whether this is a simple statement which does not require a
1928 // thunk.
1929
1930 bool
is_simple(Function_type * fntype) const1931 Thunk_statement::is_simple(Function_type* fntype) const
1932 {
1933 // We need a thunk to call a method, or to pass a variable number of
1934 // arguments.
1935 if (fntype->is_method() || fntype->is_varargs())
1936 return false;
1937
1938 // A defer statement requires a thunk to set up for whether the
1939 // function can call recover.
1940 if (this->classification() == STATEMENT_DEFER)
1941 return false;
1942
1943 // We can only permit a single parameter of pointer type.
1944 const Typed_identifier_list* parameters = fntype->parameters();
1945 if (parameters != NULL
1946 && (parameters->size() > 1
1947 || (parameters->size() == 1
1948 && parameters->begin()->type()->points_to() == NULL)))
1949 return false;
1950
1951 // If the function returns multiple values, or returns a type other
1952 // than integer, floating point, or pointer, then it may get a
1953 // hidden first parameter, in which case we need the more
1954 // complicated approach. This is true even though we are going to
1955 // ignore the return value.
1956 const Typed_identifier_list* results = fntype->results();
1957 if (results != NULL
1958 && (results->size() > 1
1959 || (results->size() == 1
1960 && !results->begin()->type()->is_basic_type()
1961 && results->begin()->type()->points_to() == NULL)))
1962 return false;
1963
1964 // If this calls something that is not a simple function, then we
1965 // need a thunk.
1966 Expression* fn = this->call_->call_expression()->fn();
1967 if (fn->func_expression() == NULL)
1968 return false;
1969
1970 // If the function uses a closure, then we need a thunk. FIXME: We
1971 // could accept a zero argument function with a closure.
1972 if (fn->func_expression()->closure() != NULL)
1973 return false;
1974
1975 return true;
1976 }
1977
1978 // Traverse a thunk statement.
1979
1980 int
do_traverse(Traverse * traverse)1981 Thunk_statement::do_traverse(Traverse* traverse)
1982 {
1983 return this->traverse_expression(traverse, &this->call_);
1984 }
1985
1986 // We implement traverse_assignment for a thunk statement because it
1987 // effectively copies the function call.
1988
1989 bool
do_traverse_assignments(Traverse_assignments * tassign)1990 Thunk_statement::do_traverse_assignments(Traverse_assignments* tassign)
1991 {
1992 Expression* fn = this->call_->call_expression()->fn();
1993 Expression* fn2 = fn;
1994 tassign->value(&fn2, true, false);
1995 return true;
1996 }
1997
1998 // Determine types in a thunk statement.
1999
2000 void
do_determine_types()2001 Thunk_statement::do_determine_types()
2002 {
2003 this->call_->determine_type_no_context();
2004
2005 // Now that we know the types of the call, build the struct used to
2006 // pass parameters.
2007 Call_expression* ce = this->call_->call_expression();
2008 if (ce == NULL)
2009 return;
2010 Function_type* fntype = ce->get_function_type();
2011 if (fntype != NULL && !this->is_simple(fntype))
2012 this->struct_type_ = this->build_struct(fntype);
2013 }
2014
2015 // Check types in a thunk statement.
2016
2017 void
do_check_types(Gogo *)2018 Thunk_statement::do_check_types(Gogo*)
2019 {
2020 if (!this->call_->discarding_value())
2021 return;
2022 Call_expression* ce = this->call_->call_expression();
2023 if (ce == NULL)
2024 {
2025 if (!this->call_->is_error_expression())
2026 this->report_error("expected call expression");
2027 return;
2028 }
2029 }
2030
2031 // The Traverse class used to find and simplify thunk statements.
2032
2033 class Simplify_thunk_traverse : public Traverse
2034 {
2035 public:
Simplify_thunk_traverse(Gogo * gogo)2036 Simplify_thunk_traverse(Gogo* gogo)
2037 : Traverse(traverse_functions | traverse_blocks),
2038 gogo_(gogo), function_(NULL)
2039 { }
2040
2041 int
2042 function(Named_object*);
2043
2044 int
2045 block(Block*);
2046
2047 private:
2048 // General IR.
2049 Gogo* gogo_;
2050 // The function we are traversing.
2051 Named_object* function_;
2052 };
2053
2054 // Keep track of the current function while looking for thunks.
2055
2056 int
function(Named_object * no)2057 Simplify_thunk_traverse::function(Named_object* no)
2058 {
2059 go_assert(this->function_ == NULL);
2060 this->function_ = no;
2061 int t = no->func_value()->traverse(this);
2062 this->function_ = NULL;
2063 if (t == TRAVERSE_EXIT)
2064 return t;
2065 return TRAVERSE_SKIP_COMPONENTS;
2066 }
2067
2068 // Look for thunks in a block.
2069
2070 int
block(Block * b)2071 Simplify_thunk_traverse::block(Block* b)
2072 {
2073 // The parser ensures that thunk statements always appear at the end
2074 // of a block.
2075 if (b->statements()->size() < 1)
2076 return TRAVERSE_CONTINUE;
2077 Thunk_statement* stat = b->statements()->back()->thunk_statement();
2078 if (stat == NULL)
2079 return TRAVERSE_CONTINUE;
2080 if (stat->simplify_statement(this->gogo_, this->function_, b))
2081 return TRAVERSE_SKIP_COMPONENTS;
2082 return TRAVERSE_CONTINUE;
2083 }
2084
2085 // Simplify all thunk statements.
2086
2087 void
simplify_thunk_statements()2088 Gogo::simplify_thunk_statements()
2089 {
2090 Simplify_thunk_traverse thunk_traverse(this);
2091 this->traverse(&thunk_traverse);
2092 }
2093
2094 // Return true if the thunk function is a constant, which means that
2095 // it does not need to be passed to the thunk routine.
2096
2097 bool
is_constant_function() const2098 Thunk_statement::is_constant_function() const
2099 {
2100 Call_expression* ce = this->call_->call_expression();
2101 Function_type* fntype = ce->get_function_type();
2102 if (fntype == NULL)
2103 {
2104 go_assert(saw_errors());
2105 return false;
2106 }
2107 if (fntype->is_builtin())
2108 return true;
2109 Expression* fn = ce->fn();
2110 if (fn->func_expression() != NULL)
2111 return fn->func_expression()->closure() == NULL;
2112 if (fn->interface_field_reference_expression() != NULL)
2113 return true;
2114 return false;
2115 }
2116
2117 // Simplify complex thunk statements into simple ones. A complicated
2118 // thunk statement is one which takes anything other than zero
2119 // parameters or a single pointer parameter. We rewrite it into code
2120 // which allocates a struct, stores the parameter values into the
2121 // struct, and does a simple go or defer statement which passes the
2122 // struct to a thunk. The thunk does the real call.
2123
2124 bool
simplify_statement(Gogo * gogo,Named_object * function,Block * block)2125 Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
2126 Block* block)
2127 {
2128 if (this->classification() == STATEMENT_ERROR)
2129 return false;
2130 if (this->call_->is_error_expression())
2131 return false;
2132
2133 if (this->classification() == STATEMENT_DEFER)
2134 {
2135 // Make sure that the defer stack exists for the function. We
2136 // will use when converting this statement to the backend
2137 // representation, but we want it to exist when we start
2138 // converting the function.
2139 function->func_value()->defer_stack(this->location());
2140 }
2141
2142 Call_expression* ce = this->call_->call_expression();
2143 Function_type* fntype = ce->get_function_type();
2144 if (fntype == NULL)
2145 {
2146 go_assert(saw_errors());
2147 this->set_is_error();
2148 return false;
2149 }
2150 if (this->is_simple(fntype))
2151 return false;
2152
2153 Expression* fn = ce->fn();
2154 Interface_field_reference_expression* interface_method =
2155 fn->interface_field_reference_expression();
2156
2157 Location location = this->location();
2158
2159 std::string thunk_name = Gogo::thunk_name();
2160
2161 // Build the thunk.
2162 this->build_thunk(gogo, thunk_name);
2163
2164 // Generate code to call the thunk.
2165
2166 // Get the values to store into the struct which is the single
2167 // argument to the thunk.
2168
2169 Expression_list* vals = new Expression_list();
2170 if (!this->is_constant_function())
2171 vals->push_back(fn);
2172
2173 if (interface_method != NULL)
2174 vals->push_back(interface_method->expr());
2175
2176 if (ce->args() != NULL)
2177 {
2178 for (Expression_list::const_iterator p = ce->args()->begin();
2179 p != ce->args()->end();
2180 ++p)
2181 vals->push_back(*p);
2182 }
2183
2184 // Build the struct.
2185 Expression* constructor =
2186 Expression::make_struct_composite_literal(this->struct_type_, vals,
2187 location);
2188
2189 // Allocate the initialized struct on the heap.
2190 constructor = Expression::make_heap_composite(constructor, location);
2191
2192 // Look up the thunk.
2193 Named_object* named_thunk = gogo->lookup(thunk_name, NULL);
2194 go_assert(named_thunk != NULL && named_thunk->is_function());
2195
2196 // Build the call.
2197 Expression* func = Expression::make_func_reference(named_thunk, NULL,
2198 location);
2199 Expression_list* params = new Expression_list();
2200 params->push_back(constructor);
2201 Call_expression* call = Expression::make_call(func, params, false, location);
2202
2203 // Build the simple go or defer statement.
2204 Statement* s;
2205 if (this->classification() == STATEMENT_GO)
2206 s = Statement::make_go_statement(call, location);
2207 else if (this->classification() == STATEMENT_DEFER)
2208 s = Statement::make_defer_statement(call, location);
2209 else
2210 go_unreachable();
2211
2212 // The current block should end with the go statement.
2213 go_assert(block->statements()->size() >= 1);
2214 go_assert(block->statements()->back() == this);
2215 block->replace_statement(block->statements()->size() - 1, s);
2216
2217 // We already ran the determine_types pass, so we need to run it now
2218 // for the new statement.
2219 s->determine_types();
2220
2221 // Sanity check.
2222 gogo->check_types_in_block(block);
2223
2224 // Return true to tell the block not to keep looking at statements.
2225 return true;
2226 }
2227
2228 // Set the name to use for thunk parameter N.
2229
2230 void
thunk_field_param(int n,char * buf,size_t buflen)2231 Thunk_statement::thunk_field_param(int n, char* buf, size_t buflen)
2232 {
2233 snprintf(buf, buflen, "a%d", n);
2234 }
2235
2236 // Build a new struct type to hold the parameters for a complicated
2237 // thunk statement. FNTYPE is the type of the function call.
2238
2239 Struct_type*
build_struct(Function_type * fntype)2240 Thunk_statement::build_struct(Function_type* fntype)
2241 {
2242 Location location = this->location();
2243
2244 Struct_field_list* fields = new Struct_field_list();
2245
2246 Call_expression* ce = this->call_->call_expression();
2247 Expression* fn = ce->fn();
2248
2249 if (!this->is_constant_function())
2250 {
2251 // The function to call.
2252 fields->push_back(Struct_field(Typed_identifier("fn", fntype,
2253 location)));
2254 }
2255
2256 // If this thunk statement calls a method on an interface, we pass
2257 // the interface object to the thunk.
2258 Interface_field_reference_expression* interface_method =
2259 fn->interface_field_reference_expression();
2260 if (interface_method != NULL)
2261 {
2262 Typed_identifier tid("object", interface_method->expr()->type(),
2263 location);
2264 fields->push_back(Struct_field(tid));
2265 }
2266
2267 // The predeclared recover function has no argument. However, we
2268 // add an argument when building recover thunks. Handle that here.
2269 if (ce->is_recover_call())
2270 {
2271 fields->push_back(Struct_field(Typed_identifier("can_recover",
2272 Type::lookup_bool_type(),
2273 location)));
2274 }
2275
2276 const Expression_list* args = ce->args();
2277 if (args != NULL)
2278 {
2279 int i = 0;
2280 for (Expression_list::const_iterator p = args->begin();
2281 p != args->end();
2282 ++p, ++i)
2283 {
2284 char buf[50];
2285 this->thunk_field_param(i, buf, sizeof buf);
2286 fields->push_back(Struct_field(Typed_identifier(buf, (*p)->type(),
2287 location)));
2288 }
2289 }
2290
2291 return Type::make_struct_type(fields, location);
2292 }
2293
2294 // Build the thunk we are going to call. This is a brand new, albeit
2295 // artificial, function.
2296
2297 void
build_thunk(Gogo * gogo,const std::string & thunk_name)2298 Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
2299 {
2300 Location location = this->location();
2301
2302 Call_expression* ce = this->call_->call_expression();
2303
2304 bool may_call_recover = false;
2305 if (this->classification() == STATEMENT_DEFER)
2306 {
2307 Func_expression* fn = ce->fn()->func_expression();
2308 if (fn == NULL)
2309 may_call_recover = true;
2310 else
2311 {
2312 const Named_object* no = fn->named_object();
2313 if (!no->is_function())
2314 may_call_recover = true;
2315 else
2316 may_call_recover = no->func_value()->calls_recover();
2317 }
2318 }
2319
2320 // Build the type of the thunk. The thunk takes a single parameter,
2321 // which is a pointer to the special structure we build.
2322 const char* const parameter_name = "__go_thunk_parameter";
2323 Typed_identifier_list* thunk_parameters = new Typed_identifier_list();
2324 Type* pointer_to_struct_type = Type::make_pointer_type(this->struct_type_);
2325 thunk_parameters->push_back(Typed_identifier(parameter_name,
2326 pointer_to_struct_type,
2327 location));
2328
2329 Typed_identifier_list* thunk_results = NULL;
2330 if (may_call_recover)
2331 {
2332 // When deferring a function which may call recover, add a
2333 // return value, to disable tail call optimizations which will
2334 // break the way we check whether recover is permitted.
2335 thunk_results = new Typed_identifier_list();
2336 thunk_results->push_back(Typed_identifier("", Type::lookup_bool_type(),
2337 location));
2338 }
2339
2340 Function_type* thunk_type = Type::make_function_type(NULL, thunk_parameters,
2341 thunk_results,
2342 location);
2343
2344 // Start building the thunk.
2345 Named_object* function = gogo->start_function(thunk_name, thunk_type, true,
2346 location);
2347
2348 gogo->start_block(location);
2349
2350 // For a defer statement, start with a call to
2351 // __go_set_defer_retaddr. */
2352 Label* retaddr_label = NULL;
2353 if (may_call_recover)
2354 {
2355 retaddr_label = gogo->add_label_reference("retaddr", location, false);
2356 Expression* arg = Expression::make_label_addr(retaddr_label, location);
2357 Expression* call = Runtime::make_call(Runtime::SET_DEFER_RETADDR,
2358 location, 1, arg);
2359
2360 // This is a hack to prevent the middle-end from deleting the
2361 // label.
2362 gogo->start_block(location);
2363 gogo->add_statement(Statement::make_goto_statement(retaddr_label,
2364 location));
2365 Block* then_block = gogo->finish_block(location);
2366 then_block->determine_types();
2367
2368 Statement* s = Statement::make_if_statement(call, then_block, NULL,
2369 location);
2370 s->determine_types();
2371 gogo->add_statement(s);
2372 }
2373
2374 // Get a reference to the parameter.
2375 Named_object* named_parameter = gogo->lookup(parameter_name, NULL);
2376 go_assert(named_parameter != NULL && named_parameter->is_variable());
2377
2378 // Build the call. Note that the field names are the same as the
2379 // ones used in build_struct.
2380 Expression* thunk_parameter = Expression::make_var_reference(named_parameter,
2381 location);
2382 thunk_parameter = Expression::make_unary(OPERATOR_MULT, thunk_parameter,
2383 location);
2384
2385 Interface_field_reference_expression* interface_method =
2386 ce->fn()->interface_field_reference_expression();
2387
2388 Expression* func_to_call;
2389 unsigned int next_index;
2390 if (this->is_constant_function())
2391 {
2392 func_to_call = ce->fn();
2393 next_index = 0;
2394 }
2395 else
2396 {
2397 func_to_call = Expression::make_field_reference(thunk_parameter,
2398 0, location);
2399 next_index = 1;
2400 }
2401
2402 if (interface_method != NULL)
2403 {
2404 // The main program passes the interface object.
2405 go_assert(next_index == 0);
2406 Expression* r = Expression::make_field_reference(thunk_parameter, 0,
2407 location);
2408 const std::string& name(interface_method->name());
2409 func_to_call = Expression::make_interface_field_reference(r, name,
2410 location);
2411 next_index = 1;
2412 }
2413
2414 Expression_list* call_params = new Expression_list();
2415 const Struct_field_list* fields = this->struct_type_->fields();
2416 Struct_field_list::const_iterator p = fields->begin();
2417 for (unsigned int i = 0; i < next_index; ++i)
2418 ++p;
2419 bool is_recover_call = ce->is_recover_call();
2420 Expression* recover_arg = NULL;
2421 for (; p != fields->end(); ++p, ++next_index)
2422 {
2423 Expression* thunk_param = Expression::make_var_reference(named_parameter,
2424 location);
2425 thunk_param = Expression::make_unary(OPERATOR_MULT, thunk_param,
2426 location);
2427 Expression* param = Expression::make_field_reference(thunk_param,
2428 next_index,
2429 location);
2430 if (!is_recover_call)
2431 call_params->push_back(param);
2432 else
2433 {
2434 go_assert(call_params->empty());
2435 recover_arg = param;
2436 }
2437 }
2438
2439 if (call_params->empty())
2440 {
2441 delete call_params;
2442 call_params = NULL;
2443 }
2444
2445 Call_expression* call = Expression::make_call(func_to_call, call_params,
2446 false, location);
2447
2448 // This call expression was already lowered before entering the
2449 // thunk statement. Don't try to lower varargs again, as that will
2450 // cause confusion for, e.g., method calls which already have a
2451 // receiver parameter.
2452 call->set_varargs_are_lowered();
2453
2454 Statement* call_statement = Statement::make_statement(call, true);
2455
2456 gogo->add_statement(call_statement);
2457
2458 // If this is a defer statement, the label comes immediately after
2459 // the call.
2460 if (may_call_recover)
2461 {
2462 gogo->add_label_definition("retaddr", location);
2463
2464 Expression_list* vals = new Expression_list();
2465 vals->push_back(Expression::make_boolean(false, location));
2466 gogo->add_statement(Statement::make_return_statement(vals, location));
2467 }
2468
2469 Block* b = gogo->finish_block(location);
2470
2471 gogo->add_block(b, location);
2472
2473 gogo->lower_block(function, b);
2474 gogo->flatten_block(function, b);
2475
2476 // We already ran the determine_types pass, so we need to run it
2477 // just for the call statement now. The other types are known.
2478 call_statement->determine_types();
2479
2480 if (may_call_recover || recover_arg != NULL)
2481 {
2482 // Dig up the call expression, which may have been changed
2483 // during lowering.
2484 go_assert(call_statement->classification() == STATEMENT_EXPRESSION);
2485 Expression_statement* es =
2486 static_cast<Expression_statement*>(call_statement);
2487 Call_expression* ce = es->expr()->call_expression();
2488 if (ce == NULL)
2489 go_assert(saw_errors());
2490 else
2491 {
2492 if (may_call_recover)
2493 ce->set_is_deferred();
2494 if (recover_arg != NULL)
2495 ce->set_recover_arg(recover_arg);
2496 }
2497 }
2498
2499 // That is all the thunk has to do.
2500 gogo->finish_function(location);
2501 }
2502
2503 // Get the function and argument expressions.
2504
2505 bool
get_fn_and_arg(Expression ** pfn,Expression ** parg)2506 Thunk_statement::get_fn_and_arg(Expression** pfn, Expression** parg)
2507 {
2508 if (this->call_->is_error_expression())
2509 return false;
2510
2511 Call_expression* ce = this->call_->call_expression();
2512
2513 Expression* fn = ce->fn();
2514 Func_expression* fe = fn->func_expression();
2515 go_assert(fe != NULL);
2516 *pfn = Expression::make_func_code_reference(fe->named_object(),
2517 fe->location());
2518
2519 const Expression_list* args = ce->args();
2520 if (args == NULL || args->empty())
2521 *parg = Expression::make_nil(this->location());
2522 else
2523 {
2524 go_assert(args->size() == 1);
2525 *parg = args->front();
2526 }
2527
2528 return true;
2529 }
2530
2531 // Class Go_statement.
2532
2533 Bstatement*
do_get_backend(Translate_context * context)2534 Go_statement::do_get_backend(Translate_context* context)
2535 {
2536 Expression* fn;
2537 Expression* arg;
2538 if (!this->get_fn_and_arg(&fn, &arg))
2539 return context->backend()->error_statement();
2540
2541 Expression* call = Runtime::make_call(Runtime::GO, this->location(), 2,
2542 fn, arg);
2543 tree call_tree = call->get_tree(context);
2544 Bexpression* call_bexpr = tree_to_expr(call_tree);
2545 return context->backend()->expression_statement(call_bexpr);
2546 }
2547
2548 // Dump the AST representation for go statement.
2549
2550 void
do_dump_statement(Ast_dump_context * ast_dump_context) const2551 Go_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
2552 {
2553 ast_dump_context->print_indent();
2554 ast_dump_context->ostream() << "go ";
2555 ast_dump_context->dump_expression(this->call());
2556 ast_dump_context->ostream() << std::endl;
2557 }
2558
2559 // Make a go statement.
2560
2561 Statement*
make_go_statement(Call_expression * call,Location location)2562 Statement::make_go_statement(Call_expression* call, Location location)
2563 {
2564 return new Go_statement(call, location);
2565 }
2566
2567 // Class Defer_statement.
2568
2569 Bstatement*
do_get_backend(Translate_context * context)2570 Defer_statement::do_get_backend(Translate_context* context)
2571 {
2572 Expression* fn;
2573 Expression* arg;
2574 if (!this->get_fn_and_arg(&fn, &arg))
2575 return context->backend()->error_statement();
2576
2577 Location loc = this->location();
2578 Expression* ds = context->function()->func_value()->defer_stack(loc);
2579
2580 Expression* call = Runtime::make_call(Runtime::DEFER, loc, 3,
2581 ds, fn, arg);
2582 tree call_tree = call->get_tree(context);
2583 Bexpression* call_bexpr = tree_to_expr(call_tree);
2584 return context->backend()->expression_statement(call_bexpr);
2585 }
2586
2587 // Dump the AST representation for defer statement.
2588
2589 void
do_dump_statement(Ast_dump_context * ast_dump_context) const2590 Defer_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
2591 {
2592 ast_dump_context->print_indent();
2593 ast_dump_context->ostream() << "defer ";
2594 ast_dump_context->dump_expression(this->call());
2595 ast_dump_context->ostream() << std::endl;
2596 }
2597
2598 // Make a defer statement.
2599
2600 Statement*
make_defer_statement(Call_expression * call,Location location)2601 Statement::make_defer_statement(Call_expression* call,
2602 Location location)
2603 {
2604 return new Defer_statement(call, location);
2605 }
2606
2607 // Class Return_statement.
2608
2609 // Traverse assignments. We treat each return value as a top level
2610 // RHS in an expression.
2611
2612 bool
do_traverse_assignments(Traverse_assignments * tassign)2613 Return_statement::do_traverse_assignments(Traverse_assignments* tassign)
2614 {
2615 Expression_list* vals = this->vals_;
2616 if (vals != NULL)
2617 {
2618 for (Expression_list::iterator p = vals->begin();
2619 p != vals->end();
2620 ++p)
2621 tassign->value(&*p, true, true);
2622 }
2623 return true;
2624 }
2625
2626 // Lower a return statement. If we are returning a function call
2627 // which returns multiple values which match the current function,
2628 // split up the call's results. If the return statement lists
2629 // explicit values, implement this statement by assigning the values
2630 // to the result variables and change this statement to a naked
2631 // return. This lets panic/recover work correctly.
2632
2633 Statement*
do_lower(Gogo *,Named_object * function,Block * enclosing,Statement_inserter *)2634 Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing,
2635 Statement_inserter*)
2636 {
2637 if (this->is_lowered_)
2638 return this;
2639
2640 Expression_list* vals = this->vals_;
2641 this->vals_ = NULL;
2642 this->is_lowered_ = true;
2643
2644 Location loc = this->location();
2645
2646 size_t vals_count = vals == NULL ? 0 : vals->size();
2647 Function::Results* results = function->func_value()->result_variables();
2648 size_t results_count = results == NULL ? 0 : results->size();
2649
2650 if (vals_count == 0)
2651 {
2652 if (results_count > 0 && !function->func_value()->results_are_named())
2653 {
2654 this->report_error(_("not enough arguments to return"));
2655 return this;
2656 }
2657 return this;
2658 }
2659
2660 if (results_count == 0)
2661 {
2662 this->report_error(_("return with value in function "
2663 "with no return type"));
2664 return this;
2665 }
2666
2667 // If the current function has multiple return values, and we are
2668 // returning a single call expression, split up the call expression.
2669 if (results_count > 1
2670 && vals->size() == 1
2671 && vals->front()->call_expression() != NULL)
2672 {
2673 Call_expression* call = vals->front()->call_expression();
2674 delete vals;
2675 vals = new Expression_list;
2676 for (size_t i = 0; i < results_count; ++i)
2677 vals->push_back(Expression::make_call_result(call, i));
2678 vals_count = results_count;
2679 }
2680
2681 if (vals_count < results_count)
2682 {
2683 this->report_error(_("not enough arguments to return"));
2684 return this;
2685 }
2686
2687 if (vals_count > results_count)
2688 {
2689 this->report_error(_("too many values in return statement"));
2690 return this;
2691 }
2692
2693 Block* b = new Block(enclosing, loc);
2694
2695 Expression_list* lhs = new Expression_list();
2696 Expression_list* rhs = new Expression_list();
2697
2698 Expression_list::const_iterator pe = vals->begin();
2699 int i = 1;
2700 for (Function::Results::const_iterator pr = results->begin();
2701 pr != results->end();
2702 ++pr, ++pe, ++i)
2703 {
2704 Named_object* rv = *pr;
2705 Expression* e = *pe;
2706
2707 // Check types now so that we give a good error message. The
2708 // result type is known. We determine the expression type
2709 // early.
2710
2711 Type *rvtype = rv->result_var_value()->type();
2712 Type_context type_context(rvtype, false);
2713 e->determine_type(&type_context);
2714
2715 std::string reason;
2716 bool ok;
2717 if (this->are_hidden_fields_ok_)
2718 ok = Type::are_assignable_hidden_ok(rvtype, e->type(), &reason);
2719 else
2720 ok = Type::are_assignable(rvtype, e->type(), &reason);
2721 if (ok)
2722 {
2723 Expression* ve = Expression::make_var_reference(rv, e->location());
2724 lhs->push_back(ve);
2725 rhs->push_back(e);
2726 }
2727 else
2728 {
2729 if (reason.empty())
2730 error_at(e->location(), "incompatible type for return value %d", i);
2731 else
2732 error_at(e->location(),
2733 "incompatible type for return value %d (%s)",
2734 i, reason.c_str());
2735 }
2736 }
2737 go_assert(lhs->size() == rhs->size());
2738
2739 if (lhs->empty())
2740 ;
2741 else if (lhs->size() == 1)
2742 {
2743 Statement* s = Statement::make_assignment(lhs->front(), rhs->front(),
2744 loc);
2745 if (this->are_hidden_fields_ok_)
2746 {
2747 Assignment_statement* as = static_cast<Assignment_statement*>(s);
2748 as->set_hidden_fields_are_ok();
2749 }
2750 b->add_statement(s);
2751 delete lhs;
2752 delete rhs;
2753 }
2754 else
2755 {
2756 Statement* s = Statement::make_tuple_assignment(lhs, rhs, loc);
2757 if (this->are_hidden_fields_ok_)
2758 {
2759 Tuple_assignment_statement* tas =
2760 static_cast<Tuple_assignment_statement*>(s);
2761 tas->set_hidden_fields_are_ok();
2762 }
2763 b->add_statement(s);
2764 }
2765
2766 b->add_statement(this);
2767
2768 delete vals;
2769
2770 return Statement::make_block_statement(b, loc);
2771 }
2772
2773 // Convert a return statement to the backend representation.
2774
2775 Bstatement*
do_get_backend(Translate_context * context)2776 Return_statement::do_get_backend(Translate_context* context)
2777 {
2778 Location loc = this->location();
2779
2780 Function* function = context->function()->func_value();
2781 tree fndecl = function->get_decl();
2782
2783 Function::Results* results = function->result_variables();
2784 std::vector<Bexpression*> retvals;
2785 if (results != NULL && !results->empty())
2786 {
2787 retvals.reserve(results->size());
2788 for (Function::Results::const_iterator p = results->begin();
2789 p != results->end();
2790 p++)
2791 {
2792 Expression* vr = Expression::make_var_reference(*p, loc);
2793 retvals.push_back(tree_to_expr(vr->get_tree(context)));
2794 }
2795 }
2796
2797 return context->backend()->return_statement(tree_to_function(fndecl),
2798 retvals, loc);
2799 }
2800
2801 // Dump the AST representation for a return statement.
2802
2803 void
do_dump_statement(Ast_dump_context * ast_dump_context) const2804 Return_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
2805 {
2806 ast_dump_context->print_indent();
2807 ast_dump_context->ostream() << "return " ;
2808 ast_dump_context->dump_expression_list(this->vals_);
2809 ast_dump_context->ostream() << std::endl;
2810 }
2811
2812 // Make a return statement.
2813
2814 Return_statement*
make_return_statement(Expression_list * vals,Location location)2815 Statement::make_return_statement(Expression_list* vals,
2816 Location location)
2817 {
2818 return new Return_statement(vals, location);
2819 }
2820
2821 // Make a statement that returns the result of a call expression.
2822
2823 Statement*
make_return_from_call(Call_expression * call,Location location)2824 Statement::make_return_from_call(Call_expression* call, Location location)
2825 {
2826 size_t rc = call->result_count();
2827 if (rc == 0)
2828 return Statement::make_statement(call, true);
2829 else
2830 {
2831 Expression_list* vals = new Expression_list();
2832 if (rc == 1)
2833 vals->push_back(call);
2834 else
2835 {
2836 for (size_t i = 0; i < rc; ++i)
2837 vals->push_back(Expression::make_call_result(call, i));
2838 }
2839 return Statement::make_return_statement(vals, location);
2840 }
2841 }
2842
2843 // A break or continue statement.
2844
2845 class Bc_statement : public Statement
2846 {
2847 public:
Bc_statement(bool is_break,Unnamed_label * label,Location location)2848 Bc_statement(bool is_break, Unnamed_label* label, Location location)
2849 : Statement(STATEMENT_BREAK_OR_CONTINUE, location),
2850 label_(label), is_break_(is_break)
2851 { }
2852
2853 bool
is_break() const2854 is_break() const
2855 { return this->is_break_; }
2856
2857 protected:
2858 int
do_traverse(Traverse *)2859 do_traverse(Traverse*)
2860 { return TRAVERSE_CONTINUE; }
2861
2862 bool
do_may_fall_through() const2863 do_may_fall_through() const
2864 { return false; }
2865
2866 Bstatement*
do_get_backend(Translate_context * context)2867 do_get_backend(Translate_context* context)
2868 { return this->label_->get_goto(context, this->location()); }
2869
2870 void
2871 do_dump_statement(Ast_dump_context*) const;
2872
2873 private:
2874 // The label that this branches to.
2875 Unnamed_label* label_;
2876 // True if this is "break", false if it is "continue".
2877 bool is_break_;
2878 };
2879
2880 // Dump the AST representation for a break/continue statement
2881
2882 void
do_dump_statement(Ast_dump_context * ast_dump_context) const2883 Bc_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
2884 {
2885 ast_dump_context->print_indent();
2886 ast_dump_context->ostream() << (this->is_break_ ? "break" : "continue");
2887 if (this->label_ != NULL)
2888 {
2889 ast_dump_context->ostream() << " ";
2890 ast_dump_context->dump_label_name(this->label_);
2891 }
2892 ast_dump_context->ostream() << std::endl;
2893 }
2894
2895 // Make a break statement.
2896
2897 Statement*
make_break_statement(Unnamed_label * label,Location location)2898 Statement::make_break_statement(Unnamed_label* label, Location location)
2899 {
2900 return new Bc_statement(true, label, location);
2901 }
2902
2903 // Make a continue statement.
2904
2905 Statement*
make_continue_statement(Unnamed_label * label,Location location)2906 Statement::make_continue_statement(Unnamed_label* label,
2907 Location location)
2908 {
2909 return new Bc_statement(false, label, location);
2910 }
2911
2912 // A goto statement.
2913
2914 class Goto_statement : public Statement
2915 {
2916 public:
Goto_statement(Label * label,Location location)2917 Goto_statement(Label* label, Location location)
2918 : Statement(STATEMENT_GOTO, location),
2919 label_(label)
2920 { }
2921
2922 protected:
2923 int
do_traverse(Traverse *)2924 do_traverse(Traverse*)
2925 { return TRAVERSE_CONTINUE; }
2926
2927 void
2928 do_check_types(Gogo*);
2929
2930 bool
do_may_fall_through() const2931 do_may_fall_through() const
2932 { return false; }
2933
2934 Bstatement*
2935 do_get_backend(Translate_context*);
2936
2937 void
2938 do_dump_statement(Ast_dump_context*) const;
2939
2940 private:
2941 Label* label_;
2942 };
2943
2944 // Check types for a label. There aren't any types per se, but we use
2945 // this to give an error if the label was never defined.
2946
2947 void
do_check_types(Gogo *)2948 Goto_statement::do_check_types(Gogo*)
2949 {
2950 if (!this->label_->is_defined())
2951 {
2952 error_at(this->location(), "reference to undefined label %qs",
2953 Gogo::message_name(this->label_->name()).c_str());
2954 this->set_is_error();
2955 }
2956 }
2957
2958 // Convert the goto statement to the backend representation.
2959
2960 Bstatement*
do_get_backend(Translate_context * context)2961 Goto_statement::do_get_backend(Translate_context* context)
2962 {
2963 Blabel* blabel = this->label_->get_backend_label(context);
2964 return context->backend()->goto_statement(blabel, this->location());
2965 }
2966
2967 // Dump the AST representation for a goto statement.
2968
2969 void
do_dump_statement(Ast_dump_context * ast_dump_context) const2970 Goto_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
2971 {
2972 ast_dump_context->print_indent();
2973 ast_dump_context->ostream() << "goto " << this->label_->name() << std::endl;
2974 }
2975
2976 // Make a goto statement.
2977
2978 Statement*
make_goto_statement(Label * label,Location location)2979 Statement::make_goto_statement(Label* label, Location location)
2980 {
2981 return new Goto_statement(label, location);
2982 }
2983
2984 // A goto statement to an unnamed label.
2985
2986 class Goto_unnamed_statement : public Statement
2987 {
2988 public:
Goto_unnamed_statement(Unnamed_label * label,Location location)2989 Goto_unnamed_statement(Unnamed_label* label, Location location)
2990 : Statement(STATEMENT_GOTO_UNNAMED, location),
2991 label_(label)
2992 { }
2993
2994 protected:
2995 int
do_traverse(Traverse *)2996 do_traverse(Traverse*)
2997 { return TRAVERSE_CONTINUE; }
2998
2999 bool
do_may_fall_through() const3000 do_may_fall_through() const
3001 { return false; }
3002
3003 Bstatement*
do_get_backend(Translate_context * context)3004 do_get_backend(Translate_context* context)
3005 { return this->label_->get_goto(context, this->location()); }
3006
3007 void
3008 do_dump_statement(Ast_dump_context*) const;
3009
3010 private:
3011 Unnamed_label* label_;
3012 };
3013
3014 // Dump the AST representation for an unnamed goto statement
3015
3016 void
do_dump_statement(Ast_dump_context * ast_dump_context) const3017 Goto_unnamed_statement::do_dump_statement(
3018 Ast_dump_context* ast_dump_context) const
3019 {
3020 ast_dump_context->print_indent();
3021 ast_dump_context->ostream() << "goto ";
3022 ast_dump_context->dump_label_name(this->label_);
3023 ast_dump_context->ostream() << std::endl;
3024 }
3025
3026 // Make a goto statement to an unnamed label.
3027
3028 Statement*
make_goto_unnamed_statement(Unnamed_label * label,Location location)3029 Statement::make_goto_unnamed_statement(Unnamed_label* label,
3030 Location location)
3031 {
3032 return new Goto_unnamed_statement(label, location);
3033 }
3034
3035 // Class Label_statement.
3036
3037 // Traversal.
3038
3039 int
do_traverse(Traverse *)3040 Label_statement::do_traverse(Traverse*)
3041 {
3042 return TRAVERSE_CONTINUE;
3043 }
3044
3045 // Return the backend representation of the statement defining this
3046 // label.
3047
3048 Bstatement*
do_get_backend(Translate_context * context)3049 Label_statement::do_get_backend(Translate_context* context)
3050 {
3051 Blabel* blabel = this->label_->get_backend_label(context);
3052 return context->backend()->label_definition_statement(blabel);
3053 }
3054
3055 // Dump the AST for a label definition statement.
3056
3057 void
do_dump_statement(Ast_dump_context * ast_dump_context) const3058 Label_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3059 {
3060 ast_dump_context->print_indent();
3061 ast_dump_context->ostream() << this->label_->name() << ":" << std::endl;
3062 }
3063
3064 // Make a label statement.
3065
3066 Statement*
make_label_statement(Label * label,Location location)3067 Statement::make_label_statement(Label* label, Location location)
3068 {
3069 return new Label_statement(label, location);
3070 }
3071
3072 // An unnamed label statement.
3073
3074 class Unnamed_label_statement : public Statement
3075 {
3076 public:
Unnamed_label_statement(Unnamed_label * label)3077 Unnamed_label_statement(Unnamed_label* label)
3078 : Statement(STATEMENT_UNNAMED_LABEL, label->location()),
3079 label_(label)
3080 { }
3081
3082 protected:
3083 int
do_traverse(Traverse *)3084 do_traverse(Traverse*)
3085 { return TRAVERSE_CONTINUE; }
3086
3087 Bstatement*
do_get_backend(Translate_context * context)3088 do_get_backend(Translate_context* context)
3089 { return this->label_->get_definition(context); }
3090
3091 void
3092 do_dump_statement(Ast_dump_context*) const;
3093
3094 private:
3095 // The label.
3096 Unnamed_label* label_;
3097 };
3098
3099 // Dump the AST representation for an unnamed label definition statement.
3100
3101 void
do_dump_statement(Ast_dump_context * ast_dump_context) const3102 Unnamed_label_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
3103 const
3104 {
3105 ast_dump_context->print_indent();
3106 ast_dump_context->dump_label_name(this->label_);
3107 ast_dump_context->ostream() << ":" << std::endl;
3108 }
3109
3110 // Make an unnamed label statement.
3111
3112 Statement*
make_unnamed_label_statement(Unnamed_label * label)3113 Statement::make_unnamed_label_statement(Unnamed_label* label)
3114 {
3115 return new Unnamed_label_statement(label);
3116 }
3117
3118 // An if statement.
3119
3120 class If_statement : public Statement
3121 {
3122 public:
If_statement(Expression * cond,Block * then_block,Block * else_block,Location location)3123 If_statement(Expression* cond, Block* then_block, Block* else_block,
3124 Location location)
3125 : Statement(STATEMENT_IF, location),
3126 cond_(cond), then_block_(then_block), else_block_(else_block)
3127 { }
3128
3129 protected:
3130 int
3131 do_traverse(Traverse*);
3132
3133 void
3134 do_determine_types();
3135
3136 void
3137 do_check_types(Gogo*);
3138
3139 bool
3140 do_may_fall_through() const;
3141
3142 Bstatement*
3143 do_get_backend(Translate_context*);
3144
3145 void
3146 do_dump_statement(Ast_dump_context*) const;
3147
3148 private:
3149 Expression* cond_;
3150 Block* then_block_;
3151 Block* else_block_;
3152 };
3153
3154 // Traversal.
3155
3156 int
do_traverse(Traverse * traverse)3157 If_statement::do_traverse(Traverse* traverse)
3158 {
3159 if (this->traverse_expression(traverse, &this->cond_) == TRAVERSE_EXIT
3160 || this->then_block_->traverse(traverse) == TRAVERSE_EXIT)
3161 return TRAVERSE_EXIT;
3162 if (this->else_block_ != NULL)
3163 {
3164 if (this->else_block_->traverse(traverse) == TRAVERSE_EXIT)
3165 return TRAVERSE_EXIT;
3166 }
3167 return TRAVERSE_CONTINUE;
3168 }
3169
3170 void
do_determine_types()3171 If_statement::do_determine_types()
3172 {
3173 Type_context context(Type::lookup_bool_type(), false);
3174 this->cond_->determine_type(&context);
3175 this->then_block_->determine_types();
3176 if (this->else_block_ != NULL)
3177 this->else_block_->determine_types();
3178 }
3179
3180 // Check types.
3181
3182 void
do_check_types(Gogo *)3183 If_statement::do_check_types(Gogo*)
3184 {
3185 Type* type = this->cond_->type();
3186 if (type->is_error())
3187 this->set_is_error();
3188 else if (!type->is_boolean_type())
3189 this->report_error(_("expected boolean expression"));
3190 }
3191
3192 // Whether the overall statement may fall through.
3193
3194 bool
do_may_fall_through() const3195 If_statement::do_may_fall_through() const
3196 {
3197 return (this->else_block_ == NULL
3198 || this->then_block_->may_fall_through()
3199 || this->else_block_->may_fall_through());
3200 }
3201
3202 // Get the backend representation.
3203
3204 Bstatement*
do_get_backend(Translate_context * context)3205 If_statement::do_get_backend(Translate_context* context)
3206 {
3207 go_assert(this->cond_->type()->is_boolean_type()
3208 || this->cond_->type()->is_error());
3209 tree cond_tree = this->cond_->get_tree(context);
3210 Bexpression* cond_expr = tree_to_expr(cond_tree);
3211 Bblock* then_block = this->then_block_->get_backend(context);
3212 Bblock* else_block = (this->else_block_ == NULL
3213 ? NULL
3214 : this->else_block_->get_backend(context));
3215 return context->backend()->if_statement(cond_expr, then_block,
3216 else_block, this->location());
3217 }
3218
3219 // Dump the AST representation for an if statement
3220
3221 void
do_dump_statement(Ast_dump_context * ast_dump_context) const3222 If_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3223 {
3224 ast_dump_context->print_indent();
3225 ast_dump_context->ostream() << "if ";
3226 ast_dump_context->dump_expression(this->cond_);
3227 ast_dump_context->ostream() << std::endl;
3228 if (ast_dump_context->dump_subblocks())
3229 {
3230 ast_dump_context->dump_block(this->then_block_);
3231 if (this->else_block_ != NULL)
3232 {
3233 ast_dump_context->print_indent();
3234 ast_dump_context->ostream() << "else" << std::endl;
3235 ast_dump_context->dump_block(this->else_block_);
3236 }
3237 }
3238 }
3239
3240 // Make an if statement.
3241
3242 Statement*
make_if_statement(Expression * cond,Block * then_block,Block * else_block,Location location)3243 Statement::make_if_statement(Expression* cond, Block* then_block,
3244 Block* else_block, Location location)
3245 {
3246 return new If_statement(cond, then_block, else_block, location);
3247 }
3248
3249 // Class Case_clauses::Hash_integer_value.
3250
3251 class Case_clauses::Hash_integer_value
3252 {
3253 public:
3254 size_t
3255 operator()(Expression*) const;
3256 };
3257
3258 size_t
operator ()(Expression * pe) const3259 Case_clauses::Hash_integer_value::operator()(Expression* pe) const
3260 {
3261 Numeric_constant nc;
3262 mpz_t ival;
3263 if (!pe->numeric_constant_value(&nc) || !nc.to_int(&ival))
3264 go_unreachable();
3265 size_t ret = mpz_get_ui(ival);
3266 mpz_clear(ival);
3267 return ret;
3268 }
3269
3270 // Class Case_clauses::Eq_integer_value.
3271
3272 class Case_clauses::Eq_integer_value
3273 {
3274 public:
3275 bool
3276 operator()(Expression*, Expression*) const;
3277 };
3278
3279 bool
operator ()(Expression * a,Expression * b) const3280 Case_clauses::Eq_integer_value::operator()(Expression* a, Expression* b) const
3281 {
3282 Numeric_constant anc;
3283 mpz_t aval;
3284 Numeric_constant bnc;
3285 mpz_t bval;
3286 if (!a->numeric_constant_value(&anc)
3287 || !anc.to_int(&aval)
3288 || !b->numeric_constant_value(&bnc)
3289 || !bnc.to_int(&bval))
3290 go_unreachable();
3291 bool ret = mpz_cmp(aval, bval) == 0;
3292 mpz_clear(aval);
3293 mpz_clear(bval);
3294 return ret;
3295 }
3296
3297 // Class Case_clauses::Case_clause.
3298
3299 // Traversal.
3300
3301 int
traverse(Traverse * traverse)3302 Case_clauses::Case_clause::traverse(Traverse* traverse)
3303 {
3304 if (this->cases_ != NULL
3305 && (traverse->traverse_mask()
3306 & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0)
3307 {
3308 if (this->cases_->traverse(traverse) == TRAVERSE_EXIT)
3309 return TRAVERSE_EXIT;
3310 }
3311 if (this->statements_ != NULL)
3312 {
3313 if (this->statements_->traverse(traverse) == TRAVERSE_EXIT)
3314 return TRAVERSE_EXIT;
3315 }
3316 return TRAVERSE_CONTINUE;
3317 }
3318
3319 // Check whether all the case expressions are integer constants.
3320
3321 bool
is_constant() const3322 Case_clauses::Case_clause::is_constant() const
3323 {
3324 if (this->cases_ != NULL)
3325 {
3326 for (Expression_list::const_iterator p = this->cases_->begin();
3327 p != this->cases_->end();
3328 ++p)
3329 if (!(*p)->is_constant() || (*p)->type()->integer_type() == NULL)
3330 return false;
3331 }
3332 return true;
3333 }
3334
3335 // Lower a case clause for a nonconstant switch. VAL_TEMP is the
3336 // value we are switching on; it may be NULL. If START_LABEL is not
3337 // NULL, it goes at the start of the statements, after the condition
3338 // test. We branch to FINISH_LABEL at the end of the statements.
3339
3340 void
lower(Block * b,Temporary_statement * val_temp,Unnamed_label * start_label,Unnamed_label * finish_label) const3341 Case_clauses::Case_clause::lower(Block* b, Temporary_statement* val_temp,
3342 Unnamed_label* start_label,
3343 Unnamed_label* finish_label) const
3344 {
3345 Location loc = this->location_;
3346 Unnamed_label* next_case_label;
3347 if (this->cases_ == NULL || this->cases_->empty())
3348 {
3349 go_assert(this->is_default_);
3350 next_case_label = NULL;
3351 }
3352 else
3353 {
3354 Expression* cond = NULL;
3355
3356 for (Expression_list::const_iterator p = this->cases_->begin();
3357 p != this->cases_->end();
3358 ++p)
3359 {
3360 Expression* ref = Expression::make_temporary_reference(val_temp,
3361 loc);
3362 Expression* this_cond = Expression::make_binary(OPERATOR_EQEQ, ref,
3363 *p, loc);
3364 if (cond == NULL)
3365 cond = this_cond;
3366 else
3367 cond = Expression::make_binary(OPERATOR_OROR, cond, this_cond, loc);
3368 }
3369
3370 Block* then_block = new Block(b, loc);
3371 next_case_label = new Unnamed_label(Linemap::unknown_location());
3372 Statement* s = Statement::make_goto_unnamed_statement(next_case_label,
3373 loc);
3374 then_block->add_statement(s);
3375
3376 // if !COND { goto NEXT_CASE_LABEL }
3377 cond = Expression::make_unary(OPERATOR_NOT, cond, loc);
3378 s = Statement::make_if_statement(cond, then_block, NULL, loc);
3379 b->add_statement(s);
3380 }
3381
3382 if (start_label != NULL)
3383 b->add_statement(Statement::make_unnamed_label_statement(start_label));
3384
3385 if (this->statements_ != NULL)
3386 b->add_statement(Statement::make_block_statement(this->statements_, loc));
3387
3388 Statement* s = Statement::make_goto_unnamed_statement(finish_label, loc);
3389 b->add_statement(s);
3390
3391 if (next_case_label != NULL)
3392 b->add_statement(Statement::make_unnamed_label_statement(next_case_label));
3393 }
3394
3395 // Determine types.
3396
3397 void
determine_types(Type * type)3398 Case_clauses::Case_clause::determine_types(Type* type)
3399 {
3400 if (this->cases_ != NULL)
3401 {
3402 Type_context case_context(type, false);
3403 for (Expression_list::iterator p = this->cases_->begin();
3404 p != this->cases_->end();
3405 ++p)
3406 (*p)->determine_type(&case_context);
3407 }
3408 if (this->statements_ != NULL)
3409 this->statements_->determine_types();
3410 }
3411
3412 // Check types. Returns false if there was an error.
3413
3414 bool
check_types(Type * type)3415 Case_clauses::Case_clause::check_types(Type* type)
3416 {
3417 if (this->cases_ != NULL)
3418 {
3419 for (Expression_list::iterator p = this->cases_->begin();
3420 p != this->cases_->end();
3421 ++p)
3422 {
3423 if (!Type::are_assignable(type, (*p)->type(), NULL)
3424 && !Type::are_assignable((*p)->type(), type, NULL))
3425 {
3426 error_at((*p)->location(),
3427 "type mismatch between switch value and case clause");
3428 return false;
3429 }
3430 }
3431 }
3432 return true;
3433 }
3434
3435 // Return true if this clause may fall through to the following
3436 // statements. Note that this is not the same as whether the case
3437 // uses the "fallthrough" keyword.
3438
3439 bool
may_fall_through() const3440 Case_clauses::Case_clause::may_fall_through() const
3441 {
3442 if (this->statements_ == NULL)
3443 return true;
3444 return this->statements_->may_fall_through();
3445 }
3446
3447 // Convert the case values and statements to the backend
3448 // representation. BREAK_LABEL is the label which break statements
3449 // should branch to. CASE_CONSTANTS is used to detect duplicate
3450 // constants. *CASES should be passed as an empty vector; the values
3451 // for this case will be added to it. If this is the default case,
3452 // *CASES will remain empty. This returns the statement to execute if
3453 // one of these cases is selected.
3454
3455 Bstatement*
get_backend(Translate_context * context,Unnamed_label * break_label,Case_constants * case_constants,std::vector<Bexpression * > * cases) const3456 Case_clauses::Case_clause::get_backend(Translate_context* context,
3457 Unnamed_label* break_label,
3458 Case_constants* case_constants,
3459 std::vector<Bexpression*>* cases) const
3460 {
3461 if (this->cases_ != NULL)
3462 {
3463 go_assert(!this->is_default_);
3464 for (Expression_list::const_iterator p = this->cases_->begin();
3465 p != this->cases_->end();
3466 ++p)
3467 {
3468 Expression* e = *p;
3469 if (e->classification() != Expression::EXPRESSION_INTEGER)
3470 {
3471 Numeric_constant nc;
3472 mpz_t ival;
3473 if (!(*p)->numeric_constant_value(&nc) || !nc.to_int(&ival))
3474 {
3475 // Something went wrong. This can happen with a
3476 // negative constant and an unsigned switch value.
3477 go_assert(saw_errors());
3478 continue;
3479 }
3480 go_assert(nc.type() != NULL);
3481 e = Expression::make_integer(&ival, nc.type(), e->location());
3482 mpz_clear(ival);
3483 }
3484
3485 std::pair<Case_constants::iterator, bool> ins =
3486 case_constants->insert(e);
3487 if (!ins.second)
3488 {
3489 // Value was already present.
3490 error_at(this->location_, "duplicate case in switch");
3491 e = Expression::make_error(this->location_);
3492 }
3493
3494 tree case_tree = e->get_tree(context);
3495 Bexpression* case_expr = tree_to_expr(case_tree);
3496 cases->push_back(case_expr);
3497 }
3498 }
3499
3500 Bstatement* statements;
3501 if (this->statements_ == NULL)
3502 statements = NULL;
3503 else
3504 {
3505 Bblock* bblock = this->statements_->get_backend(context);
3506 statements = context->backend()->block_statement(bblock);
3507 }
3508
3509 Bstatement* break_stat;
3510 if (this->is_fallthrough_)
3511 break_stat = NULL;
3512 else
3513 break_stat = break_label->get_goto(context, this->location_);
3514
3515 if (statements == NULL)
3516 return break_stat;
3517 else if (break_stat == NULL)
3518 return statements;
3519 else
3520 return context->backend()->compound_statement(statements, break_stat);
3521 }
3522
3523 // Dump the AST representation for a case clause
3524
3525 void
dump_clause(Ast_dump_context * ast_dump_context) const3526 Case_clauses::Case_clause::dump_clause(Ast_dump_context* ast_dump_context)
3527 const
3528 {
3529 ast_dump_context->print_indent();
3530 if (this->is_default_)
3531 {
3532 ast_dump_context->ostream() << "default:";
3533 }
3534 else
3535 {
3536 ast_dump_context->ostream() << "case ";
3537 ast_dump_context->dump_expression_list(this->cases_);
3538 ast_dump_context->ostream() << ":" ;
3539 }
3540 ast_dump_context->dump_block(this->statements_);
3541 if (this->is_fallthrough_)
3542 {
3543 ast_dump_context->print_indent();
3544 ast_dump_context->ostream() << " (fallthrough)" << std::endl;
3545 }
3546 }
3547
3548 // Class Case_clauses.
3549
3550 // Traversal.
3551
3552 int
traverse(Traverse * traverse)3553 Case_clauses::traverse(Traverse* traverse)
3554 {
3555 for (Clauses::iterator p = this->clauses_.begin();
3556 p != this->clauses_.end();
3557 ++p)
3558 {
3559 if (p->traverse(traverse) == TRAVERSE_EXIT)
3560 return TRAVERSE_EXIT;
3561 }
3562 return TRAVERSE_CONTINUE;
3563 }
3564
3565 // Check whether all the case expressions are constant.
3566
3567 bool
is_constant() const3568 Case_clauses::is_constant() const
3569 {
3570 for (Clauses::const_iterator p = this->clauses_.begin();
3571 p != this->clauses_.end();
3572 ++p)
3573 if (!p->is_constant())
3574 return false;
3575 return true;
3576 }
3577
3578 // Lower case clauses for a nonconstant switch.
3579
3580 void
lower(Block * b,Temporary_statement * val_temp,Unnamed_label * break_label) const3581 Case_clauses::lower(Block* b, Temporary_statement* val_temp,
3582 Unnamed_label* break_label) const
3583 {
3584 // The default case.
3585 const Case_clause* default_case = NULL;
3586
3587 // The label for the fallthrough of the previous case.
3588 Unnamed_label* last_fallthrough_label = NULL;
3589
3590 // The label for the start of the default case. This is used if the
3591 // case before the default case falls through.
3592 Unnamed_label* default_start_label = NULL;
3593
3594 // The label for the end of the default case. This normally winds
3595 // up as BREAK_LABEL, but it will be different if the default case
3596 // falls through.
3597 Unnamed_label* default_finish_label = NULL;
3598
3599 for (Clauses::const_iterator p = this->clauses_.begin();
3600 p != this->clauses_.end();
3601 ++p)
3602 {
3603 // The label to use for the start of the statements for this
3604 // case. This is NULL unless the previous case falls through.
3605 Unnamed_label* start_label = last_fallthrough_label;
3606
3607 // The label to jump to after the end of the statements for this
3608 // case.
3609 Unnamed_label* finish_label = break_label;
3610
3611 last_fallthrough_label = NULL;
3612 if (p->is_fallthrough() && p + 1 != this->clauses_.end())
3613 {
3614 finish_label = new Unnamed_label(p->location());
3615 last_fallthrough_label = finish_label;
3616 }
3617
3618 if (!p->is_default())
3619 p->lower(b, val_temp, start_label, finish_label);
3620 else
3621 {
3622 // We have to move the default case to the end, so that we
3623 // only use it if all the other tests fail.
3624 default_case = &*p;
3625 default_start_label = start_label;
3626 default_finish_label = finish_label;
3627 }
3628 }
3629
3630 if (default_case != NULL)
3631 default_case->lower(b, val_temp, default_start_label,
3632 default_finish_label);
3633 }
3634
3635 // Determine types.
3636
3637 void
determine_types(Type * type)3638 Case_clauses::determine_types(Type* type)
3639 {
3640 for (Clauses::iterator p = this->clauses_.begin();
3641 p != this->clauses_.end();
3642 ++p)
3643 p->determine_types(type);
3644 }
3645
3646 // Check types. Returns false if there was an error.
3647
3648 bool
check_types(Type * type)3649 Case_clauses::check_types(Type* type)
3650 {
3651 bool ret = true;
3652 for (Clauses::iterator p = this->clauses_.begin();
3653 p != this->clauses_.end();
3654 ++p)
3655 {
3656 if (!p->check_types(type))
3657 ret = false;
3658 }
3659 return ret;
3660 }
3661
3662 // Return true if these clauses may fall through to the statements
3663 // following the switch statement.
3664
3665 bool
may_fall_through() const3666 Case_clauses::may_fall_through() const
3667 {
3668 bool found_default = false;
3669 for (Clauses::const_iterator p = this->clauses_.begin();
3670 p != this->clauses_.end();
3671 ++p)
3672 {
3673 if (p->may_fall_through() && !p->is_fallthrough())
3674 return true;
3675 if (p->is_default())
3676 found_default = true;
3677 }
3678 return !found_default;
3679 }
3680
3681 // Convert the cases to the backend representation. This sets
3682 // *ALL_CASES and *ALL_STATEMENTS.
3683
3684 void
get_backend(Translate_context * context,Unnamed_label * break_label,std::vector<std::vector<Bexpression * >> * all_cases,std::vector<Bstatement * > * all_statements) const3685 Case_clauses::get_backend(Translate_context* context,
3686 Unnamed_label* break_label,
3687 std::vector<std::vector<Bexpression*> >* all_cases,
3688 std::vector<Bstatement*>* all_statements) const
3689 {
3690 Case_constants case_constants;
3691
3692 size_t c = this->clauses_.size();
3693 all_cases->resize(c);
3694 all_statements->resize(c);
3695
3696 size_t i = 0;
3697 for (Clauses::const_iterator p = this->clauses_.begin();
3698 p != this->clauses_.end();
3699 ++p, ++i)
3700 {
3701 std::vector<Bexpression*> cases;
3702 Bstatement* stat = p->get_backend(context, break_label, &case_constants,
3703 &cases);
3704 (*all_cases)[i].swap(cases);
3705 (*all_statements)[i] = stat;
3706 }
3707 }
3708
3709 // Dump the AST representation for case clauses (from a switch statement)
3710
3711 void
dump_clauses(Ast_dump_context * ast_dump_context) const3712 Case_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
3713 {
3714 for (Clauses::const_iterator p = this->clauses_.begin();
3715 p != this->clauses_.end();
3716 ++p)
3717 p->dump_clause(ast_dump_context);
3718 }
3719
3720 // A constant switch statement. A Switch_statement is lowered to this
3721 // when all the cases are constants.
3722
3723 class Constant_switch_statement : public Statement
3724 {
3725 public:
Constant_switch_statement(Expression * val,Case_clauses * clauses,Unnamed_label * break_label,Location location)3726 Constant_switch_statement(Expression* val, Case_clauses* clauses,
3727 Unnamed_label* break_label,
3728 Location location)
3729 : Statement(STATEMENT_CONSTANT_SWITCH, location),
3730 val_(val), clauses_(clauses), break_label_(break_label)
3731 { }
3732
3733 protected:
3734 int
3735 do_traverse(Traverse*);
3736
3737 void
3738 do_determine_types();
3739
3740 void
3741 do_check_types(Gogo*);
3742
3743 Bstatement*
3744 do_get_backend(Translate_context*);
3745
3746 void
3747 do_dump_statement(Ast_dump_context*) const;
3748
3749 private:
3750 // The value to switch on.
3751 Expression* val_;
3752 // The case clauses.
3753 Case_clauses* clauses_;
3754 // The break label, if needed.
3755 Unnamed_label* break_label_;
3756 };
3757
3758 // Traversal.
3759
3760 int
do_traverse(Traverse * traverse)3761 Constant_switch_statement::do_traverse(Traverse* traverse)
3762 {
3763 if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT)
3764 return TRAVERSE_EXIT;
3765 return this->clauses_->traverse(traverse);
3766 }
3767
3768 // Determine types.
3769
3770 void
do_determine_types()3771 Constant_switch_statement::do_determine_types()
3772 {
3773 this->val_->determine_type_no_context();
3774 this->clauses_->determine_types(this->val_->type());
3775 }
3776
3777 // Check types.
3778
3779 void
do_check_types(Gogo *)3780 Constant_switch_statement::do_check_types(Gogo*)
3781 {
3782 if (!this->clauses_->check_types(this->val_->type()))
3783 this->set_is_error();
3784 }
3785
3786 // Convert to GENERIC.
3787
3788 Bstatement*
do_get_backend(Translate_context * context)3789 Constant_switch_statement::do_get_backend(Translate_context* context)
3790 {
3791 tree switch_val_tree = this->val_->get_tree(context);
3792 Bexpression* switch_val_expr = tree_to_expr(switch_val_tree);
3793
3794 Unnamed_label* break_label = this->break_label_;
3795 if (break_label == NULL)
3796 break_label = new Unnamed_label(this->location());
3797
3798 std::vector<std::vector<Bexpression*> > all_cases;
3799 std::vector<Bstatement*> all_statements;
3800 this->clauses_->get_backend(context, break_label, &all_cases,
3801 &all_statements);
3802
3803 Bstatement* switch_statement;
3804 switch_statement = context->backend()->switch_statement(switch_val_expr,
3805 all_cases,
3806 all_statements,
3807 this->location());
3808 Bstatement* ldef = break_label->get_definition(context);
3809 return context->backend()->compound_statement(switch_statement, ldef);
3810 }
3811
3812 // Dump the AST representation for a constant switch statement.
3813
3814 void
do_dump_statement(Ast_dump_context * ast_dump_context) const3815 Constant_switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
3816 const
3817 {
3818 ast_dump_context->print_indent();
3819 ast_dump_context->ostream() << "switch ";
3820 ast_dump_context->dump_expression(this->val_);
3821
3822 if (ast_dump_context->dump_subblocks())
3823 {
3824 ast_dump_context->ostream() << " {" << std::endl;
3825 this->clauses_->dump_clauses(ast_dump_context);
3826 ast_dump_context->ostream() << "}";
3827 }
3828
3829 ast_dump_context->ostream() << std::endl;
3830 }
3831
3832 // Class Switch_statement.
3833
3834 // Traversal.
3835
3836 int
do_traverse(Traverse * traverse)3837 Switch_statement::do_traverse(Traverse* traverse)
3838 {
3839 if (this->val_ != NULL)
3840 {
3841 if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT)
3842 return TRAVERSE_EXIT;
3843 }
3844 return this->clauses_->traverse(traverse);
3845 }
3846
3847 // Lower a Switch_statement to a Constant_switch_statement or a series
3848 // of if statements.
3849
3850 Statement*
do_lower(Gogo *,Named_object *,Block * enclosing,Statement_inserter *)3851 Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
3852 Statement_inserter*)
3853 {
3854 Location loc = this->location();
3855
3856 if (this->val_ != NULL
3857 && (this->val_->is_error_expression()
3858 || this->val_->type()->is_error()))
3859 return Statement::make_error_statement(loc);
3860
3861 if (this->val_ != NULL
3862 && this->val_->type()->integer_type() != NULL
3863 && !this->clauses_->empty()
3864 && this->clauses_->is_constant())
3865 return new Constant_switch_statement(this->val_, this->clauses_,
3866 this->break_label_, loc);
3867
3868 if (this->val_ != NULL
3869 && !this->val_->type()->is_comparable()
3870 && !Type::are_compatible_for_comparison(true, this->val_->type(),
3871 Type::make_nil_type(), NULL))
3872 {
3873 error_at(this->val_->location(),
3874 "cannot switch on value whose type that may not be compared");
3875 return Statement::make_error_statement(loc);
3876 }
3877
3878 Block* b = new Block(enclosing, loc);
3879
3880 if (this->clauses_->empty())
3881 {
3882 Expression* val = this->val_;
3883 if (val == NULL)
3884 val = Expression::make_boolean(true, loc);
3885 return Statement::make_statement(val, true);
3886 }
3887
3888 // var val_temp VAL_TYPE = VAL
3889 Expression* val = this->val_;
3890 if (val == NULL)
3891 val = Expression::make_boolean(true, loc);
3892 Temporary_statement* val_temp = Statement::make_temporary(NULL, val, loc);
3893 b->add_statement(val_temp);
3894
3895 this->clauses_->lower(b, val_temp, this->break_label());
3896
3897 Statement* s = Statement::make_unnamed_label_statement(this->break_label_);
3898 b->add_statement(s);
3899
3900 return Statement::make_block_statement(b, loc);
3901 }
3902
3903 // Return the break label for this switch statement, creating it if
3904 // necessary.
3905
3906 Unnamed_label*
break_label()3907 Switch_statement::break_label()
3908 {
3909 if (this->break_label_ == NULL)
3910 this->break_label_ = new Unnamed_label(this->location());
3911 return this->break_label_;
3912 }
3913
3914 // Dump the AST representation for a switch statement.
3915
3916 void
do_dump_statement(Ast_dump_context * ast_dump_context) const3917 Switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3918 {
3919 ast_dump_context->print_indent();
3920 ast_dump_context->ostream() << "switch ";
3921 if (this->val_ != NULL)
3922 {
3923 ast_dump_context->dump_expression(this->val_);
3924 }
3925 if (ast_dump_context->dump_subblocks())
3926 {
3927 ast_dump_context->ostream() << " {" << std::endl;
3928 this->clauses_->dump_clauses(ast_dump_context);
3929 ast_dump_context->print_indent();
3930 ast_dump_context->ostream() << "}";
3931 }
3932 ast_dump_context->ostream() << std::endl;
3933 }
3934
3935 // Return whether this switch may fall through.
3936
3937 bool
do_may_fall_through() const3938 Switch_statement::do_may_fall_through() const
3939 {
3940 if (this->clauses_ == NULL)
3941 return true;
3942
3943 // If we have a break label, then some case needed it. That implies
3944 // that the switch statement as a whole can fall through.
3945 if (this->break_label_ != NULL)
3946 return true;
3947
3948 return this->clauses_->may_fall_through();
3949 }
3950
3951 // Make a switch statement.
3952
3953 Switch_statement*
make_switch_statement(Expression * val,Location location)3954 Statement::make_switch_statement(Expression* val, Location location)
3955 {
3956 return new Switch_statement(val, location);
3957 }
3958
3959 // Class Type_case_clauses::Type_case_clause.
3960
3961 // Traversal.
3962
3963 int
traverse(Traverse * traverse)3964 Type_case_clauses::Type_case_clause::traverse(Traverse* traverse)
3965 {
3966 if (!this->is_default_
3967 && ((traverse->traverse_mask()
3968 & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0)
3969 && Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
3970 return TRAVERSE_EXIT;
3971 if (this->statements_ != NULL)
3972 return this->statements_->traverse(traverse);
3973 return TRAVERSE_CONTINUE;
3974 }
3975
3976 // Lower one clause in a type switch. Add statements to the block B.
3977 // The type descriptor we are switching on is in DESCRIPTOR_TEMP.
3978 // BREAK_LABEL is the label at the end of the type switch.
3979 // *STMTS_LABEL, if not NULL, is a label to put at the start of the
3980 // statements.
3981
3982 void
lower(Type * switch_val_type,Block * b,Temporary_statement * descriptor_temp,Unnamed_label * break_label,Unnamed_label ** stmts_label) const3983 Type_case_clauses::Type_case_clause::lower(Type* switch_val_type,
3984 Block* b,
3985 Temporary_statement* descriptor_temp,
3986 Unnamed_label* break_label,
3987 Unnamed_label** stmts_label) const
3988 {
3989 Location loc = this->location_;
3990
3991 Unnamed_label* next_case_label = NULL;
3992 if (!this->is_default_)
3993 {
3994 Type* type = this->type_;
3995
3996 std::string reason;
3997 if (switch_val_type->interface_type() != NULL
3998 && !type->is_nil_constant_as_type()
3999 && type->interface_type() == NULL
4000 && !switch_val_type->interface_type()->implements_interface(type,
4001 &reason))
4002 {
4003 if (reason.empty())
4004 error_at(this->location_, "impossible type switch case");
4005 else
4006 error_at(this->location_, "impossible type switch case (%s)",
4007 reason.c_str());
4008 }
4009
4010 Expression* ref = Expression::make_temporary_reference(descriptor_temp,
4011 loc);
4012
4013 Expression* cond;
4014 // The language permits case nil, which is of course a constant
4015 // rather than a type. It will appear here as an invalid
4016 // forwarding type.
4017 if (type->is_nil_constant_as_type())
4018 cond = Expression::make_binary(OPERATOR_EQEQ, ref,
4019 Expression::make_nil(loc),
4020 loc);
4021 else
4022 cond = Runtime::make_call((type->interface_type() == NULL
4023 ? Runtime::IFACETYPEEQ
4024 : Runtime::IFACEI2TP),
4025 loc, 2,
4026 Expression::make_type_descriptor(type, loc),
4027 ref);
4028
4029 Unnamed_label* dest;
4030 if (!this->is_fallthrough_)
4031 {
4032 // if !COND { goto NEXT_CASE_LABEL }
4033 next_case_label = new Unnamed_label(Linemap::unknown_location());
4034 dest = next_case_label;
4035 cond = Expression::make_unary(OPERATOR_NOT, cond, loc);
4036 }
4037 else
4038 {
4039 // if COND { goto STMTS_LABEL }
4040 go_assert(stmts_label != NULL);
4041 if (*stmts_label == NULL)
4042 *stmts_label = new Unnamed_label(Linemap::unknown_location());
4043 dest = *stmts_label;
4044 }
4045 Block* then_block = new Block(b, loc);
4046 Statement* s = Statement::make_goto_unnamed_statement(dest, loc);
4047 then_block->add_statement(s);
4048 s = Statement::make_if_statement(cond, then_block, NULL, loc);
4049 b->add_statement(s);
4050 }
4051
4052 if (this->statements_ != NULL
4053 || (!this->is_fallthrough_
4054 && stmts_label != NULL
4055 && *stmts_label != NULL))
4056 {
4057 go_assert(!this->is_fallthrough_);
4058 if (stmts_label != NULL && *stmts_label != NULL)
4059 {
4060 go_assert(!this->is_default_);
4061 if (this->statements_ != NULL)
4062 (*stmts_label)->set_location(this->statements_->start_location());
4063 Statement* s = Statement::make_unnamed_label_statement(*stmts_label);
4064 b->add_statement(s);
4065 *stmts_label = NULL;
4066 }
4067 if (this->statements_ != NULL)
4068 b->add_statement(Statement::make_block_statement(this->statements_,
4069 loc));
4070 }
4071
4072 if (this->is_fallthrough_)
4073 go_assert(next_case_label == NULL);
4074 else
4075 {
4076 Location gloc = (this->statements_ == NULL
4077 ? loc
4078 : this->statements_->end_location());
4079 b->add_statement(Statement::make_goto_unnamed_statement(break_label,
4080 gloc));
4081 if (next_case_label != NULL)
4082 {
4083 Statement* s =
4084 Statement::make_unnamed_label_statement(next_case_label);
4085 b->add_statement(s);
4086 }
4087 }
4088 }
4089
4090 // Return true if this type clause may fall through to the statements
4091 // following the switch.
4092
4093 bool
may_fall_through() const4094 Type_case_clauses::Type_case_clause::may_fall_through() const
4095 {
4096 if (this->is_fallthrough_)
4097 {
4098 // This case means that we automatically fall through to the
4099 // next case (it's used for T1 in case T1, T2:). It does not
4100 // mean that we fall through to the end of the type switch as a
4101 // whole. There is sure to be a next case and that next case
4102 // will determine whether we fall through to the statements
4103 // after the type switch.
4104 return false;
4105 }
4106 if (this->statements_ == NULL)
4107 return true;
4108 return this->statements_->may_fall_through();
4109 }
4110
4111 // Dump the AST representation for a type case clause
4112
4113 void
dump_clause(Ast_dump_context * ast_dump_context) const4114 Type_case_clauses::Type_case_clause::dump_clause(
4115 Ast_dump_context* ast_dump_context) const
4116 {
4117 ast_dump_context->print_indent();
4118 if (this->is_default_)
4119 {
4120 ast_dump_context->ostream() << "default:";
4121 }
4122 else
4123 {
4124 ast_dump_context->ostream() << "case ";
4125 ast_dump_context->dump_type(this->type_);
4126 ast_dump_context->ostream() << ":" ;
4127 }
4128 ast_dump_context->dump_block(this->statements_);
4129 if (this->is_fallthrough_)
4130 {
4131 ast_dump_context->print_indent();
4132 ast_dump_context->ostream() << " (fallthrough)" << std::endl;
4133 }
4134 }
4135
4136 // Class Type_case_clauses.
4137
4138 // Traversal.
4139
4140 int
traverse(Traverse * traverse)4141 Type_case_clauses::traverse(Traverse* traverse)
4142 {
4143 for (Type_clauses::iterator p = this->clauses_.begin();
4144 p != this->clauses_.end();
4145 ++p)
4146 {
4147 if (p->traverse(traverse) == TRAVERSE_EXIT)
4148 return TRAVERSE_EXIT;
4149 }
4150 return TRAVERSE_CONTINUE;
4151 }
4152
4153 // Check for duplicate types.
4154
4155 void
check_duplicates() const4156 Type_case_clauses::check_duplicates() const
4157 {
4158 typedef Unordered_set_hash(const Type*, Type_hash_identical,
4159 Type_identical) Types_seen;
4160 Types_seen types_seen;
4161 for (Type_clauses::const_iterator p = this->clauses_.begin();
4162 p != this->clauses_.end();
4163 ++p)
4164 {
4165 Type* t = p->type();
4166 if (t == NULL)
4167 continue;
4168 if (t->is_nil_constant_as_type())
4169 t = Type::make_nil_type();
4170 std::pair<Types_seen::iterator, bool> ins = types_seen.insert(t);
4171 if (!ins.second)
4172 error_at(p->location(), "duplicate type in switch");
4173 }
4174 }
4175
4176 // Lower the clauses in a type switch. Add statements to the block B.
4177 // The type descriptor we are switching on is in DESCRIPTOR_TEMP.
4178 // BREAK_LABEL is the label at the end of the type switch.
4179
4180 void
lower(Type * switch_val_type,Block * b,Temporary_statement * descriptor_temp,Unnamed_label * break_label) const4181 Type_case_clauses::lower(Type* switch_val_type, Block* b,
4182 Temporary_statement* descriptor_temp,
4183 Unnamed_label* break_label) const
4184 {
4185 const Type_case_clause* default_case = NULL;
4186
4187 Unnamed_label* stmts_label = NULL;
4188 for (Type_clauses::const_iterator p = this->clauses_.begin();
4189 p != this->clauses_.end();
4190 ++p)
4191 {
4192 if (!p->is_default())
4193 p->lower(switch_val_type, b, descriptor_temp, break_label,
4194 &stmts_label);
4195 else
4196 {
4197 // We are generating a series of tests, which means that we
4198 // need to move the default case to the end.
4199 default_case = &*p;
4200 }
4201 }
4202 go_assert(stmts_label == NULL);
4203
4204 if (default_case != NULL)
4205 default_case->lower(switch_val_type, b, descriptor_temp, break_label,
4206 NULL);
4207 }
4208
4209 // Return true if these clauses may fall through to the statements
4210 // following the switch statement.
4211
4212 bool
may_fall_through() const4213 Type_case_clauses::may_fall_through() const
4214 {
4215 bool found_default = false;
4216 for (Type_clauses::const_iterator p = this->clauses_.begin();
4217 p != this->clauses_.end();
4218 ++p)
4219 {
4220 if (p->may_fall_through())
4221 return true;
4222 if (p->is_default())
4223 found_default = true;
4224 }
4225 return !found_default;
4226 }
4227
4228 // Dump the AST representation for case clauses (from a switch statement)
4229
4230 void
dump_clauses(Ast_dump_context * ast_dump_context) const4231 Type_case_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
4232 {
4233 for (Type_clauses::const_iterator p = this->clauses_.begin();
4234 p != this->clauses_.end();
4235 ++p)
4236 p->dump_clause(ast_dump_context);
4237 }
4238
4239 // Class Type_switch_statement.
4240
4241 // Traversal.
4242
4243 int
do_traverse(Traverse * traverse)4244 Type_switch_statement::do_traverse(Traverse* traverse)
4245 {
4246 if (this->var_ == NULL)
4247 {
4248 if (this->traverse_expression(traverse, &this->expr_) == TRAVERSE_EXIT)
4249 return TRAVERSE_EXIT;
4250 }
4251 if (this->clauses_ != NULL)
4252 return this->clauses_->traverse(traverse);
4253 return TRAVERSE_CONTINUE;
4254 }
4255
4256 // Lower a type switch statement to a series of if statements. The gc
4257 // compiler is able to generate a table in some cases. However, that
4258 // does not work for us because we may have type descriptors in
4259 // different shared libraries, so we can't compare them with simple
4260 // equality testing.
4261
4262 Statement*
do_lower(Gogo *,Named_object *,Block * enclosing,Statement_inserter *)4263 Type_switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
4264 Statement_inserter*)
4265 {
4266 const Location loc = this->location();
4267
4268 if (this->clauses_ != NULL)
4269 this->clauses_->check_duplicates();
4270
4271 Block* b = new Block(enclosing, loc);
4272
4273 Type* val_type = (this->var_ != NULL
4274 ? this->var_->var_value()->type()
4275 : this->expr_->type());
4276
4277 if (val_type->interface_type() == NULL)
4278 {
4279 if (!val_type->is_error())
4280 this->report_error(_("cannot type switch on non-interface value"));
4281 return Statement::make_error_statement(loc);
4282 }
4283
4284 // var descriptor_temp DESCRIPTOR_TYPE
4285 Type* descriptor_type = Type::make_type_descriptor_ptr_type();
4286 Temporary_statement* descriptor_temp =
4287 Statement::make_temporary(descriptor_type, NULL, loc);
4288 b->add_statement(descriptor_temp);
4289
4290 // descriptor_temp = ifacetype(val_temp) FIXME: This should be
4291 // inlined.
4292 bool is_empty = val_type->interface_type()->is_empty();
4293 Expression* ref;
4294 if (this->var_ == NULL)
4295 ref = this->expr_;
4296 else
4297 ref = Expression::make_var_reference(this->var_, loc);
4298 Expression* call = Runtime::make_call((is_empty
4299 ? Runtime::EFACETYPE
4300 : Runtime::IFACETYPE),
4301 loc, 1, ref);
4302 Temporary_reference_expression* lhs =
4303 Expression::make_temporary_reference(descriptor_temp, loc);
4304 lhs->set_is_lvalue();
4305 Statement* s = Statement::make_assignment(lhs, call, loc);
4306 b->add_statement(s);
4307
4308 if (this->clauses_ != NULL)
4309 this->clauses_->lower(val_type, b, descriptor_temp, this->break_label());
4310
4311 s = Statement::make_unnamed_label_statement(this->break_label_);
4312 b->add_statement(s);
4313
4314 return Statement::make_block_statement(b, loc);
4315 }
4316
4317 // Return whether this switch may fall through.
4318
4319 bool
do_may_fall_through() const4320 Type_switch_statement::do_may_fall_through() const
4321 {
4322 if (this->clauses_ == NULL)
4323 return true;
4324
4325 // If we have a break label, then some case needed it. That implies
4326 // that the switch statement as a whole can fall through.
4327 if (this->break_label_ != NULL)
4328 return true;
4329
4330 return this->clauses_->may_fall_through();
4331 }
4332
4333 // Return the break label for this type switch statement, creating it
4334 // if necessary.
4335
4336 Unnamed_label*
break_label()4337 Type_switch_statement::break_label()
4338 {
4339 if (this->break_label_ == NULL)
4340 this->break_label_ = new Unnamed_label(this->location());
4341 return this->break_label_;
4342 }
4343
4344 // Dump the AST representation for a type switch statement
4345
4346 void
do_dump_statement(Ast_dump_context * ast_dump_context) const4347 Type_switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
4348 const
4349 {
4350 ast_dump_context->print_indent();
4351 ast_dump_context->ostream() << "switch " << this->var_->name() << " = ";
4352 ast_dump_context->dump_expression(this->expr_);
4353 ast_dump_context->ostream() << " .(type)";
4354 if (ast_dump_context->dump_subblocks())
4355 {
4356 ast_dump_context->ostream() << " {" << std::endl;
4357 this->clauses_->dump_clauses(ast_dump_context);
4358 ast_dump_context->ostream() << "}";
4359 }
4360 ast_dump_context->ostream() << std::endl;
4361 }
4362
4363 // Make a type switch statement.
4364
4365 Type_switch_statement*
make_type_switch_statement(Named_object * var,Expression * expr,Location location)4366 Statement::make_type_switch_statement(Named_object* var, Expression* expr,
4367 Location location)
4368 {
4369 return new Type_switch_statement(var, expr, location);
4370 }
4371
4372 // Class Send_statement.
4373
4374 // Traversal.
4375
4376 int
do_traverse(Traverse * traverse)4377 Send_statement::do_traverse(Traverse* traverse)
4378 {
4379 if (this->traverse_expression(traverse, &this->channel_) == TRAVERSE_EXIT)
4380 return TRAVERSE_EXIT;
4381 return this->traverse_expression(traverse, &this->val_);
4382 }
4383
4384 // Determine types.
4385
4386 void
do_determine_types()4387 Send_statement::do_determine_types()
4388 {
4389 this->channel_->determine_type_no_context();
4390 Type* type = this->channel_->type();
4391 Type_context context;
4392 if (type->channel_type() != NULL)
4393 context.type = type->channel_type()->element_type();
4394 this->val_->determine_type(&context);
4395 }
4396
4397 // Check types.
4398
4399 void
do_check_types(Gogo *)4400 Send_statement::do_check_types(Gogo*)
4401 {
4402 Type* type = this->channel_->type();
4403 if (type->is_error())
4404 {
4405 this->set_is_error();
4406 return;
4407 }
4408 Channel_type* channel_type = type->channel_type();
4409 if (channel_type == NULL)
4410 {
4411 error_at(this->location(), "left operand of %<<-%> must be channel");
4412 this->set_is_error();
4413 return;
4414 }
4415 Type* element_type = channel_type->element_type();
4416 if (!Type::are_assignable(element_type, this->val_->type(), NULL))
4417 {
4418 this->report_error(_("incompatible types in send"));
4419 return;
4420 }
4421 if (!channel_type->may_send())
4422 {
4423 this->report_error(_("invalid send on receive-only channel"));
4424 return;
4425 }
4426 }
4427
4428 // Convert a send statement to the backend representation.
4429
4430 Bstatement*
do_get_backend(Translate_context * context)4431 Send_statement::do_get_backend(Translate_context* context)
4432 {
4433 Location loc = this->location();
4434
4435 Channel_type* channel_type = this->channel_->type()->channel_type();
4436 Type* element_type = channel_type->element_type();
4437 Expression* val = Expression::make_cast(element_type, this->val_, loc);
4438
4439 bool is_small;
4440 bool can_take_address;
4441 switch (element_type->base()->classification())
4442 {
4443 case Type::TYPE_BOOLEAN:
4444 case Type::TYPE_INTEGER:
4445 case Type::TYPE_FUNCTION:
4446 case Type::TYPE_POINTER:
4447 case Type::TYPE_MAP:
4448 case Type::TYPE_CHANNEL:
4449 is_small = true;
4450 can_take_address = false;
4451 break;
4452
4453 case Type::TYPE_FLOAT:
4454 case Type::TYPE_COMPLEX:
4455 case Type::TYPE_STRING:
4456 case Type::TYPE_INTERFACE:
4457 is_small = false;
4458 can_take_address = false;
4459 break;
4460
4461 case Type::TYPE_STRUCT:
4462 is_small = false;
4463 can_take_address = true;
4464 break;
4465
4466 case Type::TYPE_ARRAY:
4467 is_small = false;
4468 can_take_address = !element_type->is_slice_type();
4469 break;
4470
4471 default:
4472 case Type::TYPE_ERROR:
4473 case Type::TYPE_VOID:
4474 case Type::TYPE_SINK:
4475 case Type::TYPE_NIL:
4476 case Type::TYPE_NAMED:
4477 case Type::TYPE_FORWARD:
4478 go_assert(saw_errors());
4479 return context->backend()->error_statement();
4480 }
4481
4482 // Only try to take the address of a variable. We have already
4483 // moved variables to the heap, so this should not cause that to
4484 // happen unnecessarily.
4485 if (can_take_address
4486 && val->var_expression() == NULL
4487 && val->temporary_reference_expression() == NULL)
4488 can_take_address = false;
4489
4490 Expression* td = Expression::make_type_descriptor(this->channel_->type(),
4491 loc);
4492
4493 Runtime::Function code;
4494 Bstatement* btemp = NULL;
4495 if (is_small)
4496 {
4497 // Type is small enough to handle as uint64.
4498 code = Runtime::SEND_SMALL;
4499 val = Expression::make_unsafe_cast(Type::lookup_integer_type("uint64"),
4500 val, loc);
4501 }
4502 else if (can_take_address)
4503 {
4504 // Must pass address of value. The function doesn't change the
4505 // value, so just take its address directly.
4506 code = Runtime::SEND_BIG;
4507 val = Expression::make_unary(OPERATOR_AND, val, loc);
4508 }
4509 else
4510 {
4511 // Must pass address of value, but the value is small enough
4512 // that it might be in registers. Copy value into temporary
4513 // variable to take address.
4514 code = Runtime::SEND_BIG;
4515 Temporary_statement* temp = Statement::make_temporary(element_type,
4516 val, loc);
4517 Expression* ref = Expression::make_temporary_reference(temp, loc);
4518 val = Expression::make_unary(OPERATOR_AND, ref, loc);
4519 btemp = temp->get_backend(context);
4520 }
4521
4522 Expression* call = Runtime::make_call(code, loc, 3, td, this->channel_, val);
4523
4524 context->gogo()->lower_expression(context->function(), NULL, &call);
4525 Bexpression* bcall = tree_to_expr(call->get_tree(context));
4526 Bstatement* s = context->backend()->expression_statement(bcall);
4527
4528 if (btemp == NULL)
4529 return s;
4530 else
4531 return context->backend()->compound_statement(btemp, s);
4532 }
4533
4534 // Dump the AST representation for a send statement
4535
4536 void
do_dump_statement(Ast_dump_context * ast_dump_context) const4537 Send_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
4538 {
4539 ast_dump_context->print_indent();
4540 ast_dump_context->dump_expression(this->channel_);
4541 ast_dump_context->ostream() << " <- ";
4542 ast_dump_context->dump_expression(this->val_);
4543 ast_dump_context->ostream() << std::endl;
4544 }
4545
4546 // Make a send statement.
4547
4548 Send_statement*
make_send_statement(Expression * channel,Expression * val,Location location)4549 Statement::make_send_statement(Expression* channel, Expression* val,
4550 Location location)
4551 {
4552 return new Send_statement(channel, val, location);
4553 }
4554
4555 // Class Select_clauses::Select_clause.
4556
4557 // Traversal.
4558
4559 int
traverse(Traverse * traverse)4560 Select_clauses::Select_clause::traverse(Traverse* traverse)
4561 {
4562 if (!this->is_lowered_
4563 && (traverse->traverse_mask()
4564 & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0)
4565 {
4566 if (this->channel_ != NULL)
4567 {
4568 if (Expression::traverse(&this->channel_, traverse) == TRAVERSE_EXIT)
4569 return TRAVERSE_EXIT;
4570 }
4571 if (this->val_ != NULL)
4572 {
4573 if (Expression::traverse(&this->val_, traverse) == TRAVERSE_EXIT)
4574 return TRAVERSE_EXIT;
4575 }
4576 if (this->closed_ != NULL)
4577 {
4578 if (Expression::traverse(&this->closed_, traverse) == TRAVERSE_EXIT)
4579 return TRAVERSE_EXIT;
4580 }
4581 }
4582 if (this->statements_ != NULL)
4583 {
4584 if (this->statements_->traverse(traverse) == TRAVERSE_EXIT)
4585 return TRAVERSE_EXIT;
4586 }
4587 return TRAVERSE_CONTINUE;
4588 }
4589
4590 // Lowering. We call a function to register this clause, and arrange
4591 // to set any variables in any receive clause.
4592
4593 void
lower(Gogo * gogo,Named_object * function,Block * b,Temporary_statement * sel)4594 Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
4595 Block* b, Temporary_statement* sel)
4596 {
4597 Location loc = this->location_;
4598
4599 Expression* selref = Expression::make_temporary_reference(sel, loc);
4600
4601 mpz_t ival;
4602 mpz_init_set_ui(ival, this->index_);
4603 Expression* index_expr = Expression::make_integer(&ival, NULL, loc);
4604 mpz_clear(ival);
4605
4606 if (this->is_default_)
4607 {
4608 go_assert(this->channel_ == NULL && this->val_ == NULL);
4609 this->lower_default(b, selref, index_expr);
4610 this->is_lowered_ = true;
4611 return;
4612 }
4613
4614 // Evaluate the channel before the select statement.
4615 Temporary_statement* channel_temp = Statement::make_temporary(NULL,
4616 this->channel_,
4617 loc);
4618 b->add_statement(channel_temp);
4619 Expression* chanref = Expression::make_temporary_reference(channel_temp,
4620 loc);
4621
4622 if (this->is_send_)
4623 this->lower_send(b, selref, chanref, index_expr);
4624 else
4625 this->lower_recv(gogo, function, b, selref, chanref, index_expr);
4626
4627 // Now all references should be handled through the statements, not
4628 // through here.
4629 this->is_lowered_ = true;
4630 this->val_ = NULL;
4631 this->var_ = NULL;
4632 }
4633
4634 // Lower a default clause in a select statement.
4635
4636 void
lower_default(Block * b,Expression * selref,Expression * index_expr)4637 Select_clauses::Select_clause::lower_default(Block* b, Expression* selref,
4638 Expression* index_expr)
4639 {
4640 Location loc = this->location_;
4641 Expression* call = Runtime::make_call(Runtime::SELECTDEFAULT, loc, 2, selref,
4642 index_expr);
4643 b->add_statement(Statement::make_statement(call, true));
4644 }
4645
4646 // Lower a send clause in a select statement.
4647
4648 void
lower_send(Block * b,Expression * selref,Expression * chanref,Expression * index_expr)4649 Select_clauses::Select_clause::lower_send(Block* b, Expression* selref,
4650 Expression* chanref,
4651 Expression* index_expr)
4652 {
4653 Location loc = this->location_;
4654
4655 Channel_type* ct = this->channel_->type()->channel_type();
4656 if (ct == NULL)
4657 return;
4658
4659 Type* valtype = ct->element_type();
4660
4661 // Note that copying the value to a temporary here means that we
4662 // evaluate the send values in the required order.
4663 Temporary_statement* val = Statement::make_temporary(valtype, this->val_,
4664 loc);
4665 b->add_statement(val);
4666
4667 Expression* valref = Expression::make_temporary_reference(val, loc);
4668 Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc);
4669
4670 Expression* call = Runtime::make_call(Runtime::SELECTSEND, loc, 4, selref,
4671 chanref, valaddr, index_expr);
4672 b->add_statement(Statement::make_statement(call, true));
4673 }
4674
4675 // Lower a receive clause in a select statement.
4676
4677 void
lower_recv(Gogo * gogo,Named_object * function,Block * b,Expression * selref,Expression * chanref,Expression * index_expr)4678 Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function,
4679 Block* b, Expression* selref,
4680 Expression* chanref,
4681 Expression* index_expr)
4682 {
4683 Location loc = this->location_;
4684
4685 Channel_type* ct = this->channel_->type()->channel_type();
4686 if (ct == NULL)
4687 return;
4688
4689 Type* valtype = ct->element_type();
4690 Temporary_statement* val = Statement::make_temporary(valtype, NULL, loc);
4691 b->add_statement(val);
4692
4693 Expression* valref = Expression::make_temporary_reference(val, loc);
4694 Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc);
4695
4696 Temporary_statement* closed_temp = NULL;
4697
4698 Expression* call;
4699 if (this->closed_ == NULL && this->closedvar_ == NULL)
4700 call = Runtime::make_call(Runtime::SELECTRECV, loc, 4, selref, chanref,
4701 valaddr, index_expr);
4702 else
4703 {
4704 closed_temp = Statement::make_temporary(Type::lookup_bool_type(), NULL,
4705 loc);
4706 b->add_statement(closed_temp);
4707 Expression* cref = Expression::make_temporary_reference(closed_temp,
4708 loc);
4709 Expression* caddr = Expression::make_unary(OPERATOR_AND, cref, loc);
4710 call = Runtime::make_call(Runtime::SELECTRECV2, loc, 5, selref, chanref,
4711 valaddr, caddr, index_expr);
4712 }
4713
4714 b->add_statement(Statement::make_statement(call, true));
4715
4716 // If the block of statements is executed, arrange for the received
4717 // value to move from VAL to the place where the statements expect
4718 // it.
4719
4720 Block* init = NULL;
4721
4722 if (this->var_ != NULL)
4723 {
4724 go_assert(this->val_ == NULL);
4725 valref = Expression::make_temporary_reference(val, loc);
4726 this->var_->var_value()->set_init(valref);
4727 this->var_->var_value()->clear_type_from_chan_element();
4728 }
4729 else if (this->val_ != NULL && !this->val_->is_sink_expression())
4730 {
4731 init = new Block(b, loc);
4732 valref = Expression::make_temporary_reference(val, loc);
4733 init->add_statement(Statement::make_assignment(this->val_, valref, loc));
4734 }
4735
4736 if (this->closedvar_ != NULL)
4737 {
4738 go_assert(this->closed_ == NULL);
4739 Expression* cref = Expression::make_temporary_reference(closed_temp,
4740 loc);
4741 this->closedvar_->var_value()->set_init(cref);
4742 }
4743 else if (this->closed_ != NULL && !this->closed_->is_sink_expression())
4744 {
4745 if (init == NULL)
4746 init = new Block(b, loc);
4747 Expression* cref = Expression::make_temporary_reference(closed_temp,
4748 loc);
4749 init->add_statement(Statement::make_assignment(this->closed_, cref,
4750 loc));
4751 }
4752
4753 if (init != NULL)
4754 {
4755 gogo->lower_block(function, init);
4756
4757 if (this->statements_ != NULL)
4758 init->add_statement(Statement::make_block_statement(this->statements_,
4759 loc));
4760 this->statements_ = init;
4761 }
4762 }
4763
4764 // Determine types.
4765
4766 void
determine_types()4767 Select_clauses::Select_clause::determine_types()
4768 {
4769 go_assert(this->is_lowered_);
4770 if (this->statements_ != NULL)
4771 this->statements_->determine_types();
4772 }
4773
4774 // Check types.
4775
4776 void
check_types()4777 Select_clauses::Select_clause::check_types()
4778 {
4779 if (this->is_default_)
4780 return;
4781
4782 Channel_type* ct = this->channel_->type()->channel_type();
4783 if (ct == NULL)
4784 {
4785 error_at(this->channel_->location(), "expected channel");
4786 return;
4787 }
4788
4789 if (this->is_send_ && !ct->may_send())
4790 error_at(this->location(), "invalid send on receive-only channel");
4791 else if (!this->is_send_ && !ct->may_receive())
4792 error_at(this->location(), "invalid receive on send-only channel");
4793 }
4794
4795 // Whether this clause may fall through to the statement which follows
4796 // the overall select statement.
4797
4798 bool
may_fall_through() const4799 Select_clauses::Select_clause::may_fall_through() const
4800 {
4801 if (this->statements_ == NULL)
4802 return true;
4803 return this->statements_->may_fall_through();
4804 }
4805
4806 // Return the backend representation for the statements to execute.
4807
4808 Bstatement*
get_statements_backend(Translate_context * context)4809 Select_clauses::Select_clause::get_statements_backend(
4810 Translate_context* context)
4811 {
4812 if (this->statements_ == NULL)
4813 return NULL;
4814 Bblock* bblock = this->statements_->get_backend(context);
4815 return context->backend()->block_statement(bblock);
4816 }
4817
4818 // Dump the AST representation for a select case clause
4819
4820 void
dump_clause(Ast_dump_context * ast_dump_context) const4821 Select_clauses::Select_clause::dump_clause(
4822 Ast_dump_context* ast_dump_context) const
4823 {
4824 ast_dump_context->print_indent();
4825 if (this->is_default_)
4826 {
4827 ast_dump_context->ostream() << "default:";
4828 }
4829 else
4830 {
4831 ast_dump_context->ostream() << "case " ;
4832 if (this->is_send_)
4833 {
4834 ast_dump_context->dump_expression(this->channel_);
4835 ast_dump_context->ostream() << " <- " ;
4836 if (this->val_ != NULL)
4837 ast_dump_context->dump_expression(this->val_);
4838 }
4839 else
4840 {
4841 if (this->val_ != NULL)
4842 ast_dump_context->dump_expression(this->val_);
4843 if (this->closed_ != NULL)
4844 {
4845 // FIXME: can val_ == NULL and closed_ ! = NULL?
4846 ast_dump_context->ostream() << " , " ;
4847 ast_dump_context->dump_expression(this->closed_);
4848 }
4849 if (this->closedvar_ != NULL || this->var_ != NULL)
4850 ast_dump_context->ostream() << " := " ;
4851
4852 ast_dump_context->ostream() << " <- " ;
4853 ast_dump_context->dump_expression(this->channel_);
4854 }
4855 ast_dump_context->ostream() << ":" ;
4856 }
4857 ast_dump_context->dump_block(this->statements_);
4858 }
4859
4860 // Class Select_clauses.
4861
4862 // Traversal.
4863
4864 int
traverse(Traverse * traverse)4865 Select_clauses::traverse(Traverse* traverse)
4866 {
4867 for (Clauses::iterator p = this->clauses_.begin();
4868 p != this->clauses_.end();
4869 ++p)
4870 {
4871 if (p->traverse(traverse) == TRAVERSE_EXIT)
4872 return TRAVERSE_EXIT;
4873 }
4874 return TRAVERSE_CONTINUE;
4875 }
4876
4877 // Lowering. Here we pull out the channel and the send values, to
4878 // enforce the order of evaluation. We also add explicit send and
4879 // receive statements to the clauses.
4880
4881 void
lower(Gogo * gogo,Named_object * function,Block * b,Temporary_statement * sel)4882 Select_clauses::lower(Gogo* gogo, Named_object* function, Block* b,
4883 Temporary_statement* sel)
4884 {
4885 for (Clauses::iterator p = this->clauses_.begin();
4886 p != this->clauses_.end();
4887 ++p)
4888 p->lower(gogo, function, b, sel);
4889 }
4890
4891 // Determine types.
4892
4893 void
determine_types()4894 Select_clauses::determine_types()
4895 {
4896 for (Clauses::iterator p = this->clauses_.begin();
4897 p != this->clauses_.end();
4898 ++p)
4899 p->determine_types();
4900 }
4901
4902 // Check types.
4903
4904 void
check_types()4905 Select_clauses::check_types()
4906 {
4907 for (Clauses::iterator p = this->clauses_.begin();
4908 p != this->clauses_.end();
4909 ++p)
4910 p->check_types();
4911 }
4912
4913 // Return whether these select clauses fall through to the statement
4914 // following the overall select statement.
4915
4916 bool
may_fall_through() const4917 Select_clauses::may_fall_through() const
4918 {
4919 for (Clauses::const_iterator p = this->clauses_.begin();
4920 p != this->clauses_.end();
4921 ++p)
4922 if (p->may_fall_through())
4923 return true;
4924 return false;
4925 }
4926
4927 // Convert to the backend representation. We have already accumulated
4928 // all the select information. Now we call selectgo, which will
4929 // return the index of the clause to execute.
4930
4931 Bstatement*
get_backend(Translate_context * context,Temporary_statement * sel,Unnamed_label * break_label,Location location)4932 Select_clauses::get_backend(Translate_context* context,
4933 Temporary_statement* sel,
4934 Unnamed_label *break_label,
4935 Location location)
4936 {
4937 size_t count = this->clauses_.size();
4938 std::vector<std::vector<Bexpression*> > cases(count);
4939 std::vector<Bstatement*> clauses(count);
4940
4941 Type* int32_type = Type::lookup_integer_type("int32");
4942
4943 int i = 0;
4944 for (Clauses::iterator p = this->clauses_.begin();
4945 p != this->clauses_.end();
4946 ++p, ++i)
4947 {
4948 int index = p->index();
4949 mpz_t ival;
4950 mpz_init_set_ui(ival, index);
4951 Expression* index_expr = Expression::make_integer(&ival, int32_type,
4952 location);
4953 mpz_clear(ival);
4954 cases[i].push_back(tree_to_expr(index_expr->get_tree(context)));
4955
4956 Bstatement* s = p->get_statements_backend(context);
4957 Location gloc = (p->statements() == NULL
4958 ? p->location()
4959 : p->statements()->end_location());
4960 Bstatement* g = break_label->get_goto(context, gloc);
4961
4962 if (s == NULL)
4963 clauses[i] = g;
4964 else
4965 clauses[i] = context->backend()->compound_statement(s, g);
4966 }
4967
4968 Expression* selref = Expression::make_temporary_reference(sel, location);
4969 Expression* call = Runtime::make_call(Runtime::SELECTGO, location, 1,
4970 selref);
4971 context->gogo()->lower_expression(context->function(), NULL, &call);
4972 Bexpression* bcall = tree_to_expr(call->get_tree(context));
4973
4974 if (count == 0)
4975 return context->backend()->expression_statement(bcall);
4976
4977 std::vector<Bstatement*> statements;
4978 statements.reserve(2);
4979
4980 Bstatement* switch_stmt = context->backend()->switch_statement(bcall,
4981 cases,
4982 clauses,
4983 location);
4984 statements.push_back(switch_stmt);
4985
4986 Bstatement* ldef = break_label->get_definition(context);
4987 statements.push_back(ldef);
4988
4989 return context->backend()->statement_list(statements);
4990 }
4991 // Dump the AST representation for select clauses.
4992
4993 void
dump_clauses(Ast_dump_context * ast_dump_context) const4994 Select_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
4995 {
4996 for (Clauses::const_iterator p = this->clauses_.begin();
4997 p != this->clauses_.end();
4998 ++p)
4999 p->dump_clause(ast_dump_context);
5000 }
5001
5002 // Class Select_statement.
5003
5004 // Return the break label for this switch statement, creating it if
5005 // necessary.
5006
5007 Unnamed_label*
break_label()5008 Select_statement::break_label()
5009 {
5010 if (this->break_label_ == NULL)
5011 this->break_label_ = new Unnamed_label(this->location());
5012 return this->break_label_;
5013 }
5014
5015 // Lower a select statement. This will still return a select
5016 // statement, but it will be modified to implement the order of
5017 // evaluation rules, and to include the send and receive statements as
5018 // explicit statements in the clauses.
5019
5020 Statement*
do_lower(Gogo * gogo,Named_object * function,Block * enclosing,Statement_inserter *)5021 Select_statement::do_lower(Gogo* gogo, Named_object* function,
5022 Block* enclosing, Statement_inserter*)
5023 {
5024 if (this->is_lowered_)
5025 return this;
5026
5027 Location loc = this->location();
5028
5029 Block* b = new Block(enclosing, loc);
5030
5031 go_assert(this->sel_ == NULL);
5032
5033 mpz_t ival;
5034 mpz_init_set_ui(ival, this->clauses_->size());
5035 Expression* size_expr = Expression::make_integer(&ival, NULL, loc);
5036 mpz_clear(ival);
5037
5038 Expression* call = Runtime::make_call(Runtime::NEWSELECT, loc, 1, size_expr);
5039
5040 this->sel_ = Statement::make_temporary(NULL, call, loc);
5041 b->add_statement(this->sel_);
5042
5043 this->clauses_->lower(gogo, function, b, this->sel_);
5044 this->is_lowered_ = true;
5045 b->add_statement(this);
5046
5047 return Statement::make_block_statement(b, loc);
5048 }
5049
5050 // Whether the select statement itself may fall through to the following
5051 // statement.
5052
5053 bool
do_may_fall_through() const5054 Select_statement::do_may_fall_through() const
5055 {
5056 // A select statement is terminating if no break statement
5057 // refers to it and all of its clauses are terminating.
5058 if (this->break_label_ != NULL)
5059 return true;
5060 return this->clauses_->may_fall_through();
5061 }
5062
5063 // Return the backend representation for a select statement.
5064
5065 Bstatement*
do_get_backend(Translate_context * context)5066 Select_statement::do_get_backend(Translate_context* context)
5067 {
5068 return this->clauses_->get_backend(context, this->sel_, this->break_label(),
5069 this->location());
5070 }
5071
5072 // Dump the AST representation for a select statement.
5073
5074 void
do_dump_statement(Ast_dump_context * ast_dump_context) const5075 Select_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
5076 {
5077 ast_dump_context->print_indent();
5078 ast_dump_context->ostream() << "select";
5079 if (ast_dump_context->dump_subblocks())
5080 {
5081 ast_dump_context->ostream() << " {" << std::endl;
5082 this->clauses_->dump_clauses(ast_dump_context);
5083 ast_dump_context->ostream() << "}";
5084 }
5085 ast_dump_context->ostream() << std::endl;
5086 }
5087
5088 // Make a select statement.
5089
5090 Select_statement*
make_select_statement(Location location)5091 Statement::make_select_statement(Location location)
5092 {
5093 return new Select_statement(location);
5094 }
5095
5096 // Class For_statement.
5097
5098 // Traversal.
5099
5100 int
do_traverse(Traverse * traverse)5101 For_statement::do_traverse(Traverse* traverse)
5102 {
5103 if (this->init_ != NULL)
5104 {
5105 if (this->init_->traverse(traverse) == TRAVERSE_EXIT)
5106 return TRAVERSE_EXIT;
5107 }
5108 if (this->cond_ != NULL)
5109 {
5110 if (this->traverse_expression(traverse, &this->cond_) == TRAVERSE_EXIT)
5111 return TRAVERSE_EXIT;
5112 }
5113 if (this->post_ != NULL)
5114 {
5115 if (this->post_->traverse(traverse) == TRAVERSE_EXIT)
5116 return TRAVERSE_EXIT;
5117 }
5118 return this->statements_->traverse(traverse);
5119 }
5120
5121 // Lower a For_statement into if statements and gotos. Getting rid of
5122 // complex statements make it easier to handle garbage collection.
5123
5124 Statement*
do_lower(Gogo *,Named_object *,Block * enclosing,Statement_inserter *)5125 For_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
5126 Statement_inserter*)
5127 {
5128 Statement* s;
5129 Location loc = this->location();
5130
5131 Block* b = new Block(enclosing, this->location());
5132 if (this->init_ != NULL)
5133 {
5134 s = Statement::make_block_statement(this->init_,
5135 this->init_->start_location());
5136 b->add_statement(s);
5137 }
5138
5139 Unnamed_label* entry = NULL;
5140 if (this->cond_ != NULL)
5141 {
5142 entry = new Unnamed_label(this->location());
5143 b->add_statement(Statement::make_goto_unnamed_statement(entry, loc));
5144 }
5145
5146 Unnamed_label* top = new Unnamed_label(this->location());
5147 b->add_statement(Statement::make_unnamed_label_statement(top));
5148
5149 s = Statement::make_block_statement(this->statements_,
5150 this->statements_->start_location());
5151 b->add_statement(s);
5152
5153 Location end_loc = this->statements_->end_location();
5154
5155 Unnamed_label* cont = this->continue_label_;
5156 if (cont != NULL)
5157 b->add_statement(Statement::make_unnamed_label_statement(cont));
5158
5159 if (this->post_ != NULL)
5160 {
5161 s = Statement::make_block_statement(this->post_,
5162 this->post_->start_location());
5163 b->add_statement(s);
5164 end_loc = this->post_->end_location();
5165 }
5166
5167 if (this->cond_ == NULL)
5168 b->add_statement(Statement::make_goto_unnamed_statement(top, end_loc));
5169 else
5170 {
5171 b->add_statement(Statement::make_unnamed_label_statement(entry));
5172
5173 Location cond_loc = this->cond_->location();
5174 Block* then_block = new Block(b, cond_loc);
5175 s = Statement::make_goto_unnamed_statement(top, cond_loc);
5176 then_block->add_statement(s);
5177
5178 s = Statement::make_if_statement(this->cond_, then_block, NULL, cond_loc);
5179 b->add_statement(s);
5180 }
5181
5182 Unnamed_label* brk = this->break_label_;
5183 if (brk != NULL)
5184 b->add_statement(Statement::make_unnamed_label_statement(brk));
5185
5186 b->set_end_location(end_loc);
5187
5188 return Statement::make_block_statement(b, loc);
5189 }
5190
5191 // Return the break label, creating it if necessary.
5192
5193 Unnamed_label*
break_label()5194 For_statement::break_label()
5195 {
5196 if (this->break_label_ == NULL)
5197 this->break_label_ = new Unnamed_label(this->location());
5198 return this->break_label_;
5199 }
5200
5201 // Return the continue LABEL_EXPR.
5202
5203 Unnamed_label*
continue_label()5204 For_statement::continue_label()
5205 {
5206 if (this->continue_label_ == NULL)
5207 this->continue_label_ = new Unnamed_label(this->location());
5208 return this->continue_label_;
5209 }
5210
5211 // Set the break and continue labels a for statement. This is used
5212 // when lowering a for range statement.
5213
5214 void
set_break_continue_labels(Unnamed_label * break_label,Unnamed_label * continue_label)5215 For_statement::set_break_continue_labels(Unnamed_label* break_label,
5216 Unnamed_label* continue_label)
5217 {
5218 go_assert(this->break_label_ == NULL && this->continue_label_ == NULL);
5219 this->break_label_ = break_label;
5220 this->continue_label_ = continue_label;
5221 }
5222
5223 // Whether the overall statement may fall through.
5224
5225 bool
do_may_fall_through() const5226 For_statement::do_may_fall_through() const
5227 {
5228 // A for loop is terminating if it has no condition and
5229 // no break statement.
5230 if(this->cond_ != NULL)
5231 return true;
5232 if(this->break_label_ != NULL)
5233 return true;
5234 return false;
5235 }
5236
5237 // Dump the AST representation for a for statement.
5238
5239 void
do_dump_statement(Ast_dump_context * ast_dump_context) const5240 For_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
5241 {
5242 if (this->init_ != NULL && ast_dump_context->dump_subblocks())
5243 {
5244 ast_dump_context->print_indent();
5245 ast_dump_context->indent();
5246 ast_dump_context->ostream() << "// INIT " << std::endl;
5247 ast_dump_context->dump_block(this->init_);
5248 ast_dump_context->unindent();
5249 }
5250 ast_dump_context->print_indent();
5251 ast_dump_context->ostream() << "for ";
5252 if (this->cond_ != NULL)
5253 ast_dump_context->dump_expression(this->cond_);
5254
5255 if (ast_dump_context->dump_subblocks())
5256 {
5257 ast_dump_context->ostream() << " {" << std::endl;
5258 ast_dump_context->dump_block(this->statements_);
5259 if (this->init_ != NULL)
5260 {
5261 ast_dump_context->print_indent();
5262 ast_dump_context->ostream() << "// POST " << std::endl;
5263 ast_dump_context->dump_block(this->post_);
5264 }
5265 ast_dump_context->unindent();
5266
5267 ast_dump_context->print_indent();
5268 ast_dump_context->ostream() << "}";
5269 }
5270
5271 ast_dump_context->ostream() << std::endl;
5272 }
5273
5274 // Make a for statement.
5275
5276 For_statement*
make_for_statement(Block * init,Expression * cond,Block * post,Location location)5277 Statement::make_for_statement(Block* init, Expression* cond, Block* post,
5278 Location location)
5279 {
5280 return new For_statement(init, cond, post, location);
5281 }
5282
5283 // Class For_range_statement.
5284
5285 // Traversal.
5286
5287 int
do_traverse(Traverse * traverse)5288 For_range_statement::do_traverse(Traverse* traverse)
5289 {
5290 if (this->traverse_expression(traverse, &this->index_var_) == TRAVERSE_EXIT)
5291 return TRAVERSE_EXIT;
5292 if (this->value_var_ != NULL)
5293 {
5294 if (this->traverse_expression(traverse, &this->value_var_)
5295 == TRAVERSE_EXIT)
5296 return TRAVERSE_EXIT;
5297 }
5298 if (this->traverse_expression(traverse, &this->range_) == TRAVERSE_EXIT)
5299 return TRAVERSE_EXIT;
5300 return this->statements_->traverse(traverse);
5301 }
5302
5303 // Lower a for range statement. For simplicity we lower this into a
5304 // for statement, which will then be lowered in turn to goto
5305 // statements.
5306
5307 Statement*
do_lower(Gogo * gogo,Named_object *,Block * enclosing,Statement_inserter *)5308 For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
5309 Statement_inserter*)
5310 {
5311 Type* range_type = this->range_->type();
5312 if (range_type->points_to() != NULL
5313 && range_type->points_to()->array_type() != NULL
5314 && !range_type->points_to()->is_slice_type())
5315 range_type = range_type->points_to();
5316
5317 Type* index_type;
5318 Type* value_type = NULL;
5319 if (range_type->array_type() != NULL)
5320 {
5321 index_type = Type::lookup_integer_type("int");
5322 value_type = range_type->array_type()->element_type();
5323 }
5324 else if (range_type->is_string_type())
5325 {
5326 index_type = Type::lookup_integer_type("int");
5327 value_type = Type::lookup_integer_type("int32");
5328 }
5329 else if (range_type->map_type() != NULL)
5330 {
5331 index_type = range_type->map_type()->key_type();
5332 value_type = range_type->map_type()->val_type();
5333 }
5334 else if (range_type->channel_type() != NULL)
5335 {
5336 index_type = range_type->channel_type()->element_type();
5337 if (this->value_var_ != NULL)
5338 {
5339 if (!this->value_var_->type()->is_error())
5340 this->report_error(_("too many variables for range clause "
5341 "with channel"));
5342 return Statement::make_error_statement(this->location());
5343 }
5344 }
5345 else
5346 {
5347 this->report_error(_("range clause must have "
5348 "array, slice, string, map, or channel type"));
5349 return Statement::make_error_statement(this->location());
5350 }
5351
5352 Location loc = this->location();
5353 Block* temp_block = new Block(enclosing, loc);
5354
5355 Named_object* range_object = NULL;
5356 Temporary_statement* range_temp = NULL;
5357 Var_expression* ve = this->range_->var_expression();
5358 if (ve != NULL)
5359 range_object = ve->named_object();
5360 else
5361 {
5362 range_temp = Statement::make_temporary(NULL, this->range_, loc);
5363 temp_block->add_statement(range_temp);
5364 this->range_ = NULL;
5365 }
5366
5367 Temporary_statement* index_temp = Statement::make_temporary(index_type,
5368 NULL, loc);
5369 temp_block->add_statement(index_temp);
5370
5371 Temporary_statement* value_temp = NULL;
5372 if (this->value_var_ != NULL)
5373 {
5374 value_temp = Statement::make_temporary(value_type, NULL, loc);
5375 temp_block->add_statement(value_temp);
5376 }
5377
5378 Block* body = new Block(temp_block, loc);
5379
5380 Block* init;
5381 Expression* cond;
5382 Block* iter_init;
5383 Block* post;
5384
5385 // Arrange to do a loop appropriate for the type. We will produce
5386 // for INIT ; COND ; POST {
5387 // ITER_INIT
5388 // INDEX = INDEX_TEMP
5389 // VALUE = VALUE_TEMP // If there is a value
5390 // original statements
5391 // }
5392
5393 if (range_type->is_slice_type())
5394 this->lower_range_slice(gogo, temp_block, body, range_object, range_temp,
5395 index_temp, value_temp, &init, &cond, &iter_init,
5396 &post);
5397 else if (range_type->array_type() != NULL)
5398 this->lower_range_array(gogo, temp_block, body, range_object, range_temp,
5399 index_temp, value_temp, &init, &cond, &iter_init,
5400 &post);
5401 else if (range_type->is_string_type())
5402 this->lower_range_string(gogo, temp_block, body, range_object, range_temp,
5403 index_temp, value_temp, &init, &cond, &iter_init,
5404 &post);
5405 else if (range_type->map_type() != NULL)
5406 this->lower_range_map(gogo, temp_block, body, range_object, range_temp,
5407 index_temp, value_temp, &init, &cond, &iter_init,
5408 &post);
5409 else if (range_type->channel_type() != NULL)
5410 this->lower_range_channel(gogo, temp_block, body, range_object, range_temp,
5411 index_temp, value_temp, &init, &cond, &iter_init,
5412 &post);
5413 else
5414 go_unreachable();
5415
5416 if (iter_init != NULL)
5417 body->add_statement(Statement::make_block_statement(iter_init, loc));
5418
5419 Statement* assign;
5420 Expression* index_ref = Expression::make_temporary_reference(index_temp, loc);
5421 if (this->value_var_ == NULL)
5422 {
5423 assign = Statement::make_assignment(this->index_var_, index_ref, loc);
5424 }
5425 else
5426 {
5427 Expression_list* lhs = new Expression_list();
5428 lhs->push_back(this->index_var_);
5429 lhs->push_back(this->value_var_);
5430
5431 Expression_list* rhs = new Expression_list();
5432 rhs->push_back(index_ref);
5433 rhs->push_back(Expression::make_temporary_reference(value_temp, loc));
5434
5435 assign = Statement::make_tuple_assignment(lhs, rhs, loc);
5436 }
5437 body->add_statement(assign);
5438
5439 body->add_statement(Statement::make_block_statement(this->statements_, loc));
5440
5441 body->set_end_location(this->statements_->end_location());
5442
5443 For_statement* loop = Statement::make_for_statement(init, cond, post,
5444 this->location());
5445 loop->add_statements(body);
5446 loop->set_break_continue_labels(this->break_label_, this->continue_label_);
5447
5448 temp_block->add_statement(loop);
5449
5450 return Statement::make_block_statement(temp_block, loc);
5451 }
5452
5453 // Return a reference to the range, which may be in RANGE_OBJECT or in
5454 // RANGE_TEMP.
5455
5456 Expression*
make_range_ref(Named_object * range_object,Temporary_statement * range_temp,Location loc)5457 For_range_statement::make_range_ref(Named_object* range_object,
5458 Temporary_statement* range_temp,
5459 Location loc)
5460 {
5461 if (range_object != NULL)
5462 return Expression::make_var_reference(range_object, loc);
5463 else
5464 return Expression::make_temporary_reference(range_temp, loc);
5465 }
5466
5467 // Return a call to the predeclared function FUNCNAME passing a
5468 // reference to the temporary variable ARG.
5469
5470 Expression*
call_builtin(Gogo * gogo,const char * funcname,Expression * arg,Location loc)5471 For_range_statement::call_builtin(Gogo* gogo, const char* funcname,
5472 Expression* arg,
5473 Location loc)
5474 {
5475 Named_object* no = gogo->lookup_global(funcname);
5476 go_assert(no != NULL && no->is_function_declaration());
5477 Expression* func = Expression::make_func_reference(no, NULL, loc);
5478 Expression_list* params = new Expression_list();
5479 params->push_back(arg);
5480 return Expression::make_call(func, params, false, loc);
5481 }
5482
5483 // Lower a for range over an array.
5484
5485 void
lower_range_array(Gogo * gogo,Block * enclosing,Block * body_block,Named_object * range_object,Temporary_statement * range_temp,Temporary_statement * index_temp,Temporary_statement * value_temp,Block ** pinit,Expression ** pcond,Block ** piter_init,Block ** ppost)5486 For_range_statement::lower_range_array(Gogo* gogo,
5487 Block* enclosing,
5488 Block* body_block,
5489 Named_object* range_object,
5490 Temporary_statement* range_temp,
5491 Temporary_statement* index_temp,
5492 Temporary_statement* value_temp,
5493 Block** pinit,
5494 Expression** pcond,
5495 Block** piter_init,
5496 Block** ppost)
5497 {
5498 Location loc = this->location();
5499
5500 // The loop we generate:
5501 // len_temp := len(range)
5502 // for index_temp = 0; index_temp < len_temp; index_temp++ {
5503 // value_temp = range[index_temp]
5504 // index = index_temp
5505 // value = value_temp
5506 // original body
5507 // }
5508
5509 // Set *PINIT to
5510 // var len_temp int
5511 // len_temp = len(range)
5512 // index_temp = 0
5513
5514 Block* init = new Block(enclosing, loc);
5515
5516 Expression* ref = this->make_range_ref(range_object, range_temp, loc);
5517 Expression* len_call = this->call_builtin(gogo, "len", ref, loc);
5518 Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(),
5519 len_call, loc);
5520 init->add_statement(len_temp);
5521
5522 mpz_t zval;
5523 mpz_init_set_ui(zval, 0UL);
5524 Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
5525 mpz_clear(zval);
5526
5527 Temporary_reference_expression* tref =
5528 Expression::make_temporary_reference(index_temp, loc);
5529 tref->set_is_lvalue();
5530 Statement* s = Statement::make_assignment(tref, zexpr, loc);
5531 init->add_statement(s);
5532
5533 *pinit = init;
5534
5535 // Set *PCOND to
5536 // index_temp < len_temp
5537
5538 ref = Expression::make_temporary_reference(index_temp, loc);
5539 Expression* ref2 = Expression::make_temporary_reference(len_temp, loc);
5540 Expression* lt = Expression::make_binary(OPERATOR_LT, ref, ref2, loc);
5541
5542 *pcond = lt;
5543
5544 // Set *PITER_INIT to
5545 // value_temp = range[index_temp]
5546
5547 Block* iter_init = NULL;
5548 if (value_temp != NULL)
5549 {
5550 iter_init = new Block(body_block, loc);
5551
5552 ref = this->make_range_ref(range_object, range_temp, loc);
5553 Expression* ref2 = Expression::make_temporary_reference(index_temp, loc);
5554 Expression* index = Expression::make_index(ref, ref2, NULL, NULL, loc);
5555
5556 tref = Expression::make_temporary_reference(value_temp, loc);
5557 tref->set_is_lvalue();
5558 s = Statement::make_assignment(tref, index, loc);
5559
5560 iter_init->add_statement(s);
5561 }
5562 *piter_init = iter_init;
5563
5564 // Set *PPOST to
5565 // index_temp++
5566
5567 Block* post = new Block(enclosing, loc);
5568 tref = Expression::make_temporary_reference(index_temp, loc);
5569 tref->set_is_lvalue();
5570 s = Statement::make_inc_statement(tref);
5571 post->add_statement(s);
5572 *ppost = post;
5573 }
5574
5575 // Lower a for range over a slice.
5576
5577 void
lower_range_slice(Gogo * gogo,Block * enclosing,Block * body_block,Named_object * range_object,Temporary_statement * range_temp,Temporary_statement * index_temp,Temporary_statement * value_temp,Block ** pinit,Expression ** pcond,Block ** piter_init,Block ** ppost)5578 For_range_statement::lower_range_slice(Gogo* gogo,
5579 Block* enclosing,
5580 Block* body_block,
5581 Named_object* range_object,
5582 Temporary_statement* range_temp,
5583 Temporary_statement* index_temp,
5584 Temporary_statement* value_temp,
5585 Block** pinit,
5586 Expression** pcond,
5587 Block** piter_init,
5588 Block** ppost)
5589 {
5590 Location loc = this->location();
5591
5592 // The loop we generate:
5593 // for_temp := range
5594 // len_temp := len(for_temp)
5595 // for index_temp = 0; index_temp < len_temp; index_temp++ {
5596 // value_temp = for_temp[index_temp]
5597 // index = index_temp
5598 // value = value_temp
5599 // original body
5600 // }
5601 //
5602 // Using for_temp means that we don't need to check bounds when
5603 // fetching range_temp[index_temp].
5604
5605 // Set *PINIT to
5606 // range_temp := range
5607 // var len_temp int
5608 // len_temp = len(range_temp)
5609 // index_temp = 0
5610
5611 Block* init = new Block(enclosing, loc);
5612
5613 Expression* ref = this->make_range_ref(range_object, range_temp, loc);
5614 Temporary_statement* for_temp = Statement::make_temporary(NULL, ref, loc);
5615 init->add_statement(for_temp);
5616
5617 ref = Expression::make_temporary_reference(for_temp, loc);
5618 Expression* len_call = this->call_builtin(gogo, "len", ref, loc);
5619 Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(),
5620 len_call, loc);
5621 init->add_statement(len_temp);
5622
5623 mpz_t zval;
5624 mpz_init_set_ui(zval, 0UL);
5625 Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
5626 mpz_clear(zval);
5627
5628 Temporary_reference_expression* tref =
5629 Expression::make_temporary_reference(index_temp, loc);
5630 tref->set_is_lvalue();
5631 Statement* s = Statement::make_assignment(tref, zexpr, loc);
5632 init->add_statement(s);
5633
5634 *pinit = init;
5635
5636 // Set *PCOND to
5637 // index_temp < len_temp
5638
5639 ref = Expression::make_temporary_reference(index_temp, loc);
5640 Expression* ref2 = Expression::make_temporary_reference(len_temp, loc);
5641 Expression* lt = Expression::make_binary(OPERATOR_LT, ref, ref2, loc);
5642
5643 *pcond = lt;
5644
5645 // Set *PITER_INIT to
5646 // value_temp = range[index_temp]
5647
5648 Block* iter_init = NULL;
5649 if (value_temp != NULL)
5650 {
5651 iter_init = new Block(body_block, loc);
5652
5653 ref = Expression::make_temporary_reference(for_temp, loc);
5654 Expression* ref2 = Expression::make_temporary_reference(index_temp, loc);
5655 Expression* index = Expression::make_index(ref, ref2, NULL, NULL, loc);
5656
5657 tref = Expression::make_temporary_reference(value_temp, loc);
5658 tref->set_is_lvalue();
5659 s = Statement::make_assignment(tref, index, loc);
5660
5661 iter_init->add_statement(s);
5662 }
5663 *piter_init = iter_init;
5664
5665 // Set *PPOST to
5666 // index_temp++
5667
5668 Block* post = new Block(enclosing, loc);
5669 tref = Expression::make_temporary_reference(index_temp, loc);
5670 tref->set_is_lvalue();
5671 s = Statement::make_inc_statement(tref);
5672 post->add_statement(s);
5673 *ppost = post;
5674 }
5675
5676 // Lower a for range over a string.
5677
5678 void
lower_range_string(Gogo *,Block * enclosing,Block * body_block,Named_object * range_object,Temporary_statement * range_temp,Temporary_statement * index_temp,Temporary_statement * value_temp,Block ** pinit,Expression ** pcond,Block ** piter_init,Block ** ppost)5679 For_range_statement::lower_range_string(Gogo*,
5680 Block* enclosing,
5681 Block* body_block,
5682 Named_object* range_object,
5683 Temporary_statement* range_temp,
5684 Temporary_statement* index_temp,
5685 Temporary_statement* value_temp,
5686 Block** pinit,
5687 Expression** pcond,
5688 Block** piter_init,
5689 Block** ppost)
5690 {
5691 Location loc = this->location();
5692
5693 // The loop we generate:
5694 // var next_index_temp int
5695 // for index_temp = 0; ; index_temp = next_index_temp {
5696 // next_index_temp, value_temp = stringiter2(range, index_temp)
5697 // if next_index_temp == 0 {
5698 // break
5699 // }
5700 // index = index_temp
5701 // value = value_temp
5702 // original body
5703 // }
5704
5705 // Set *PINIT to
5706 // var next_index_temp int
5707 // index_temp = 0
5708
5709 Block* init = new Block(enclosing, loc);
5710
5711 Temporary_statement* next_index_temp =
5712 Statement::make_temporary(index_temp->type(), NULL, loc);
5713 init->add_statement(next_index_temp);
5714
5715 mpz_t zval;
5716 mpz_init_set_ui(zval, 0UL);
5717 Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
5718
5719 Temporary_reference_expression* ref =
5720 Expression::make_temporary_reference(index_temp, loc);
5721 ref->set_is_lvalue();
5722 Statement* s = Statement::make_assignment(ref, zexpr, loc);
5723
5724 init->add_statement(s);
5725 *pinit = init;
5726
5727 // The loop has no condition.
5728
5729 *pcond = NULL;
5730
5731 // Set *PITER_INIT to
5732 // next_index_temp = runtime.stringiter(range, index_temp)
5733 // or
5734 // next_index_temp, value_temp = runtime.stringiter2(range, index_temp)
5735 // followed by
5736 // if next_index_temp == 0 {
5737 // break
5738 // }
5739
5740 Block* iter_init = new Block(body_block, loc);
5741
5742 Expression* p1 = this->make_range_ref(range_object, range_temp, loc);
5743 Expression* p2 = Expression::make_temporary_reference(index_temp, loc);
5744 Call_expression* call = Runtime::make_call((value_temp == NULL
5745 ? Runtime::STRINGITER
5746 : Runtime::STRINGITER2),
5747 loc, 2, p1, p2);
5748
5749 if (value_temp == NULL)
5750 {
5751 ref = Expression::make_temporary_reference(next_index_temp, loc);
5752 ref->set_is_lvalue();
5753 s = Statement::make_assignment(ref, call, loc);
5754 }
5755 else
5756 {
5757 Expression_list* lhs = new Expression_list();
5758
5759 ref = Expression::make_temporary_reference(next_index_temp, loc);
5760 ref->set_is_lvalue();
5761 lhs->push_back(ref);
5762
5763 ref = Expression::make_temporary_reference(value_temp, loc);
5764 ref->set_is_lvalue();
5765 lhs->push_back(ref);
5766
5767 Expression_list* rhs = new Expression_list();
5768 rhs->push_back(Expression::make_call_result(call, 0));
5769 rhs->push_back(Expression::make_call_result(call, 1));
5770
5771 s = Statement::make_tuple_assignment(lhs, rhs, loc);
5772 }
5773 iter_init->add_statement(s);
5774
5775 ref = Expression::make_temporary_reference(next_index_temp, loc);
5776 zexpr = Expression::make_integer(&zval, NULL, loc);
5777 mpz_clear(zval);
5778 Expression* equals = Expression::make_binary(OPERATOR_EQEQ, ref, zexpr, loc);
5779
5780 Block* then_block = new Block(iter_init, loc);
5781 s = Statement::make_break_statement(this->break_label(), loc);
5782 then_block->add_statement(s);
5783
5784 s = Statement::make_if_statement(equals, then_block, NULL, loc);
5785 iter_init->add_statement(s);
5786
5787 *piter_init = iter_init;
5788
5789 // Set *PPOST to
5790 // index_temp = next_index_temp
5791
5792 Block* post = new Block(enclosing, loc);
5793
5794 Temporary_reference_expression* lhs =
5795 Expression::make_temporary_reference(index_temp, loc);
5796 lhs->set_is_lvalue();
5797 Expression* rhs = Expression::make_temporary_reference(next_index_temp, loc);
5798 s = Statement::make_assignment(lhs, rhs, loc);
5799
5800 post->add_statement(s);
5801 *ppost = post;
5802 }
5803
5804 // Lower a for range over a map.
5805
5806 void
lower_range_map(Gogo *,Block * enclosing,Block * body_block,Named_object * range_object,Temporary_statement * range_temp,Temporary_statement * index_temp,Temporary_statement * value_temp,Block ** pinit,Expression ** pcond,Block ** piter_init,Block ** ppost)5807 For_range_statement::lower_range_map(Gogo*,
5808 Block* enclosing,
5809 Block* body_block,
5810 Named_object* range_object,
5811 Temporary_statement* range_temp,
5812 Temporary_statement* index_temp,
5813 Temporary_statement* value_temp,
5814 Block** pinit,
5815 Expression** pcond,
5816 Block** piter_init,
5817 Block** ppost)
5818 {
5819 Location loc = this->location();
5820
5821 // The runtime uses a struct to handle ranges over a map. The
5822 // struct is four pointers long. The first pointer is NULL when we
5823 // have completed the iteration.
5824
5825 // The loop we generate:
5826 // var hiter map_iteration_struct
5827 // for mapiterinit(range, &hiter); hiter[0] != nil; mapiternext(&hiter) {
5828 // mapiter2(hiter, &index_temp, &value_temp)
5829 // index = index_temp
5830 // value = value_temp
5831 // original body
5832 // }
5833
5834 // Set *PINIT to
5835 // var hiter map_iteration_struct
5836 // runtime.mapiterinit(range, &hiter)
5837
5838 Block* init = new Block(enclosing, loc);
5839
5840 Type* map_iteration_type = Runtime::map_iteration_type();
5841 Temporary_statement* hiter = Statement::make_temporary(map_iteration_type,
5842 NULL, loc);
5843 init->add_statement(hiter);
5844
5845 Expression* p1 = this->make_range_ref(range_object, range_temp, loc);
5846 Expression* ref = Expression::make_temporary_reference(hiter, loc);
5847 Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
5848 Expression* call = Runtime::make_call(Runtime::MAPITERINIT, loc, 2, p1, p2);
5849 init->add_statement(Statement::make_statement(call, true));
5850
5851 *pinit = init;
5852
5853 // Set *PCOND to
5854 // hiter[0] != nil
5855
5856 ref = Expression::make_temporary_reference(hiter, loc);
5857
5858 mpz_t zval;
5859 mpz_init_set_ui(zval, 0UL);
5860 Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
5861 mpz_clear(zval);
5862
5863 Expression* index = Expression::make_index(ref, zexpr, NULL, NULL, loc);
5864
5865 Expression* ne = Expression::make_binary(OPERATOR_NOTEQ, index,
5866 Expression::make_nil(loc),
5867 loc);
5868
5869 *pcond = ne;
5870
5871 // Set *PITER_INIT to
5872 // mapiter1(hiter, &index_temp)
5873 // or
5874 // mapiter2(hiter, &index_temp, &value_temp)
5875
5876 Block* iter_init = new Block(body_block, loc);
5877
5878 ref = Expression::make_temporary_reference(hiter, loc);
5879 p1 = Expression::make_unary(OPERATOR_AND, ref, loc);
5880 ref = Expression::make_temporary_reference(index_temp, loc);
5881 p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
5882 if (value_temp == NULL)
5883 call = Runtime::make_call(Runtime::MAPITER1, loc, 2, p1, p2);
5884 else
5885 {
5886 ref = Expression::make_temporary_reference(value_temp, loc);
5887 Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
5888 call = Runtime::make_call(Runtime::MAPITER2, loc, 3, p1, p2, p3);
5889 }
5890 iter_init->add_statement(Statement::make_statement(call, true));
5891
5892 *piter_init = iter_init;
5893
5894 // Set *PPOST to
5895 // mapiternext(&hiter)
5896
5897 Block* post = new Block(enclosing, loc);
5898
5899 ref = Expression::make_temporary_reference(hiter, loc);
5900 p1 = Expression::make_unary(OPERATOR_AND, ref, loc);
5901 call = Runtime::make_call(Runtime::MAPITERNEXT, loc, 1, p1);
5902 post->add_statement(Statement::make_statement(call, true));
5903
5904 *ppost = post;
5905 }
5906
5907 // Lower a for range over a channel.
5908
5909 void
lower_range_channel(Gogo *,Block *,Block * body_block,Named_object * range_object,Temporary_statement * range_temp,Temporary_statement * index_temp,Temporary_statement * value_temp,Block ** pinit,Expression ** pcond,Block ** piter_init,Block ** ppost)5910 For_range_statement::lower_range_channel(Gogo*,
5911 Block*,
5912 Block* body_block,
5913 Named_object* range_object,
5914 Temporary_statement* range_temp,
5915 Temporary_statement* index_temp,
5916 Temporary_statement* value_temp,
5917 Block** pinit,
5918 Expression** pcond,
5919 Block** piter_init,
5920 Block** ppost)
5921 {
5922 go_assert(value_temp == NULL);
5923
5924 Location loc = this->location();
5925
5926 // The loop we generate:
5927 // for {
5928 // index_temp, ok_temp = <-range
5929 // if !ok_temp {
5930 // break
5931 // }
5932 // index = index_temp
5933 // original body
5934 // }
5935
5936 // We have no initialization code, no condition, and no post code.
5937
5938 *pinit = NULL;
5939 *pcond = NULL;
5940 *ppost = NULL;
5941
5942 // Set *PITER_INIT to
5943 // index_temp, ok_temp = <-range
5944 // if !ok_temp {
5945 // break
5946 // }
5947
5948 Block* iter_init = new Block(body_block, loc);
5949
5950 Temporary_statement* ok_temp =
5951 Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
5952 iter_init->add_statement(ok_temp);
5953
5954 Expression* cref = this->make_range_ref(range_object, range_temp, loc);
5955 Temporary_reference_expression* iref =
5956 Expression::make_temporary_reference(index_temp, loc);
5957 iref->set_is_lvalue();
5958 Temporary_reference_expression* oref =
5959 Expression::make_temporary_reference(ok_temp, loc);
5960 oref->set_is_lvalue();
5961 Statement* s = Statement::make_tuple_receive_assignment(iref, oref, cref,
5962 loc);
5963 iter_init->add_statement(s);
5964
5965 Block* then_block = new Block(iter_init, loc);
5966 s = Statement::make_break_statement(this->break_label(), loc);
5967 then_block->add_statement(s);
5968
5969 oref = Expression::make_temporary_reference(ok_temp, loc);
5970 Expression* cond = Expression::make_unary(OPERATOR_NOT, oref, loc);
5971 s = Statement::make_if_statement(cond, then_block, NULL, loc);
5972 iter_init->add_statement(s);
5973
5974 *piter_init = iter_init;
5975 }
5976
5977 // Return the break LABEL_EXPR.
5978
5979 Unnamed_label*
break_label()5980 For_range_statement::break_label()
5981 {
5982 if (this->break_label_ == NULL)
5983 this->break_label_ = new Unnamed_label(this->location());
5984 return this->break_label_;
5985 }
5986
5987 // Return the continue LABEL_EXPR.
5988
5989 Unnamed_label*
continue_label()5990 For_range_statement::continue_label()
5991 {
5992 if (this->continue_label_ == NULL)
5993 this->continue_label_ = new Unnamed_label(this->location());
5994 return this->continue_label_;
5995 }
5996
5997 // Dump the AST representation for a for range statement.
5998
5999 void
do_dump_statement(Ast_dump_context * ast_dump_context) const6000 For_range_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
6001 {
6002
6003 ast_dump_context->print_indent();
6004 ast_dump_context->ostream() << "for ";
6005 ast_dump_context->dump_expression(this->index_var_);
6006 if (this->value_var_ != NULL)
6007 {
6008 ast_dump_context->ostream() << ", ";
6009 ast_dump_context->dump_expression(this->value_var_);
6010 }
6011
6012 ast_dump_context->ostream() << " = range ";
6013 ast_dump_context->dump_expression(this->range_);
6014 if (ast_dump_context->dump_subblocks())
6015 {
6016 ast_dump_context->ostream() << " {" << std::endl;
6017
6018 ast_dump_context->indent();
6019
6020 ast_dump_context->dump_block(this->statements_);
6021
6022 ast_dump_context->unindent();
6023 ast_dump_context->print_indent();
6024 ast_dump_context->ostream() << "}";
6025 }
6026 ast_dump_context->ostream() << std::endl;
6027 }
6028
6029 // Make a for statement with a range clause.
6030
6031 For_range_statement*
make_for_range_statement(Expression * index_var,Expression * value_var,Expression * range,Location location)6032 Statement::make_for_range_statement(Expression* index_var,
6033 Expression* value_var,
6034 Expression* range,
6035 Location location)
6036 {
6037 return new For_range_statement(index_var, value_var, range, location);
6038 }
6039