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