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