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