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_multi_eval_safe())
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_multi_eval_safe())
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 // var ok_temp bool
1989 Temporary_statement* ok_temp = NULL;
1990 if (!this->ok_->is_sink_expression())
1991 {
1992 ok_temp = Statement::make_temporary(this->ok_->type(),
1993 NULL, loc);
1994 b->add_statement(ok_temp);
1995 }
1996
1997 // ok_temp = CODE(type_descriptor, expr, &val_temp)
1998 Expression* p1 = Expression::make_type_descriptor(this->type_, loc);
1999 Expression* ref = Expression::make_temporary_reference(val_temp, loc);
2000 Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
2001 Expression* call = Runtime::make_call(code, loc, 3, p1, this->expr_, p3);
2002 Statement* s;
2003 if (ok_temp == NULL)
2004 s = Statement::make_statement(call, true);
2005 else
2006 {
2007 Expression* ok_ref = Expression::make_temporary_reference(ok_temp, loc);
2008 s = Statement::make_assignment(ok_ref, call, loc);
2009 }
2010 b->add_statement(s);
2011
2012 // val = val_temp
2013 ref = Expression::make_temporary_reference(val_temp, loc);
2014 s = Statement::make_assignment(this->val_, ref, loc);
2015 b->add_statement(s);
2016
2017 // ok = ok_temp
2018 if (ok_temp != NULL)
2019 {
2020 ref = Expression::make_temporary_reference(ok_temp, loc);
2021 s = Statement::make_assignment(this->ok_, ref, loc);
2022 b->add_statement(s);
2023 }
2024 }
2025
2026 // Dump the AST representation for a tuple type guard statement.
2027
2028 void
do_dump_statement(Ast_dump_context * ast_dump_context) const2029 Tuple_type_guard_assignment_statement::do_dump_statement(
2030 Ast_dump_context* ast_dump_context) const
2031 {
2032 ast_dump_context->print_indent();
2033 ast_dump_context->dump_expression(this->val_);
2034 ast_dump_context->ostream() << ", ";
2035 ast_dump_context->dump_expression(this->ok_);
2036 ast_dump_context->ostream() << " = ";
2037 ast_dump_context->dump_expression(this->expr_);
2038 ast_dump_context->ostream() << " . ";
2039 ast_dump_context->dump_type(this->type_);
2040 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
2041 }
2042
2043 // Make an assignment from a type guard to a pair of variables.
2044
2045 Statement*
make_tuple_type_guard_assignment(Expression * val,Expression * ok,Expression * expr,Type * type,Location location)2046 Statement::make_tuple_type_guard_assignment(Expression* val, Expression* ok,
2047 Expression* expr, Type* type,
2048 Location location)
2049 {
2050 return new Tuple_type_guard_assignment_statement(val, ok, expr, type,
2051 location);
2052 }
2053
2054 // Class Expression_statement.
2055
2056 // Constructor.
2057
Expression_statement(Expression * expr,bool is_ignored)2058 Expression_statement::Expression_statement(Expression* expr, bool is_ignored)
2059 : Statement(STATEMENT_EXPRESSION, expr->location()),
2060 expr_(expr), is_ignored_(is_ignored)
2061 {
2062 }
2063
2064 // Determine types.
2065
2066 void
do_determine_types()2067 Expression_statement::do_determine_types()
2068 {
2069 this->expr_->determine_type_no_context();
2070 }
2071
2072 // Check the types of an expression statement. The only check we do
2073 // is to possibly give an error about discarding the value of the
2074 // expression.
2075
2076 void
do_check_types(Gogo *)2077 Expression_statement::do_check_types(Gogo*)
2078 {
2079 if (!this->is_ignored_)
2080 this->expr_->discarding_value();
2081 }
2082
2083 // An expression statement is only a terminating statement if it is
2084 // a call to panic.
2085
2086 bool
do_may_fall_through() const2087 Expression_statement::do_may_fall_through() const
2088 {
2089 const Call_expression* call = this->expr_->call_expression();
2090 if (call != NULL)
2091 {
2092 const Expression* fn = call->fn();
2093 // panic is still an unknown named object.
2094 const Unknown_expression* ue = fn->unknown_expression();
2095 if (ue != NULL)
2096 {
2097 Named_object* no = ue->named_object();
2098
2099 if (no->is_unknown())
2100 no = no->unknown_value()->real_named_object();
2101 if (no != NULL)
2102 {
2103 Function_type* fntype;
2104 if (no->is_function())
2105 fntype = no->func_value()->type();
2106 else if (no->is_function_declaration())
2107 fntype = no->func_declaration_value()->type();
2108 else
2109 fntype = NULL;
2110
2111 // The builtin function panic does not return.
2112 if (fntype != NULL && fntype->is_builtin() && no->name() == "panic")
2113 return false;
2114 }
2115 }
2116 }
2117 return true;
2118 }
2119
2120 // Export an expression statement.
2121
2122 void
do_export_statement(Export_function_body * efb)2123 Expression_statement::do_export_statement(Export_function_body* efb)
2124 {
2125 this->expr_->export_expression(efb);
2126 }
2127
2128 // Convert to backend representation.
2129
2130 Bstatement*
do_get_backend(Translate_context * context)2131 Expression_statement::do_get_backend(Translate_context* context)
2132 {
2133 Bexpression* bexpr = this->expr_->get_backend(context);
2134 Bfunction* bfunction = context->function()->func_value()->get_decl();
2135 return context->backend()->expression_statement(bfunction, bexpr);
2136 }
2137
2138 // Dump the AST representation for an expression statement
2139
2140 void
do_dump_statement(Ast_dump_context * ast_dump_context) const2141 Expression_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
2142 const
2143 {
2144 ast_dump_context->print_indent();
2145 ast_dump_context->dump_expression(expr_);
2146 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
2147 }
2148
2149 // Make an expression statement from an Expression.
2150
2151 Statement*
make_statement(Expression * expr,bool is_ignored)2152 Statement::make_statement(Expression* expr, bool is_ignored)
2153 {
2154 return new Expression_statement(expr, is_ignored);
2155 }
2156
2157 // Export data for a block.
2158
2159 void
do_export_statement(Export_function_body * efb)2160 Block_statement::do_export_statement(Export_function_body* efb)
2161 {
2162 Block_statement::export_block(efb, this->block_,
2163 this->is_lowered_for_statement_);
2164 }
2165
2166 void
export_block(Export_function_body * efb,Block * block,bool is_lowered_for_statement)2167 Block_statement::export_block(Export_function_body* efb, Block* block,
2168 bool is_lowered_for_statement)
2169 {
2170 // We are already indented to the right position.
2171 char buf[50];
2172 efb->write_c_string("{");
2173 if (is_lowered_for_statement)
2174 efb->write_c_string(" /*for*/");
2175 snprintf(buf, sizeof buf, " //%d\n",
2176 Linemap::location_to_line(block->start_location()));
2177 efb->write_c_string(buf);
2178
2179 block->export_block(efb);
2180 // The indentation is correct for the statements in the block, so
2181 // subtract one for the closing curly brace.
2182 efb->decrement_indent();
2183 efb->indent();
2184 efb->write_c_string("}");
2185 // Increment back to the value the caller thinks it has.
2186 efb->increment_indent();
2187 }
2188
2189 // Import a block statement, returning the block.
2190
2191 Block*
do_import(Import_function_body * ifb,Location loc,bool * is_lowered_for_statement)2192 Block_statement::do_import(Import_function_body* ifb, Location loc,
2193 bool* is_lowered_for_statement)
2194 {
2195 go_assert(ifb->match_c_string("{"));
2196 *is_lowered_for_statement = false;
2197 if (ifb->match_c_string(" /*for*/"))
2198 {
2199 ifb->advance(8);
2200 *is_lowered_for_statement = true;
2201 }
2202 size_t nl = ifb->body().find('\n', ifb->off());
2203 if (nl == std::string::npos)
2204 {
2205 if (!ifb->saw_error())
2206 go_error_at(ifb->location(),
2207 "import error: no newline after %<{%> at %lu",
2208 static_cast<unsigned long>(ifb->off()));
2209 ifb->set_saw_error();
2210 return NULL;
2211 }
2212 ifb->set_off(nl + 1);
2213 ifb->increment_indent();
2214 Block* block = new Block(ifb->block(), loc);
2215 ifb->begin_block(block);
2216 bool ok = Block::import_block(block, ifb, loc);
2217 ifb->finish_block();
2218 ifb->decrement_indent();
2219 if (!ok)
2220 return NULL;
2221 return block;
2222 }
2223
2224 // Convert a block to the backend representation of a statement.
2225
2226 Bstatement*
do_get_backend(Translate_context * context)2227 Block_statement::do_get_backend(Translate_context* context)
2228 {
2229 Bblock* bblock = this->block_->get_backend(context);
2230 return context->backend()->block_statement(bblock);
2231 }
2232
2233 // Dump the AST for a block statement
2234
2235 void
do_dump_statement(Ast_dump_context *) const2236 Block_statement::do_dump_statement(Ast_dump_context*) const
2237 {
2238 // block statement braces are dumped when traversing.
2239 }
2240
2241 // Make a block statement.
2242
2243 Block_statement*
make_block_statement(Block * block,Location location)2244 Statement::make_block_statement(Block* block, Location location)
2245 {
2246 return new Block_statement(block, location);
2247 }
2248
2249 // An increment or decrement statement.
2250
2251 class Inc_dec_statement : public Statement
2252 {
2253 public:
Inc_dec_statement(bool is_inc,Expression * expr)2254 Inc_dec_statement(bool is_inc, Expression* expr)
2255 : Statement(STATEMENT_INCDEC, expr->location()),
2256 expr_(expr), is_inc_(is_inc)
2257 { }
2258
2259 protected:
2260 int
do_traverse(Traverse * traverse)2261 do_traverse(Traverse* traverse)
2262 { return this->traverse_expression(traverse, &this->expr_); }
2263
2264 bool
do_traverse_assignments(Traverse_assignments *)2265 do_traverse_assignments(Traverse_assignments*)
2266 { go_unreachable(); }
2267
2268 Statement*
2269 do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
2270
2271 Bstatement*
do_get_backend(Translate_context *)2272 do_get_backend(Translate_context*)
2273 { go_unreachable(); }
2274
2275 void
2276 do_dump_statement(Ast_dump_context*) const;
2277
2278 private:
2279 // The l-value to increment or decrement.
2280 Expression* expr_;
2281 // Whether to increment or decrement.
2282 bool is_inc_;
2283 };
2284
2285 // Lower to += or -=.
2286
2287 Statement*
do_lower(Gogo *,Named_object *,Block *,Statement_inserter *)2288 Inc_dec_statement::do_lower(Gogo*, Named_object*, Block*, Statement_inserter*)
2289 {
2290 Location loc = this->location();
2291 if (!this->expr_->type()->is_numeric_type())
2292 {
2293 this->report_error("increment or decrement of non-numeric type");
2294 return Statement::make_error_statement(loc);
2295 }
2296 Expression* oexpr = Expression::make_integer_ul(1, this->expr_->type(), loc);
2297 Operator op = this->is_inc_ ? OPERATOR_PLUSEQ : OPERATOR_MINUSEQ;
2298 return Statement::make_assignment_operation(op, this->expr_, oexpr, loc);
2299 }
2300
2301 // Dump the AST representation for a inc/dec statement.
2302
2303 void
do_dump_statement(Ast_dump_context * ast_dump_context) const2304 Inc_dec_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
2305 {
2306 ast_dump_context->print_indent();
2307 ast_dump_context->dump_expression(expr_);
2308 ast_dump_context->ostream() << (is_inc_? "++": "--") << dsuffix(location()) << std::endl;
2309 }
2310
2311 // Make an increment statement.
2312
2313 Statement*
make_inc_statement(Expression * expr)2314 Statement::make_inc_statement(Expression* expr)
2315 {
2316 return new Inc_dec_statement(true, expr);
2317 }
2318
2319 // Make a decrement statement.
2320
2321 Statement*
make_dec_statement(Expression * expr)2322 Statement::make_dec_statement(Expression* expr)
2323 {
2324 return new Inc_dec_statement(false, expr);
2325 }
2326
2327 // Class Thunk_statement. This is the base class for go and defer
2328 // statements.
2329
2330 // Constructor.
2331
Thunk_statement(Statement_classification classification,Call_expression * call,Location location)2332 Thunk_statement::Thunk_statement(Statement_classification classification,
2333 Call_expression* call,
2334 Location location)
2335 : Statement(classification, location),
2336 call_(call), struct_type_(NULL)
2337 {
2338 }
2339
2340 // Return whether this is a simple statement which does not require a
2341 // thunk.
2342
2343 bool
is_simple(Function_type * fntype) const2344 Thunk_statement::is_simple(Function_type* fntype) const
2345 {
2346 // We need a thunk to call a method, or to pass a variable number of
2347 // arguments.
2348 if (fntype->is_method() || fntype->is_varargs())
2349 return false;
2350
2351 // A defer statement requires a thunk to set up for whether the
2352 // function can call recover.
2353 if (this->classification() == STATEMENT_DEFER)
2354 return false;
2355
2356 // We can only permit a single parameter of pointer type.
2357 const Typed_identifier_list* parameters = fntype->parameters();
2358 if (parameters != NULL
2359 && (parameters->size() > 1
2360 || (parameters->size() == 1
2361 && parameters->begin()->type()->points_to() == NULL)))
2362 return false;
2363
2364 // If the function returns multiple values, or returns a type other
2365 // than integer, floating point, or pointer, then it may get a
2366 // hidden first parameter, in which case we need the more
2367 // complicated approach. This is true even though we are going to
2368 // ignore the return value.
2369 const Typed_identifier_list* results = fntype->results();
2370 if (results != NULL
2371 && (results->size() > 1
2372 || (results->size() == 1
2373 && !results->begin()->type()->is_basic_type()
2374 && results->begin()->type()->points_to() == NULL)))
2375 return false;
2376
2377 // If this calls something that is not a simple function, then we
2378 // need a thunk.
2379 Expression* fn = this->call_->call_expression()->fn();
2380 if (fn->func_expression() == NULL)
2381 return false;
2382
2383 // If the function uses a closure, then we need a thunk. FIXME: We
2384 // could accept a zero argument function with a closure.
2385 if (fn->func_expression()->closure() != NULL)
2386 return false;
2387
2388 return true;
2389 }
2390
2391 // Traverse a thunk statement.
2392
2393 int
do_traverse(Traverse * traverse)2394 Thunk_statement::do_traverse(Traverse* traverse)
2395 {
2396 return this->traverse_expression(traverse, &this->call_);
2397 }
2398
2399 // We implement traverse_assignment for a thunk statement because it
2400 // effectively copies the function call.
2401
2402 bool
do_traverse_assignments(Traverse_assignments * tassign)2403 Thunk_statement::do_traverse_assignments(Traverse_assignments* tassign)
2404 {
2405 Expression* fn = this->call_->call_expression()->fn();
2406 Expression* fn2 = fn;
2407 tassign->value(&fn2, true, false);
2408 return true;
2409 }
2410
2411 // Determine types in a thunk statement.
2412
2413 void
do_determine_types()2414 Thunk_statement::do_determine_types()
2415 {
2416 this->call_->determine_type_no_context();
2417
2418 // Now that we know the types of the call, build the struct used to
2419 // pass parameters.
2420 Call_expression* ce = this->call_->call_expression();
2421 if (ce == NULL)
2422 return;
2423 Function_type* fntype = ce->get_function_type();
2424 if (fntype != NULL && !this->is_simple(fntype))
2425 this->struct_type_ = this->build_struct(fntype);
2426 }
2427
2428 // Check types in a thunk statement.
2429
2430 void
do_check_types(Gogo *)2431 Thunk_statement::do_check_types(Gogo*)
2432 {
2433 if (!this->call_->discarding_value())
2434 return;
2435 Call_expression* ce = this->call_->call_expression();
2436 if (ce == NULL)
2437 {
2438 if (!this->call_->is_error_expression())
2439 this->report_error("expected call expression");
2440 return;
2441 }
2442 }
2443
2444 // The Traverse class used to find and simplify thunk statements.
2445
2446 class Simplify_thunk_traverse : public Traverse
2447 {
2448 public:
Simplify_thunk_traverse(Gogo * gogo)2449 Simplify_thunk_traverse(Gogo* gogo)
2450 : Traverse(traverse_functions | traverse_blocks),
2451 gogo_(gogo), function_(NULL)
2452 { }
2453
2454 int
2455 function(Named_object*);
2456
2457 int
2458 block(Block*);
2459
2460 private:
2461 // General IR.
2462 Gogo* gogo_;
2463 // The function we are traversing.
2464 Named_object* function_;
2465 };
2466
2467 // Keep track of the current function while looking for thunks.
2468
2469 int
function(Named_object * no)2470 Simplify_thunk_traverse::function(Named_object* no)
2471 {
2472 go_assert(this->function_ == NULL);
2473 this->function_ = no;
2474 int t = no->func_value()->traverse(this);
2475 this->function_ = NULL;
2476 if (t == TRAVERSE_EXIT)
2477 return t;
2478 return TRAVERSE_SKIP_COMPONENTS;
2479 }
2480
2481 // Look for thunks in a block.
2482
2483 int
block(Block * b)2484 Simplify_thunk_traverse::block(Block* b)
2485 {
2486 // The parser ensures that thunk statements always appear at the end
2487 // of a block.
2488 if (b->statements()->size() < 1)
2489 return TRAVERSE_CONTINUE;
2490 Thunk_statement* stat = b->statements()->back()->thunk_statement();
2491 if (stat == NULL)
2492 return TRAVERSE_CONTINUE;
2493 if (stat->simplify_statement(this->gogo_, this->function_, b))
2494 return TRAVERSE_SKIP_COMPONENTS;
2495 return TRAVERSE_CONTINUE;
2496 }
2497
2498 // Simplify all thunk statements.
2499
2500 void
simplify_thunk_statements()2501 Gogo::simplify_thunk_statements()
2502 {
2503 Simplify_thunk_traverse thunk_traverse(this);
2504 this->traverse(&thunk_traverse);
2505 }
2506
2507 // Return true if the thunk function is a constant, which means that
2508 // it does not need to be passed to the thunk routine.
2509
2510 bool
is_constant_function() const2511 Thunk_statement::is_constant_function() const
2512 {
2513 Call_expression* ce = this->call_->call_expression();
2514 Function_type* fntype = ce->get_function_type();
2515 if (fntype == NULL)
2516 {
2517 go_assert(saw_errors());
2518 return false;
2519 }
2520 if (fntype->is_builtin())
2521 return true;
2522 Expression* fn = ce->fn();
2523 if (fn->func_expression() != NULL)
2524 return fn->func_expression()->closure() == NULL;
2525 if (fn->interface_field_reference_expression() != NULL)
2526 return true;
2527 if (fn->bound_method_expression() != NULL)
2528 return true;
2529 return false;
2530 }
2531
2532 // Simplify complex thunk statements into simple ones. A complicated
2533 // thunk statement is one which takes anything other than zero
2534 // parameters or a single pointer parameter. We rewrite it into code
2535 // which allocates a struct, stores the parameter values into the
2536 // struct, and does a simple go or defer statement which passes the
2537 // struct to a thunk. The thunk does the real call.
2538
2539 bool
simplify_statement(Gogo * gogo,Named_object * function,Block * block)2540 Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
2541 Block* block)
2542 {
2543 if (this->classification() == STATEMENT_ERROR)
2544 return false;
2545 if (this->call_->is_error_expression())
2546 return false;
2547
2548 if (this->classification() == STATEMENT_DEFER)
2549 {
2550 // Make sure that the defer stack exists for the function. We
2551 // will use when converting this statement to the backend
2552 // representation, but we want it to exist when we start
2553 // converting the function.
2554 function->func_value()->defer_stack(this->location());
2555 }
2556
2557 Call_expression* ce = this->call_->call_expression();
2558 Function_type* fntype = ce->get_function_type();
2559 if (fntype == NULL)
2560 {
2561 go_assert(saw_errors());
2562 this->set_is_error();
2563 return false;
2564 }
2565 if (this->is_simple(fntype))
2566 return false;
2567
2568 Expression* fn = ce->fn();
2569 Interface_field_reference_expression* interface_method =
2570 fn->interface_field_reference_expression();
2571 Bound_method_expression* bme = fn->bound_method_expression();
2572
2573 Location location = this->location();
2574
2575 bool is_constant_function = this->is_constant_function();
2576 Temporary_statement* fn_temp = NULL;
2577 if (!is_constant_function)
2578 {
2579 fn_temp = Statement::make_temporary(NULL, fn, location);
2580 block->insert_statement_before(block->statements()->size() - 1, fn_temp);
2581 fn = Expression::make_temporary_reference(fn_temp, location);
2582 }
2583
2584 std::string thunk_name = gogo->thunk_name();
2585
2586 // Build the thunk.
2587 this->build_thunk(gogo, thunk_name);
2588
2589 // Generate code to call the thunk.
2590
2591 // Get the values to store into the struct which is the single
2592 // argument to the thunk.
2593
2594 Expression_list* vals = new Expression_list();
2595 if (!is_constant_function)
2596 vals->push_back(fn);
2597
2598 if (interface_method != NULL)
2599 vals->push_back(interface_method->expr());
2600 if (bme != NULL)
2601 vals->push_back(bme->first_argument());
2602
2603 if (ce->args() != NULL)
2604 {
2605 for (Expression_list::const_iterator p = ce->args()->begin();
2606 p != ce->args()->end();
2607 ++p)
2608 {
2609 if ((*p)->is_constant())
2610 continue;
2611 vals->push_back(*p);
2612 }
2613 }
2614
2615 // Build the struct.
2616 Expression* constructor =
2617 Expression::make_struct_composite_literal(this->struct_type_, vals,
2618 location);
2619
2620 // Allocate the initialized struct on the heap.
2621 constructor = Expression::make_heap_expression(constructor, location);
2622 if ((Node::make_node(this)->encoding() & ESCAPE_MASK) == Node::ESCAPE_NONE)
2623 constructor->heap_expression()->set_allocate_on_stack();
2624
2625 // Throw an error if the function is nil. This is so that for `go
2626 // nil` we get a backtrace from the go statement, rather than a
2627 // useless backtrace from the brand new goroutine.
2628 Expression* param = constructor;
2629 if (!is_constant_function && this->classification() == STATEMENT_GO)
2630 {
2631 fn = Expression::make_temporary_reference(fn_temp, location);
2632 Expression* nil = Expression::make_nil(location);
2633 Expression* isnil = Expression::make_binary(OPERATOR_EQEQ, fn, nil,
2634 location);
2635 Expression* crash = Runtime::make_call(Runtime::PANIC_GO_NIL,
2636 location, 0);
2637 crash = Expression::make_conditional(isnil, crash,
2638 Expression::make_nil(location),
2639 location);
2640 param = Expression::make_compound(crash, constructor, location);
2641 }
2642
2643 // Look up the thunk.
2644 Named_object* named_thunk = gogo->lookup(thunk_name, NULL);
2645 go_assert(named_thunk != NULL && named_thunk->is_function());
2646
2647 // Build the call.
2648 Expression* func = Expression::make_func_reference(named_thunk, NULL,
2649 location);
2650 Expression_list* params = new Expression_list();
2651 params->push_back(param);
2652 Call_expression* call = Expression::make_call(func, params, false, location);
2653
2654 // Build the simple go or defer statement.
2655 Statement* s;
2656 if (this->classification() == STATEMENT_GO)
2657 s = Statement::make_go_statement(call, location);
2658 else if (this->classification() == STATEMENT_DEFER)
2659 {
2660 s = Statement::make_defer_statement(call, location);
2661 if ((Node::make_node(this)->encoding() & ESCAPE_MASK) == Node::ESCAPE_NONE)
2662 s->defer_statement()->set_on_stack();
2663 }
2664 else
2665 go_unreachable();
2666
2667 // The current block should end with the go statement.
2668 go_assert(block->statements()->size() >= 1);
2669 go_assert(block->statements()->back() == this);
2670 block->replace_statement(block->statements()->size() - 1, s);
2671
2672 // We already ran the determine_types pass, so we need to run it now
2673 // for the new statement.
2674 s->determine_types();
2675
2676 // Sanity check.
2677 gogo->check_types_in_block(block);
2678
2679 // Return true to tell the block not to keep looking at statements.
2680 return true;
2681 }
2682
2683 // Set the name to use for thunk parameter N.
2684
2685 void
thunk_field_param(int n,char * buf,size_t buflen)2686 Thunk_statement::thunk_field_param(int n, char* buf, size_t buflen)
2687 {
2688 snprintf(buf, buflen, "a%d", n);
2689 }
2690
2691 // Build a new struct type to hold the parameters for a complicated
2692 // thunk statement. FNTYPE is the type of the function call.
2693
2694 Struct_type*
build_struct(Function_type * fntype)2695 Thunk_statement::build_struct(Function_type* fntype)
2696 {
2697 Location location = this->location();
2698
2699 Struct_field_list* fields = new Struct_field_list();
2700
2701 Call_expression* ce = this->call_->call_expression();
2702 Expression* fn = ce->fn();
2703
2704 if (!this->is_constant_function())
2705 {
2706 // The function to call.
2707 fields->push_back(Struct_field(Typed_identifier("fn", fntype,
2708 location)));
2709 }
2710
2711 // If this thunk statement calls a method on an interface, we pass
2712 // the interface object to the thunk.
2713 Interface_field_reference_expression* interface_method =
2714 fn->interface_field_reference_expression();
2715 if (interface_method != NULL)
2716 {
2717 Typed_identifier tid("object", interface_method->expr()->type(),
2718 location);
2719 fields->push_back(Struct_field(tid));
2720 }
2721
2722 // If this thunk statement calls a bound method expression, as in
2723 // "go s.m()", we pass the bound method argument to the thunk,
2724 // to ensure that we make a copy of it if needed.
2725 Bound_method_expression* bme = fn->bound_method_expression();
2726 if (bme != NULL)
2727 {
2728 Typed_identifier tid("object", bme->first_argument()->type(), location);
2729 fields->push_back(Struct_field(tid));
2730 }
2731
2732 // The predeclared recover function has no argument. However, we
2733 // add an argument when building recover thunks. Handle that here.
2734 if (ce->is_recover_call())
2735 {
2736 fields->push_back(Struct_field(Typed_identifier("can_recover",
2737 Type::lookup_bool_type(),
2738 location)));
2739 }
2740
2741 const Expression_list* args = ce->args();
2742 if (args != NULL)
2743 {
2744 int i = 0;
2745 for (Expression_list::const_iterator p = args->begin();
2746 p != args->end();
2747 ++p, ++i)
2748 {
2749 if ((*p)->is_constant())
2750 continue;
2751
2752 char buf[50];
2753 this->thunk_field_param(i, buf, sizeof buf);
2754 fields->push_back(Struct_field(Typed_identifier(buf, (*p)->type(),
2755 location)));
2756 }
2757 }
2758
2759 Struct_type *st = Type::make_struct_type(fields, location);
2760 st->set_is_struct_incomparable();
2761 return st;
2762 }
2763
2764 // Build the thunk we are going to call. This is a brand new, albeit
2765 // artificial, function.
2766
2767 void
build_thunk(Gogo * gogo,const std::string & thunk_name)2768 Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
2769 {
2770 Location location = this->location();
2771
2772 Call_expression* ce = this->call_->call_expression();
2773
2774 bool may_call_recover = false;
2775 if (this->classification() == STATEMENT_DEFER)
2776 {
2777 Func_expression* fn = ce->fn()->func_expression();
2778 if (fn == NULL)
2779 may_call_recover = true;
2780 else
2781 {
2782 const Named_object* no = fn->named_object();
2783 if (!no->is_function())
2784 may_call_recover = true;
2785 else
2786 may_call_recover = no->func_value()->calls_recover();
2787 }
2788 }
2789
2790 // Build the type of the thunk. The thunk takes a single parameter,
2791 // which is a pointer to the special structure we build.
2792 const char* const parameter_name = "__go_thunk_parameter";
2793 Typed_identifier_list* thunk_parameters = new Typed_identifier_list();
2794 Type* pointer_to_struct_type = Type::make_pointer_type(this->struct_type_);
2795 thunk_parameters->push_back(Typed_identifier(parameter_name,
2796 pointer_to_struct_type,
2797 location));
2798
2799 Typed_identifier_list* thunk_results = NULL;
2800 if (may_call_recover)
2801 {
2802 // When deferring a function which may call recover, add a
2803 // return value, to disable tail call optimizations which will
2804 // break the way we check whether recover is permitted.
2805 thunk_results = new Typed_identifier_list();
2806 thunk_results->push_back(Typed_identifier("", Type::lookup_bool_type(),
2807 location));
2808 }
2809
2810 Function_type* thunk_type = Type::make_function_type(NULL, thunk_parameters,
2811 thunk_results,
2812 location);
2813
2814 // Start building the thunk.
2815 Named_object* function = gogo->start_function(thunk_name, thunk_type, true,
2816 location);
2817
2818 gogo->start_block(location);
2819
2820 // For a defer statement, start with a call to
2821 // __go_set_defer_retaddr. */
2822 Label* retaddr_label = NULL;
2823 if (may_call_recover)
2824 {
2825 retaddr_label = gogo->add_label_reference("retaddr", location, false);
2826 Expression* arg = Expression::make_label_addr(retaddr_label, location);
2827 Expression* call = Runtime::make_call(Runtime::SETDEFERRETADDR,
2828 location, 1, arg);
2829
2830 // This is a hack to prevent the middle-end from deleting the
2831 // label.
2832 gogo->start_block(location);
2833 gogo->add_statement(Statement::make_goto_statement(retaddr_label,
2834 location));
2835 Block* then_block = gogo->finish_block(location);
2836 then_block->determine_types();
2837
2838 Statement* s = Statement::make_if_statement(call, then_block, NULL,
2839 location);
2840 s->determine_types();
2841 gogo->add_statement(s);
2842
2843 function->func_value()->set_calls_defer_retaddr();
2844 }
2845
2846 // Get a reference to the parameter.
2847 Named_object* named_parameter = gogo->lookup(parameter_name, NULL);
2848 go_assert(named_parameter != NULL && named_parameter->is_variable());
2849
2850 // Build the call. Note that the field names are the same as the
2851 // ones used in build_struct.
2852 Expression* thunk_parameter = Expression::make_var_reference(named_parameter,
2853 location);
2854 thunk_parameter =
2855 Expression::make_dereference(thunk_parameter,
2856 Expression::NIL_CHECK_NOT_NEEDED,
2857 location);
2858
2859 Interface_field_reference_expression* interface_method =
2860 ce->fn()->interface_field_reference_expression();
2861 Bound_method_expression* bme = ce->fn()->bound_method_expression();
2862
2863 Expression* func_to_call;
2864 unsigned int next_index;
2865 if (this->is_constant_function())
2866 {
2867 func_to_call = ce->fn();
2868 next_index = 0;
2869 }
2870 else
2871 {
2872 func_to_call = Expression::make_field_reference(thunk_parameter,
2873 0, location);
2874 next_index = 1;
2875 }
2876
2877 if (interface_method != NULL)
2878 {
2879 // The main program passes the interface object.
2880 go_assert(next_index == 0);
2881 Expression* r = Expression::make_field_reference(thunk_parameter, 0,
2882 location);
2883 const std::string& name(interface_method->name());
2884 func_to_call = Expression::make_interface_field_reference(r, name,
2885 location);
2886 next_index = 1;
2887 }
2888
2889 if (bme != NULL)
2890 {
2891 // This is a call to a method.
2892 go_assert(next_index == 0);
2893 Expression* r = Expression::make_field_reference(thunk_parameter, 0,
2894 location);
2895 func_to_call = Expression::make_bound_method(r, bme->method(),
2896 bme->function(), location);
2897 next_index = 1;
2898 }
2899
2900 Expression_list* call_params = new Expression_list();
2901 const Struct_field_list* fields = this->struct_type_->fields();
2902 Struct_field_list::const_iterator p = fields->begin();
2903 for (unsigned int i = 0; i < next_index; ++i)
2904 ++p;
2905 bool is_recover_call = ce->is_recover_call();
2906 Expression* recover_arg = NULL;
2907
2908 const Expression_list* args = ce->args();
2909 if (args != NULL)
2910 {
2911 for (Expression_list::const_iterator arg = args->begin();
2912 arg != args->end();
2913 ++arg)
2914 {
2915 Expression* param;
2916 if ((*arg)->is_constant())
2917 param = *arg;
2918 else
2919 {
2920 Expression* thunk_param =
2921 Expression::make_var_reference(named_parameter, location);
2922 thunk_param =
2923 Expression::make_dereference(thunk_param,
2924 Expression::NIL_CHECK_NOT_NEEDED,
2925 location);
2926 param = Expression::make_field_reference(thunk_param,
2927 next_index,
2928 location);
2929 ++next_index;
2930 }
2931
2932 if (!is_recover_call)
2933 call_params->push_back(param);
2934 else
2935 {
2936 go_assert(call_params->empty());
2937 recover_arg = param;
2938 }
2939 }
2940 }
2941
2942 if (call_params->empty())
2943 {
2944 delete call_params;
2945 call_params = NULL;
2946 }
2947
2948 Call_expression* call = Expression::make_call(func_to_call, call_params,
2949 false, location);
2950
2951 // This call expression was already lowered before entering the
2952 // thunk statement. Don't try to lower varargs again, as that will
2953 // cause confusion for, e.g., method calls which already have a
2954 // receiver parameter.
2955 call->set_varargs_are_lowered();
2956
2957 Statement* call_statement = Statement::make_statement(call, true);
2958
2959 gogo->add_statement(call_statement);
2960
2961 // If this is a defer statement, the label comes immediately after
2962 // the call.
2963 if (may_call_recover)
2964 {
2965 gogo->add_label_definition("retaddr", location);
2966
2967 Expression_list* vals = new Expression_list();
2968 vals->push_back(Expression::make_boolean(false, location));
2969 gogo->add_statement(Statement::make_return_statement(vals, location));
2970 }
2971
2972 Block* b = gogo->finish_block(location);
2973
2974 gogo->add_block(b, location);
2975
2976 gogo->lower_block(function, b);
2977
2978 // We already ran the determine_types pass, so we need to run it
2979 // just for the call statement now. The other types are known.
2980 call_statement->determine_types();
2981
2982 gogo->add_conversions_in_block(b);
2983
2984 if (may_call_recover
2985 || recover_arg != NULL
2986 || this->classification() == STATEMENT_GO)
2987 {
2988 // Dig up the call expression, which may have been changed
2989 // during lowering.
2990 go_assert(call_statement->classification() == STATEMENT_EXPRESSION);
2991 Expression_statement* es =
2992 static_cast<Expression_statement*>(call_statement);
2993 ce = es->expr()->call_expression();
2994 if (ce == NULL)
2995 go_assert(saw_errors());
2996 else
2997 {
2998 if (may_call_recover)
2999 ce->set_is_deferred();
3000 if (this->classification() == STATEMENT_GO)
3001 ce->set_is_concurrent();
3002 if (recover_arg != NULL)
3003 ce->set_recover_arg(recover_arg);
3004 }
3005 }
3006
3007 gogo->flatten_block(function, b);
3008
3009 // That is all the thunk has to do.
3010 gogo->finish_function(location);
3011 }
3012
3013 // Get the function and argument expressions.
3014
3015 bool
get_fn_and_arg(Expression ** pfn,Expression ** parg)3016 Thunk_statement::get_fn_and_arg(Expression** pfn, Expression** parg)
3017 {
3018 if (this->call_->is_error_expression())
3019 return false;
3020
3021 Call_expression* ce = this->call_->call_expression();
3022
3023 Expression* fn = ce->fn();
3024 Func_expression* fe = fn->func_expression();
3025 go_assert(fe != NULL);
3026 *pfn = Expression::make_func_code_reference(fe->named_object(),
3027 fe->location());
3028
3029 const Expression_list* args = ce->args();
3030 if (args == NULL || args->empty())
3031 *parg = Expression::make_nil(this->location());
3032 else
3033 {
3034 go_assert(args->size() == 1);
3035 *parg = args->front();
3036 }
3037
3038 return true;
3039 }
3040
3041 // Class Go_statement.
3042
3043 Bstatement*
do_get_backend(Translate_context * context)3044 Go_statement::do_get_backend(Translate_context* context)
3045 {
3046 Expression* fn;
3047 Expression* arg;
3048 if (!this->get_fn_and_arg(&fn, &arg))
3049 return context->backend()->error_statement();
3050
3051 Expression* call = Runtime::make_call(Runtime::GO, this->location(), 2,
3052 fn, arg);
3053 Bexpression* bcall = call->get_backend(context);
3054 Bfunction* bfunction = context->function()->func_value()->get_decl();
3055 return context->backend()->expression_statement(bfunction, bcall);
3056 }
3057
3058 // Dump the AST representation for go statement.
3059
3060 void
do_dump_statement(Ast_dump_context * ast_dump_context) const3061 Go_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3062 {
3063 ast_dump_context->print_indent();
3064 ast_dump_context->ostream() << "go ";
3065 ast_dump_context->dump_expression(this->call());
3066 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
3067 }
3068
3069 // Make a go statement.
3070
3071 Statement*
make_go_statement(Call_expression * call,Location location)3072 Statement::make_go_statement(Call_expression* call, Location location)
3073 {
3074 return new Go_statement(call, location);
3075 }
3076
3077 // Class Defer_statement.
3078
3079 Bstatement*
do_get_backend(Translate_context * context)3080 Defer_statement::do_get_backend(Translate_context* context)
3081 {
3082 Expression* fn;
3083 Expression* arg;
3084 if (!this->get_fn_and_arg(&fn, &arg))
3085 return context->backend()->error_statement();
3086
3087 Location loc = this->location();
3088 Expression* ds = context->function()->func_value()->defer_stack(loc);
3089
3090 Expression* call;
3091 if (this->on_stack_)
3092 {
3093 if (context->gogo()->debug_optimization())
3094 go_debug(loc, "stack allocated defer");
3095
3096 Type* defer_type = Defer_statement::defer_struct_type();
3097 Expression* defer = Expression::make_allocation(defer_type, loc);
3098 defer->allocation_expression()->set_allocate_on_stack();
3099 defer->allocation_expression()->set_no_zero();
3100 call = Runtime::make_call(Runtime::DEFERPROCSTACK, loc, 4,
3101 defer, ds, fn, arg);
3102 }
3103 else
3104 call = Runtime::make_call(Runtime::DEFERPROC, loc, 3,
3105 ds, fn, arg);
3106 Bexpression* bcall = call->get_backend(context);
3107 Bfunction* bfunction = context->function()->func_value()->get_decl();
3108 return context->backend()->expression_statement(bfunction, bcall);
3109 }
3110
3111 Type*
defer_struct_type()3112 Defer_statement::defer_struct_type()
3113 {
3114 Type* ptr_type = Type::make_pointer_type(Type::make_void_type());
3115 Type* uintptr_type = Type::lookup_integer_type("uintptr");
3116 Type* bool_type = Type::make_boolean_type();
3117 return Type::make_builtin_struct_type(9,
3118 "link", ptr_type,
3119 "frame", ptr_type,
3120 "panicStack", ptr_type,
3121 "_panic", ptr_type,
3122 "pfn", uintptr_type,
3123 "arg", ptr_type,
3124 "retaddr", uintptr_type,
3125 "makefunccanrecover", bool_type,
3126 "heap", bool_type);
3127 }
3128
3129 // Dump the AST representation for defer statement.
3130
3131 void
do_dump_statement(Ast_dump_context * ast_dump_context) const3132 Defer_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3133 {
3134 ast_dump_context->print_indent();
3135 ast_dump_context->ostream() << "defer ";
3136 ast_dump_context->dump_expression(this->call());
3137 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
3138 }
3139
3140 // Make a defer statement.
3141
3142 Statement*
make_defer_statement(Call_expression * call,Location location)3143 Statement::make_defer_statement(Call_expression* call,
3144 Location location)
3145 {
3146 return new Defer_statement(call, location);
3147 }
3148
3149 // Class Return_statement.
3150
3151 // Traverse assignments. We treat each return value as a top level
3152 // RHS in an expression.
3153
3154 bool
do_traverse_assignments(Traverse_assignments * tassign)3155 Return_statement::do_traverse_assignments(Traverse_assignments* tassign)
3156 {
3157 Expression_list* vals = this->vals_;
3158 if (vals != NULL)
3159 {
3160 for (Expression_list::iterator p = vals->begin();
3161 p != vals->end();
3162 ++p)
3163 tassign->value(&*p, true, true);
3164 }
3165 return true;
3166 }
3167
3168 // Lower a return statement. If we are returning a function call
3169 // which returns multiple values which match the current function,
3170 // split up the call's results. If the return statement lists
3171 // explicit values, implement this statement by assigning the values
3172 // to the result variables and change this statement to a naked
3173 // return. This lets panic/recover work correctly.
3174
3175 Statement*
do_lower(Gogo *,Named_object * function,Block * enclosing,Statement_inserter *)3176 Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing,
3177 Statement_inserter*)
3178 {
3179 if (this->is_lowered_)
3180 return this;
3181
3182 Expression_list* vals = this->vals_;
3183 this->vals_ = NULL;
3184 this->is_lowered_ = true;
3185
3186 Location loc = this->location();
3187
3188 size_t vals_count = vals == NULL ? 0 : vals->size();
3189 Function::Results* results = function->func_value()->result_variables();
3190 size_t results_count = results == NULL ? 0 : results->size();
3191
3192 if (vals_count == 0)
3193 {
3194 if (results_count > 0 && !function->func_value()->results_are_named())
3195 {
3196 this->report_error(_("not enough arguments to return"));
3197 return this;
3198 }
3199 return this;
3200 }
3201
3202 if (results_count == 0)
3203 {
3204 this->report_error(_("return with value in function "
3205 "with no return type"));
3206 return this;
3207 }
3208
3209 // If the current function has multiple return values, and we are
3210 // returning a single call expression, split up the call expression.
3211 if (results_count > 1
3212 && vals->size() == 1
3213 && vals->front()->call_expression() != NULL)
3214 {
3215 Call_expression* call = vals->front()->call_expression();
3216 call->set_expected_result_count(results_count);
3217 delete vals;
3218 vals = new Expression_list;
3219 for (size_t i = 0; i < results_count; ++i)
3220 vals->push_back(Expression::make_call_result(call, i));
3221 vals_count = results_count;
3222 }
3223
3224 if (vals_count < results_count)
3225 {
3226 this->report_error(_("not enough arguments to return"));
3227 return this;
3228 }
3229
3230 if (vals_count > results_count)
3231 {
3232 this->report_error(_("too many values in return statement"));
3233 return this;
3234 }
3235
3236 Block* b = new Block(enclosing, loc);
3237
3238 Expression_list* lhs = new Expression_list();
3239 Expression_list* rhs = new Expression_list();
3240
3241 Expression_list::const_iterator pe = vals->begin();
3242 int i = 1;
3243 for (Function::Results::const_iterator pr = results->begin();
3244 pr != results->end();
3245 ++pr, ++pe, ++i)
3246 {
3247 Named_object* rv = *pr;
3248 Expression* e = *pe;
3249
3250 // Check types now so that we give a good error message. The
3251 // result type is known. We determine the expression type
3252 // early.
3253
3254 Type *rvtype = rv->result_var_value()->type();
3255 Type_context type_context(rvtype, false);
3256 e->determine_type(&type_context);
3257
3258 std::string reason;
3259 if (Type::are_assignable(rvtype, e->type(), &reason))
3260 {
3261 Expression* ve = Expression::make_var_reference(rv, e->location());
3262 lhs->push_back(ve);
3263 rhs->push_back(e);
3264 }
3265 else
3266 {
3267 if (reason.empty())
3268 go_error_at(e->location(),
3269 "incompatible type for return value %d", i);
3270 else
3271 go_error_at(e->location(),
3272 "incompatible type for return value %d (%s)",
3273 i, reason.c_str());
3274 }
3275 }
3276 go_assert(lhs->size() == rhs->size());
3277
3278 if (lhs->empty())
3279 ;
3280 else if (lhs->size() == 1)
3281 {
3282 b->add_statement(Statement::make_assignment(lhs->front(), rhs->front(),
3283 loc));
3284 delete lhs;
3285 delete rhs;
3286 }
3287 else
3288 b->add_statement(Statement::make_tuple_assignment(lhs, rhs, loc));
3289
3290 b->add_statement(this);
3291
3292 delete vals;
3293
3294 return Statement::make_block_statement(b, loc);
3295 }
3296
3297 // Convert a return statement to the backend representation.
3298
3299 Bstatement*
do_get_backend(Translate_context * context)3300 Return_statement::do_get_backend(Translate_context* context)
3301 {
3302 Location loc = this->location();
3303
3304 Function* function = context->function()->func_value();
3305 Function::Results* results = function->result_variables();
3306 std::vector<Bexpression*> retvals;
3307 if (results != NULL && !results->empty())
3308 {
3309 retvals.reserve(results->size());
3310 for (Function::Results::const_iterator p = results->begin();
3311 p != results->end();
3312 p++)
3313 {
3314 Expression* vr = Expression::make_var_reference(*p, loc);
3315 retvals.push_back(vr->get_backend(context));
3316 }
3317 }
3318
3319 return context->backend()->return_statement(function->get_decl(),
3320 retvals, loc);
3321 }
3322
3323 // Export a return statement. At this point all the expressions have
3324 // been converted to assignments to the result variables, so this is
3325 // simple.
3326
3327 void
do_export_statement(Export_function_body * efb)3328 Return_statement::do_export_statement(Export_function_body* efb)
3329 {
3330 efb->write_c_string("return");
3331 }
3332
3333 // Dump the AST representation for a return statement.
3334
3335 void
do_dump_statement(Ast_dump_context * ast_dump_context) const3336 Return_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3337 {
3338 ast_dump_context->print_indent();
3339 ast_dump_context->ostream() << "return " ;
3340 ast_dump_context->dump_expression_list(this->vals_);
3341 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
3342 }
3343
3344 // Make a return statement.
3345
3346 Return_statement*
make_return_statement(Expression_list * vals,Location location)3347 Statement::make_return_statement(Expression_list* vals,
3348 Location location)
3349 {
3350 return new Return_statement(vals, location);
3351 }
3352
3353 // Make a statement that returns the result of a call expression.
3354
3355 Statement*
make_return_from_call(Call_expression * call,Location location)3356 Statement::make_return_from_call(Call_expression* call, Location location)
3357 {
3358 size_t rc = call->result_count();
3359 if (rc == 0)
3360 return Statement::make_statement(call, true);
3361 else
3362 {
3363 Expression_list* vals = new Expression_list();
3364 if (rc == 1)
3365 vals->push_back(call);
3366 else
3367 {
3368 for (size_t i = 0; i < rc; ++i)
3369 vals->push_back(Expression::make_call_result(call, i));
3370 }
3371 return Statement::make_return_statement(vals, location);
3372 }
3373 }
3374
3375 // A break or continue statement.
3376
3377 class Bc_statement : public Statement
3378 {
3379 public:
Bc_statement(bool is_break,Unnamed_label * label,Location location)3380 Bc_statement(bool is_break, Unnamed_label* label, Location location)
3381 : Statement(STATEMENT_BREAK_OR_CONTINUE, location),
3382 label_(label), is_break_(is_break)
3383 { }
3384
3385 bool
is_break() const3386 is_break() const
3387 { return this->is_break_; }
3388
3389 protected:
3390 int
do_traverse(Traverse *)3391 do_traverse(Traverse*)
3392 { return TRAVERSE_CONTINUE; }
3393
3394 bool
do_may_fall_through() const3395 do_may_fall_through() const
3396 { return false; }
3397
3398 Bstatement*
do_get_backend(Translate_context * context)3399 do_get_backend(Translate_context* context)
3400 { return this->label_->get_goto(context, this->location()); }
3401
3402 void
3403 do_dump_statement(Ast_dump_context*) const;
3404
3405 private:
3406 // The label that this branches to.
3407 Unnamed_label* label_;
3408 // True if this is "break", false if it is "continue".
3409 bool is_break_;
3410 };
3411
3412 // Dump the AST representation for a break/continue statement
3413
3414 void
do_dump_statement(Ast_dump_context * ast_dump_context) const3415 Bc_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3416 {
3417 ast_dump_context->print_indent();
3418 ast_dump_context->ostream() << (this->is_break_ ? "break" : "continue");
3419 if (this->label_ != NULL)
3420 {
3421 ast_dump_context->ostream() << " ";
3422 ast_dump_context->dump_label_name(this->label_);
3423 }
3424 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
3425 }
3426
3427 // Make a break statement.
3428
3429 Statement*
make_break_statement(Unnamed_label * label,Location location)3430 Statement::make_break_statement(Unnamed_label* label, Location location)
3431 {
3432 return new Bc_statement(true, label, location);
3433 }
3434
3435 // Make a continue statement.
3436
3437 Statement*
make_continue_statement(Unnamed_label * label,Location location)3438 Statement::make_continue_statement(Unnamed_label* label,
3439 Location location)
3440 {
3441 return new Bc_statement(false, label, location);
3442 }
3443
3444 // Class Goto_statement.
3445
3446 int
do_traverse(Traverse *)3447 Goto_statement::do_traverse(Traverse*)
3448 {
3449 return TRAVERSE_CONTINUE;
3450 }
3451
3452 // Check types for a label. There aren't any types per se, but we use
3453 // this to give an error if the label was never defined.
3454
3455 void
do_check_types(Gogo *)3456 Goto_statement::do_check_types(Gogo*)
3457 {
3458 if (!this->label_->is_defined())
3459 {
3460 go_error_at(this->location(), "reference to undefined label %qs",
3461 Gogo::message_name(this->label_->name()).c_str());
3462 this->set_is_error();
3463 }
3464 }
3465
3466 // Convert the goto statement to the backend representation.
3467
3468 Bstatement*
do_get_backend(Translate_context * context)3469 Goto_statement::do_get_backend(Translate_context* context)
3470 {
3471 Blabel* blabel = this->label_->get_backend_label(context);
3472 return context->backend()->goto_statement(blabel, this->location());
3473 }
3474
3475 // Export a goto statement.
3476
3477 void
do_export_statement(Export_function_body * efb)3478 Goto_statement::do_export_statement(Export_function_body *efb)
3479 {
3480 efb->write_c_string("goto ");
3481 efb->write_string(this->label_->name());
3482 }
3483
3484 // Import a goto or goto unnamed statement.
3485
3486 Statement*
do_import(Import_function_body * ifb,Location loc)3487 Goto_statement::do_import(Import_function_body* ifb, Location loc)
3488 {
3489 ifb->require_c_string("goto ");
3490 std::string id = ifb->read_identifier();
3491 if (id[0] != '$')
3492 {
3493 Function* fn = ifb->function()->func_value();
3494 Label* label = fn->add_label_reference(ifb->gogo(), id, loc, false);
3495 return Statement::make_goto_statement(label, loc);
3496 }
3497 else
3498 {
3499 if (id[1] != 'l')
3500 {
3501 if (!ifb->saw_error())
3502 go_error_at(loc,
3503 ("invalid export data for %qs: "
3504 "bad unnamed label at %lu"),
3505 ifb->name().c_str(),
3506 static_cast<unsigned long>(ifb->off()));
3507 ifb->set_saw_error();
3508 return Statement::make_error_statement(loc);
3509 }
3510 const char* p = id.c_str();
3511 char* end;
3512 long idx = strtol(p + 2, &end, 10);
3513 if (*end != '\0' || idx > 0x7fffffff)
3514 {
3515 if (!ifb->saw_error())
3516 go_error_at(loc,
3517 ("invalid export data for %qs: "
3518 "bad unnamed label index at %lu"),
3519 ifb->name().c_str(),
3520 static_cast<unsigned long>(ifb->off()));
3521 ifb->set_saw_error();
3522 return Statement::make_error_statement(loc);
3523 }
3524
3525 Unnamed_label* label = ifb->unnamed_label(idx, loc);
3526 return Statement::make_goto_unnamed_statement(label, loc);
3527 }
3528 }
3529
3530 // Dump the AST representation for a goto statement.
3531
3532 void
do_dump_statement(Ast_dump_context * ast_dump_context) const3533 Goto_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3534 {
3535 ast_dump_context->print_indent();
3536 ast_dump_context->ostream() << "goto " << this->label_->name() << dsuffix(location()) << std::endl;
3537 }
3538
3539 // Make a goto statement.
3540
3541 Statement*
make_goto_statement(Label * label,Location location)3542 Statement::make_goto_statement(Label* label, Location location)
3543 {
3544 return new Goto_statement(label, location);
3545 }
3546
3547 // Class Goto_unnamed_statement.
3548
3549 int
do_traverse(Traverse *)3550 Goto_unnamed_statement::do_traverse(Traverse*)
3551 {
3552 return TRAVERSE_CONTINUE;
3553 }
3554
3555 // Convert the goto unnamed statement to the backend representation.
3556
3557 Bstatement*
do_get_backend(Translate_context * context)3558 Goto_unnamed_statement::do_get_backend(Translate_context* context)
3559 {
3560 return this->label_->get_goto(context, this->location());
3561 }
3562
3563 // Export a goto unnamed statement.
3564
3565 void
do_export_statement(Export_function_body * efb)3566 Goto_unnamed_statement::do_export_statement(Export_function_body *efb)
3567 {
3568 unsigned int index = efb->unnamed_label_index(this->label_);
3569 char buf[100];
3570 snprintf(buf, sizeof buf, "goto $l%u", index);
3571 efb->write_c_string(buf);
3572 }
3573
3574 // Dump the AST representation for an unnamed goto statement
3575
3576 void
do_dump_statement(Ast_dump_context * ast_dump_context) const3577 Goto_unnamed_statement::do_dump_statement(
3578 Ast_dump_context* ast_dump_context) const
3579 {
3580 ast_dump_context->print_indent();
3581 ast_dump_context->ostream() << "goto ";
3582 ast_dump_context->dump_label_name(this->label_);
3583 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
3584 }
3585
3586 // Make a goto statement to an unnamed label.
3587
3588 Statement*
make_goto_unnamed_statement(Unnamed_label * label,Location location)3589 Statement::make_goto_unnamed_statement(Unnamed_label* label,
3590 Location location)
3591 {
3592 return new Goto_unnamed_statement(label, location);
3593 }
3594
3595 // Class Label_statement.
3596
3597 // Traversal.
3598
3599 int
do_traverse(Traverse *)3600 Label_statement::do_traverse(Traverse*)
3601 {
3602 return TRAVERSE_CONTINUE;
3603 }
3604
3605 // Return the backend representation of the statement defining this
3606 // label.
3607
3608 Bstatement*
do_get_backend(Translate_context * context)3609 Label_statement::do_get_backend(Translate_context* context)
3610 {
3611 if (this->label_->is_dummy_label())
3612 {
3613 Bexpression* bce = context->backend()->boolean_constant_expression(false);
3614 Bfunction* bfunction = context->function()->func_value()->get_decl();
3615 return context->backend()->expression_statement(bfunction, bce);
3616 }
3617 Blabel* blabel = this->label_->get_backend_label(context);
3618 return context->backend()->label_definition_statement(blabel);
3619 }
3620
3621 // Export a label.
3622
3623 void
do_export_statement(Export_function_body * efb)3624 Label_statement::do_export_statement(Export_function_body* efb)
3625 {
3626 if (this->label_->is_dummy_label())
3627 return;
3628 // We use a leading colon, not a trailing one, to simplify import.
3629 efb->write_c_string(":");
3630 efb->write_string(this->label_->name());
3631 }
3632
3633 // Import a label or an unnamed label.
3634
3635 Statement*
do_import(Import_function_body * ifb,Location loc)3636 Label_statement::do_import(Import_function_body* ifb, Location loc)
3637 {
3638 ifb->require_c_string(":");
3639 std::string id = ifb->read_identifier();
3640 if (id[0] != '$')
3641 {
3642 Function* fn = ifb->function()->func_value();
3643 Label* label = fn->add_label_definition(ifb->gogo(), id, loc);
3644 return Statement::make_label_statement(label, loc);
3645 }
3646 else
3647 {
3648 if (id[1] != 'l')
3649 {
3650 if (!ifb->saw_error())
3651 go_error_at(loc,
3652 ("invalid export data for %qs: "
3653 "bad unnamed label at %lu"),
3654 ifb->name().c_str(),
3655 static_cast<unsigned long>(ifb->off()));
3656 ifb->set_saw_error();
3657 return Statement::make_error_statement(loc);
3658 }
3659 const char* p = id.c_str();
3660 char* end;
3661 long idx = strtol(p + 2, &end, 10);
3662 if (*end != '\0' || idx > 0x7fffffff)
3663 {
3664 if (!ifb->saw_error())
3665 go_error_at(loc,
3666 ("invalid export data for %qs: "
3667 "bad unnamed label index at %lu"),
3668 ifb->name().c_str(),
3669 static_cast<unsigned long>(ifb->off()));
3670 ifb->set_saw_error();
3671 return Statement::make_error_statement(loc);
3672 }
3673
3674 Unnamed_label* label = ifb->unnamed_label(idx, loc);
3675 return Statement::make_unnamed_label_statement(label);
3676 }
3677 }
3678
3679 // Dump the AST for a label definition statement.
3680
3681 void
do_dump_statement(Ast_dump_context * ast_dump_context) const3682 Label_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3683 {
3684 ast_dump_context->print_indent();
3685 ast_dump_context->ostream() << this->label_->name() << ":" << dsuffix(location()) << std::endl;
3686 }
3687
3688 // Make a label statement.
3689
3690 Statement*
make_label_statement(Label * label,Location location)3691 Statement::make_label_statement(Label* label, Location location)
3692 {
3693 return new Label_statement(label, location);
3694 }
3695
3696 // Class Unnamed_label_statement.
3697
Unnamed_label_statement(Unnamed_label * label)3698 Unnamed_label_statement::Unnamed_label_statement(Unnamed_label* label)
3699 : Statement(STATEMENT_UNNAMED_LABEL, label->location()),
3700 label_(label)
3701 { }
3702
3703 int
do_traverse(Traverse *)3704 Unnamed_label_statement::do_traverse(Traverse*)
3705 {
3706 return TRAVERSE_CONTINUE;
3707 }
3708
3709 // Get the backend definition for this unnamed label statement.
3710
3711 Bstatement*
do_get_backend(Translate_context * context)3712 Unnamed_label_statement::do_get_backend(Translate_context* context)
3713 {
3714 return this->label_->get_definition(context);
3715 }
3716
3717 // Export an unnamed label.
3718
3719 void
do_export_statement(Export_function_body * efb)3720 Unnamed_label_statement::do_export_statement(Export_function_body* efb)
3721 {
3722 unsigned int index = efb->unnamed_label_index(this->label_);
3723 char buf[50];
3724 // We use a leading colon, not a trailing one, to simplify import.
3725 snprintf(buf, sizeof buf, ":$l%u", index);
3726 efb->write_c_string(buf);
3727 }
3728
3729 // Dump the AST representation for an unnamed label definition statement.
3730
3731 void
do_dump_statement(Ast_dump_context * ast_dump_context) const3732 Unnamed_label_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
3733 const
3734 {
3735 ast_dump_context->print_indent();
3736 ast_dump_context->dump_label_name(this->label_);
3737 ast_dump_context->ostream() << ":" << dsuffix(location()) << std::endl;
3738 }
3739
3740 // Make an unnamed label statement.
3741
3742 Statement*
make_unnamed_label_statement(Unnamed_label * label)3743 Statement::make_unnamed_label_statement(Unnamed_label* label)
3744 {
3745 return new Unnamed_label_statement(label);
3746 }
3747
3748 // Class If_statement.
3749
3750 // Traversal.
3751
3752 int
do_traverse(Traverse * traverse)3753 If_statement::do_traverse(Traverse* traverse)
3754 {
3755 if (this->traverse_expression(traverse, &this->cond_) == TRAVERSE_EXIT
3756 || this->then_block_->traverse(traverse) == TRAVERSE_EXIT)
3757 return TRAVERSE_EXIT;
3758 if (this->else_block_ != NULL)
3759 {
3760 if (this->else_block_->traverse(traverse) == TRAVERSE_EXIT)
3761 return TRAVERSE_EXIT;
3762 }
3763 return TRAVERSE_CONTINUE;
3764 }
3765
3766 void
do_determine_types()3767 If_statement::do_determine_types()
3768 {
3769 Type_context context(Type::lookup_bool_type(), false);
3770 this->cond_->determine_type(&context);
3771 this->then_block_->determine_types();
3772 if (this->else_block_ != NULL)
3773 this->else_block_->determine_types();
3774 }
3775
3776 // Check types.
3777
3778 void
do_check_types(Gogo *)3779 If_statement::do_check_types(Gogo*)
3780 {
3781 Type* type = this->cond_->type();
3782 if (type->is_error())
3783 this->set_is_error();
3784 else if (!type->is_boolean_type())
3785 this->report_error(_("expected boolean expression"));
3786 }
3787
3788 // Whether the overall statement may fall through.
3789
3790 bool
do_may_fall_through() const3791 If_statement::do_may_fall_through() const
3792 {
3793 return (this->else_block_ == NULL
3794 || this->then_block_->may_fall_through()
3795 || this->else_block_->may_fall_through());
3796 }
3797
3798 // Get the backend representation.
3799
3800 Bstatement*
do_get_backend(Translate_context * context)3801 If_statement::do_get_backend(Translate_context* context)
3802 {
3803 go_assert(this->cond_->type()->is_boolean_type()
3804 || this->cond_->type()->is_error());
3805 Bexpression* cond = this->cond_->get_backend(context);
3806 Bblock* then_block = this->then_block_->get_backend(context);
3807 Bblock* else_block = (this->else_block_ == NULL
3808 ? NULL
3809 : this->else_block_->get_backend(context));
3810 Bfunction* bfunction = context->function()->func_value()->get_decl();
3811 return context->backend()->if_statement(bfunction,
3812 cond, then_block, else_block,
3813 this->location());
3814 }
3815
3816 // Export an if statement.
3817
3818 void
do_export_statement(Export_function_body * efb)3819 If_statement::do_export_statement(Export_function_body* efb)
3820 {
3821 efb->write_c_string("if ");
3822 this->cond_->export_expression(efb);
3823 efb->write_c_string(" ");
3824 Block_statement::export_block(efb, this->then_block_, false);
3825 if (this->else_block_ != NULL)
3826 {
3827 efb->write_c_string(" else ");
3828 Block_statement::export_block(efb, this->else_block_, false);
3829 }
3830 }
3831
3832 // Import an if statement.
3833
3834 Statement*
do_import(Import_function_body * ifb,Location loc)3835 If_statement::do_import(Import_function_body* ifb, Location loc)
3836 {
3837 ifb->require_c_string("if ");
3838
3839 Expression* cond = Expression::import_expression(ifb, loc);
3840 ifb->require_c_string(" ");
3841
3842 if (!ifb->match_c_string("{"))
3843 {
3844 if (!ifb->saw_error())
3845 go_error_at(ifb->location(),
3846 "import error for %qs: no block for if statement at %lu",
3847 ifb->name().c_str(),
3848 static_cast<unsigned long>(ifb->off()));
3849 ifb->set_saw_error();
3850 return Statement::make_error_statement(loc);
3851 }
3852
3853 bool is_lowered_for_statement;
3854 Block* then_block = Block_statement::do_import(ifb, loc,
3855 &is_lowered_for_statement);
3856 if (then_block == NULL)
3857 return Statement::make_error_statement(loc);
3858 if (is_lowered_for_statement)
3859 {
3860 if (!ifb->saw_error())
3861 go_error_at(ifb->location(),
3862 ("import error for %qs: "
3863 "unexpected lowered for in if statement at %lu"),
3864 ifb->name().c_str(),
3865 static_cast<unsigned long>(ifb->off()));
3866 ifb->set_saw_error();
3867 return Statement::make_error_statement(loc);
3868 }
3869
3870 Block* else_block = NULL;
3871 if (ifb->match_c_string(" else "))
3872 {
3873 ifb->advance(6);
3874 if (!ifb->match_c_string("{"))
3875 {
3876 if (!ifb->saw_error())
3877 go_error_at(ifb->location(),
3878 ("import error for %qs: no else block "
3879 "for if statement at %lu"),
3880 ifb->name().c_str(),
3881 static_cast<unsigned long>(ifb->off()));
3882 ifb->set_saw_error();
3883 return Statement::make_error_statement(loc);
3884 }
3885
3886 else_block = Block_statement::do_import(ifb, loc,
3887 &is_lowered_for_statement);
3888 if (else_block == NULL)
3889 return Statement::make_error_statement(loc);
3890 if (is_lowered_for_statement)
3891 {
3892 if (!ifb->saw_error())
3893 go_error_at(ifb->location(),
3894 ("import error for %qs: "
3895 "unexpected lowered for in if statement at %lu"),
3896 ifb->name().c_str(),
3897 static_cast<unsigned long>(ifb->off()));
3898 ifb->set_saw_error();
3899 return Statement::make_error_statement(loc);
3900 }
3901 }
3902
3903 return Statement::make_if_statement(cond, then_block, else_block, loc);
3904 }
3905
3906 // Dump the AST representation for an if statement
3907
3908 void
do_dump_statement(Ast_dump_context * ast_dump_context) const3909 If_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3910 {
3911 ast_dump_context->print_indent();
3912 ast_dump_context->ostream() << "if ";
3913 ast_dump_context->dump_expression(this->cond_);
3914 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
3915 if (ast_dump_context->dump_subblocks())
3916 {
3917 ast_dump_context->dump_block(this->then_block_);
3918 if (this->else_block_ != NULL)
3919 {
3920 ast_dump_context->print_indent();
3921 ast_dump_context->ostream() << "else" << std::endl;
3922 ast_dump_context->dump_block(this->else_block_);
3923 }
3924 }
3925 }
3926
3927 // Make an if statement.
3928
3929 Statement*
make_if_statement(Expression * cond,Block * then_block,Block * else_block,Location location)3930 Statement::make_if_statement(Expression* cond, Block* then_block,
3931 Block* else_block, Location location)
3932 {
3933 return new If_statement(cond, then_block, else_block, location);
3934 }
3935
3936 // Class Case_clauses::Hash_integer_value.
3937
3938 class Case_clauses::Hash_integer_value
3939 {
3940 public:
3941 size_t
3942 operator()(Expression*) const;
3943 };
3944
3945 size_t
operator ()(Expression * pe) const3946 Case_clauses::Hash_integer_value::operator()(Expression* pe) const
3947 {
3948 Numeric_constant nc;
3949 mpz_t ival;
3950 if (!pe->numeric_constant_value(&nc) || !nc.to_int(&ival))
3951 go_unreachable();
3952 size_t ret = mpz_get_ui(ival);
3953 mpz_clear(ival);
3954 return ret;
3955 }
3956
3957 // Class Case_clauses::Eq_integer_value.
3958
3959 class Case_clauses::Eq_integer_value
3960 {
3961 public:
3962 bool
3963 operator()(Expression*, Expression*) const;
3964 };
3965
3966 bool
operator ()(Expression * a,Expression * b) const3967 Case_clauses::Eq_integer_value::operator()(Expression* a, Expression* b) const
3968 {
3969 Numeric_constant anc;
3970 mpz_t aval;
3971 Numeric_constant bnc;
3972 mpz_t bval;
3973 if (!a->numeric_constant_value(&anc)
3974 || !anc.to_int(&aval)
3975 || !b->numeric_constant_value(&bnc)
3976 || !bnc.to_int(&bval))
3977 go_unreachable();
3978 bool ret = mpz_cmp(aval, bval) == 0;
3979 mpz_clear(aval);
3980 mpz_clear(bval);
3981 return ret;
3982 }
3983
3984 // Class Case_clauses::Case_clause.
3985
3986 // Traversal.
3987
3988 int
traverse(Traverse * traverse)3989 Case_clauses::Case_clause::traverse(Traverse* traverse)
3990 {
3991 if (this->cases_ != NULL
3992 && (traverse->traverse_mask()
3993 & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0)
3994 {
3995 if (this->cases_->traverse(traverse) == TRAVERSE_EXIT)
3996 return TRAVERSE_EXIT;
3997 }
3998 if (this->statements_ != NULL)
3999 {
4000 if (this->statements_->traverse(traverse) == TRAVERSE_EXIT)
4001 return TRAVERSE_EXIT;
4002 }
4003 return TRAVERSE_CONTINUE;
4004 }
4005
4006 // Check whether all the case expressions are integer constants.
4007
4008 bool
is_constant() const4009 Case_clauses::Case_clause::is_constant() const
4010 {
4011 if (this->cases_ != NULL)
4012 {
4013 for (Expression_list::const_iterator p = this->cases_->begin();
4014 p != this->cases_->end();
4015 ++p)
4016 if (!(*p)->is_constant() || (*p)->type()->integer_type() == NULL)
4017 return false;
4018 }
4019 return true;
4020 }
4021
4022 // Lower a case clause for a nonconstant switch. VAL_TEMP is the
4023 // value we are switching on; it may be NULL. If START_LABEL is not
4024 // NULL, it goes at the start of the statements, after the condition
4025 // test. We branch to FINISH_LABEL at the end of the statements.
4026
4027 void
lower(Block * b,Temporary_statement * val_temp,Unnamed_label * start_label,Unnamed_label * finish_label) const4028 Case_clauses::Case_clause::lower(Block* b, Temporary_statement* val_temp,
4029 Unnamed_label* start_label,
4030 Unnamed_label* finish_label) const
4031 {
4032 Location loc = this->location_;
4033 Unnamed_label* next_case_label;
4034 if (this->cases_ == NULL || this->cases_->empty())
4035 {
4036 go_assert(this->is_default_);
4037 next_case_label = NULL;
4038 }
4039 else
4040 {
4041 Expression* cond = NULL;
4042
4043 for (Expression_list::const_iterator p = this->cases_->begin();
4044 p != this->cases_->end();
4045 ++p)
4046 {
4047 Expression* ref = Expression::make_temporary_reference(val_temp,
4048 loc);
4049 Expression* this_cond = Expression::make_binary(OPERATOR_EQEQ, ref,
4050 *p, loc);
4051 if (cond == NULL)
4052 cond = this_cond;
4053 else
4054 cond = Expression::make_binary(OPERATOR_OROR, cond, this_cond, loc);
4055 }
4056
4057 Block* then_block = new Block(b, loc);
4058 next_case_label = new Unnamed_label(Linemap::unknown_location());
4059 Statement* s = Statement::make_goto_unnamed_statement(next_case_label,
4060 loc);
4061 then_block->add_statement(s);
4062
4063 // if !COND { goto NEXT_CASE_LABEL }
4064 cond = Expression::make_unary(OPERATOR_NOT, cond, loc);
4065 s = Statement::make_if_statement(cond, then_block, NULL, loc);
4066 b->add_statement(s);
4067 }
4068
4069 if (start_label != NULL)
4070 b->add_statement(Statement::make_unnamed_label_statement(start_label));
4071
4072 if (this->statements_ != NULL)
4073 b->add_statement(Statement::make_block_statement(this->statements_, loc));
4074
4075 Statement* s = Statement::make_goto_unnamed_statement(finish_label, loc);
4076 b->add_statement(s);
4077
4078 if (next_case_label != NULL)
4079 b->add_statement(Statement::make_unnamed_label_statement(next_case_label));
4080 }
4081
4082 // Determine types.
4083
4084 void
determine_types(Type * type)4085 Case_clauses::Case_clause::determine_types(Type* type)
4086 {
4087 if (this->cases_ != NULL)
4088 {
4089 Type_context case_context(type, false);
4090 for (Expression_list::iterator p = this->cases_->begin();
4091 p != this->cases_->end();
4092 ++p)
4093 (*p)->determine_type(&case_context);
4094 }
4095 if (this->statements_ != NULL)
4096 this->statements_->determine_types();
4097 }
4098
4099 // Check types. Returns false if there was an error.
4100
4101 bool
check_types(Type * type)4102 Case_clauses::Case_clause::check_types(Type* type)
4103 {
4104 if (this->cases_ != NULL)
4105 {
4106 for (Expression_list::iterator p = this->cases_->begin();
4107 p != this->cases_->end();
4108 ++p)
4109 {
4110 if (!Type::are_assignable(type, (*p)->type(), NULL)
4111 && !Type::are_assignable((*p)->type(), type, NULL))
4112 {
4113 go_error_at((*p)->location(),
4114 "type mismatch between switch value and case clause");
4115 return false;
4116 }
4117 }
4118 }
4119 return true;
4120 }
4121
4122 // Return true if this clause may fall through to the following
4123 // statements. Note that this is not the same as whether the case
4124 // uses the "fallthrough" keyword.
4125
4126 bool
may_fall_through() const4127 Case_clauses::Case_clause::may_fall_through() const
4128 {
4129 if (this->statements_ == NULL)
4130 return true;
4131 return this->statements_->may_fall_through();
4132 }
4133
4134 // Convert the case values and statements to the backend
4135 // representation. BREAK_LABEL is the label which break statements
4136 // should branch to. CASE_CONSTANTS is used to detect duplicate
4137 // constants. *CASES should be passed as an empty vector; the values
4138 // for this case will be added to it. If this is the default case,
4139 // *CASES will remain empty. This returns the statement to execute if
4140 // one of these cases is selected.
4141
4142 Bstatement*
get_backend(Translate_context * context,Unnamed_label * break_label,Case_constants * case_constants,std::vector<Bexpression * > * cases) const4143 Case_clauses::Case_clause::get_backend(Translate_context* context,
4144 Unnamed_label* break_label,
4145 Case_constants* case_constants,
4146 std::vector<Bexpression*>* cases) const
4147 {
4148 if (this->cases_ != NULL)
4149 {
4150 go_assert(!this->is_default_);
4151 for (Expression_list::const_iterator p = this->cases_->begin();
4152 p != this->cases_->end();
4153 ++p)
4154 {
4155 Expression* e = *p;
4156 if (e->classification() != Expression::EXPRESSION_INTEGER)
4157 {
4158 Numeric_constant nc;
4159 mpz_t ival;
4160 if (!(*p)->numeric_constant_value(&nc) || !nc.to_int(&ival))
4161 {
4162 // Something went wrong. This can happen with a
4163 // negative constant and an unsigned switch value.
4164 go_assert(saw_errors());
4165 continue;
4166 }
4167 go_assert(nc.type() != NULL);
4168 e = Expression::make_integer_z(&ival, nc.type(), e->location());
4169 mpz_clear(ival);
4170 }
4171
4172 std::pair<Case_constants::iterator, bool> ins =
4173 case_constants->insert(e);
4174 if (!ins.second)
4175 {
4176 // Value was already present.
4177 go_error_at(this->location_, "duplicate case in switch");
4178 e = Expression::make_error(this->location_);
4179 }
4180 cases->push_back(e->get_backend(context));
4181 }
4182 }
4183
4184 Bstatement* statements;
4185 if (this->statements_ == NULL)
4186 statements = NULL;
4187 else
4188 {
4189 Bblock* bblock = this->statements_->get_backend(context);
4190 statements = context->backend()->block_statement(bblock);
4191 }
4192
4193 Bstatement* break_stat;
4194 if (this->is_fallthrough_)
4195 break_stat = NULL;
4196 else
4197 break_stat = break_label->get_goto(context, this->location_);
4198
4199 if (statements == NULL)
4200 return break_stat;
4201 else if (break_stat == NULL)
4202 return statements;
4203 else
4204 return context->backend()->compound_statement(statements, break_stat);
4205 }
4206
4207 // Dump the AST representation for a case clause
4208
4209 void
dump_clause(Ast_dump_context * ast_dump_context) const4210 Case_clauses::Case_clause::dump_clause(Ast_dump_context* ast_dump_context)
4211 const
4212 {
4213 ast_dump_context->print_indent();
4214 if (this->is_default_)
4215 {
4216 ast_dump_context->ostream() << "default:";
4217 }
4218 else
4219 {
4220 ast_dump_context->ostream() << "case ";
4221 ast_dump_context->dump_expression_list(this->cases_);
4222 ast_dump_context->ostream() << ":" ;
4223 }
4224 ast_dump_context->dump_block(this->statements_);
4225 if (this->is_fallthrough_)
4226 {
4227 ast_dump_context->print_indent();
4228 ast_dump_context->ostream() << " (fallthrough)" << dsuffix(location()) << std::endl;
4229 }
4230 }
4231
4232 // Class Case_clauses.
4233
4234 // Traversal.
4235
4236 int
traverse(Traverse * traverse)4237 Case_clauses::traverse(Traverse* traverse)
4238 {
4239 for (Clauses::iterator p = this->clauses_.begin();
4240 p != this->clauses_.end();
4241 ++p)
4242 {
4243 if (p->traverse(traverse) == TRAVERSE_EXIT)
4244 return TRAVERSE_EXIT;
4245 }
4246 return TRAVERSE_CONTINUE;
4247 }
4248
4249 // Check whether all the case expressions are constant.
4250
4251 bool
is_constant() const4252 Case_clauses::is_constant() const
4253 {
4254 for (Clauses::const_iterator p = this->clauses_.begin();
4255 p != this->clauses_.end();
4256 ++p)
4257 if (!p->is_constant())
4258 return false;
4259 return true;
4260 }
4261
4262 // Lower case clauses for a nonconstant switch.
4263
4264 void
lower(Block * b,Temporary_statement * val_temp,Unnamed_label * break_label) const4265 Case_clauses::lower(Block* b, Temporary_statement* val_temp,
4266 Unnamed_label* break_label) const
4267 {
4268 // The default case.
4269 const Case_clause* default_case = NULL;
4270
4271 // The label for the fallthrough of the previous case.
4272 Unnamed_label* last_fallthrough_label = NULL;
4273
4274 // The label for the start of the default case. This is used if the
4275 // case before the default case falls through.
4276 Unnamed_label* default_start_label = NULL;
4277
4278 // The label for the end of the default case. This normally winds
4279 // up as BREAK_LABEL, but it will be different if the default case
4280 // falls through.
4281 Unnamed_label* default_finish_label = NULL;
4282
4283 for (Clauses::const_iterator p = this->clauses_.begin();
4284 p != this->clauses_.end();
4285 ++p)
4286 {
4287 // The label to use for the start of the statements for this
4288 // case. This is NULL unless the previous case falls through.
4289 Unnamed_label* start_label = last_fallthrough_label;
4290
4291 // The label to jump to after the end of the statements for this
4292 // case.
4293 Unnamed_label* finish_label = break_label;
4294
4295 last_fallthrough_label = NULL;
4296 if (p->is_fallthrough() && p + 1 != this->clauses_.end())
4297 {
4298 finish_label = new Unnamed_label(p->location());
4299 last_fallthrough_label = finish_label;
4300 }
4301
4302 if (!p->is_default())
4303 p->lower(b, val_temp, start_label, finish_label);
4304 else
4305 {
4306 // We have to move the default case to the end, so that we
4307 // only use it if all the other tests fail.
4308 default_case = &*p;
4309 default_start_label = start_label;
4310 default_finish_label = finish_label;
4311 }
4312 }
4313
4314 if (default_case != NULL)
4315 default_case->lower(b, val_temp, default_start_label,
4316 default_finish_label);
4317 }
4318
4319 // Determine types.
4320
4321 void
determine_types(Type * type)4322 Case_clauses::determine_types(Type* type)
4323 {
4324 for (Clauses::iterator p = this->clauses_.begin();
4325 p != this->clauses_.end();
4326 ++p)
4327 p->determine_types(type);
4328 }
4329
4330 // Check types. Returns false if there was an error.
4331
4332 bool
check_types(Type * type)4333 Case_clauses::check_types(Type* type)
4334 {
4335 bool ret = true;
4336 for (Clauses::iterator p = this->clauses_.begin();
4337 p != this->clauses_.end();
4338 ++p)
4339 {
4340 if (!p->check_types(type))
4341 ret = false;
4342 }
4343 return ret;
4344 }
4345
4346 // Return true if these clauses may fall through to the statements
4347 // following the switch statement.
4348
4349 bool
may_fall_through() const4350 Case_clauses::may_fall_through() const
4351 {
4352 bool found_default = false;
4353 for (Clauses::const_iterator p = this->clauses_.begin();
4354 p != this->clauses_.end();
4355 ++p)
4356 {
4357 if (p->may_fall_through() && !p->is_fallthrough())
4358 return true;
4359 if (p->is_default())
4360 found_default = true;
4361 }
4362 return !found_default;
4363 }
4364
4365 // Convert the cases to the backend representation. This sets
4366 // *ALL_CASES and *ALL_STATEMENTS.
4367
4368 void
get_backend(Translate_context * context,Unnamed_label * break_label,std::vector<std::vector<Bexpression * >> * all_cases,std::vector<Bstatement * > * all_statements) const4369 Case_clauses::get_backend(Translate_context* context,
4370 Unnamed_label* break_label,
4371 std::vector<std::vector<Bexpression*> >* all_cases,
4372 std::vector<Bstatement*>* all_statements) const
4373 {
4374 Case_constants case_constants;
4375
4376 size_t c = this->clauses_.size();
4377 all_cases->resize(c);
4378 all_statements->resize(c);
4379
4380 size_t i = 0;
4381 for (Clauses::const_iterator p = this->clauses_.begin();
4382 p != this->clauses_.end();
4383 ++p, ++i)
4384 {
4385 std::vector<Bexpression*> cases;
4386 Bstatement* stat = p->get_backend(context, break_label, &case_constants,
4387 &cases);
4388 // The final clause can't fall through.
4389 if (i == c - 1 && p->is_fallthrough())
4390 {
4391 go_assert(saw_errors());
4392 stat = context->backend()->error_statement();
4393 }
4394 (*all_cases)[i].swap(cases);
4395 (*all_statements)[i] = stat;
4396 }
4397 }
4398
4399 // Dump the AST representation for case clauses (from a switch statement)
4400
4401 void
dump_clauses(Ast_dump_context * ast_dump_context) const4402 Case_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
4403 {
4404 for (Clauses::const_iterator p = this->clauses_.begin();
4405 p != this->clauses_.end();
4406 ++p)
4407 p->dump_clause(ast_dump_context);
4408 }
4409
4410 // A constant switch statement. A Switch_statement is lowered to this
4411 // when all the cases are constants.
4412
4413 class Constant_switch_statement : public Statement
4414 {
4415 public:
Constant_switch_statement(Expression * val,Case_clauses * clauses,Unnamed_label * break_label,Location location)4416 Constant_switch_statement(Expression* val, Case_clauses* clauses,
4417 Unnamed_label* break_label,
4418 Location location)
4419 : Statement(STATEMENT_CONSTANT_SWITCH, location),
4420 val_(val), clauses_(clauses), break_label_(break_label)
4421 { }
4422
4423 protected:
4424 int
4425 do_traverse(Traverse*);
4426
4427 void
4428 do_determine_types();
4429
4430 void
4431 do_check_types(Gogo*);
4432
4433 Bstatement*
4434 do_get_backend(Translate_context*);
4435
4436 void
4437 do_dump_statement(Ast_dump_context*) const;
4438
4439 private:
4440 // The value to switch on.
4441 Expression* val_;
4442 // The case clauses.
4443 Case_clauses* clauses_;
4444 // The break label, if needed.
4445 Unnamed_label* break_label_;
4446 };
4447
4448 // Traversal.
4449
4450 int
do_traverse(Traverse * traverse)4451 Constant_switch_statement::do_traverse(Traverse* traverse)
4452 {
4453 if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT)
4454 return TRAVERSE_EXIT;
4455 return this->clauses_->traverse(traverse);
4456 }
4457
4458 // Determine types.
4459
4460 void
do_determine_types()4461 Constant_switch_statement::do_determine_types()
4462 {
4463 this->val_->determine_type_no_context();
4464 this->clauses_->determine_types(this->val_->type());
4465 }
4466
4467 // Check types.
4468
4469 void
do_check_types(Gogo *)4470 Constant_switch_statement::do_check_types(Gogo*)
4471 {
4472 if (!this->clauses_->check_types(this->val_->type()))
4473 this->set_is_error();
4474 }
4475
4476 // Convert to GENERIC.
4477
4478 Bstatement*
do_get_backend(Translate_context * context)4479 Constant_switch_statement::do_get_backend(Translate_context* context)
4480 {
4481 Bexpression* switch_val_expr = this->val_->get_backend(context);
4482
4483 Unnamed_label* break_label = this->break_label_;
4484 if (break_label == NULL)
4485 break_label = new Unnamed_label(this->location());
4486
4487 std::vector<std::vector<Bexpression*> > all_cases;
4488 std::vector<Bstatement*> all_statements;
4489 this->clauses_->get_backend(context, break_label, &all_cases,
4490 &all_statements);
4491
4492 Bfunction* bfunction = context->function()->func_value()->get_decl();
4493 Bstatement* switch_statement;
4494 switch_statement = context->backend()->switch_statement(bfunction,
4495 switch_val_expr,
4496 all_cases,
4497 all_statements,
4498 this->location());
4499 Bstatement* ldef = break_label->get_definition(context);
4500 return context->backend()->compound_statement(switch_statement, ldef);
4501 }
4502
4503 // Dump the AST representation for a constant switch statement.
4504
4505 void
do_dump_statement(Ast_dump_context * ast_dump_context) const4506 Constant_switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
4507 const
4508 {
4509 ast_dump_context->print_indent();
4510 ast_dump_context->ostream() << "switch ";
4511 ast_dump_context->dump_expression(this->val_);
4512
4513 if (ast_dump_context->dump_subblocks())
4514 {
4515 ast_dump_context->ostream() << " {" << std::endl;
4516 this->clauses_->dump_clauses(ast_dump_context);
4517 ast_dump_context->ostream() << "}";
4518 }
4519
4520 ast_dump_context->ostream() << std::endl;
4521 }
4522
4523 // Class Switch_statement.
4524
4525 // Traversal.
4526
4527 int
do_traverse(Traverse * traverse)4528 Switch_statement::do_traverse(Traverse* traverse)
4529 {
4530 if (this->val_ != NULL)
4531 {
4532 if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT)
4533 return TRAVERSE_EXIT;
4534 }
4535 return this->clauses_->traverse(traverse);
4536 }
4537
4538 // Lower a Switch_statement to a Constant_switch_statement or a series
4539 // of if statements.
4540
4541 Statement*
do_lower(Gogo *,Named_object *,Block * enclosing,Statement_inserter *)4542 Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
4543 Statement_inserter*)
4544 {
4545 Location loc = this->location();
4546
4547 if (this->val_ != NULL
4548 && (this->val_->is_error_expression()
4549 || this->val_->type()->is_error()))
4550 {
4551 go_assert(saw_errors());
4552 return Statement::make_error_statement(loc);
4553 }
4554
4555 if (this->val_ != NULL
4556 && this->val_->type()->integer_type() != NULL
4557 && !this->clauses_->empty()
4558 && this->clauses_->is_constant())
4559 return new Constant_switch_statement(this->val_, this->clauses_,
4560 this->break_label_, loc);
4561
4562 if (this->val_ != NULL
4563 && !this->val_->type()->is_comparable()
4564 && !Type::are_compatible_for_comparison(true, this->val_->type(),
4565 Type::make_nil_type(), NULL))
4566 {
4567 go_error_at(this->val_->location(),
4568 "cannot switch on value whose type may not be compared");
4569 return Statement::make_error_statement(loc);
4570 }
4571
4572 Block* b = new Block(enclosing, loc);
4573
4574 if (this->clauses_->empty())
4575 {
4576 Expression* val = this->val_;
4577 if (val == NULL)
4578 val = Expression::make_boolean(true, loc);
4579 return Statement::make_statement(val, true);
4580 }
4581
4582 // var val_temp VAL_TYPE = VAL
4583 Expression* val = this->val_;
4584 if (val == NULL)
4585 val = Expression::make_boolean(true, loc);
4586
4587 Type* type = val->type();
4588 if (type->is_abstract())
4589 type = type->make_non_abstract_type();
4590 Temporary_statement* val_temp = Statement::make_temporary(type, val, loc);
4591 b->add_statement(val_temp);
4592
4593 this->clauses_->lower(b, val_temp, this->break_label());
4594
4595 Statement* s = Statement::make_unnamed_label_statement(this->break_label_);
4596 b->add_statement(s);
4597
4598 return Statement::make_block_statement(b, loc);
4599 }
4600
4601 // Return the break label for this switch statement, creating it if
4602 // necessary.
4603
4604 Unnamed_label*
break_label()4605 Switch_statement::break_label()
4606 {
4607 if (this->break_label_ == NULL)
4608 this->break_label_ = new Unnamed_label(this->location());
4609 return this->break_label_;
4610 }
4611
4612 // Dump the AST representation for a switch statement.
4613
4614 void
do_dump_statement(Ast_dump_context * ast_dump_context) const4615 Switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
4616 {
4617 ast_dump_context->print_indent();
4618 ast_dump_context->ostream() << "switch ";
4619 if (this->val_ != NULL)
4620 {
4621 ast_dump_context->dump_expression(this->val_);
4622 }
4623 if (ast_dump_context->dump_subblocks())
4624 {
4625 ast_dump_context->ostream() << " {" << dsuffix(location()) << std::endl;
4626 this->clauses_->dump_clauses(ast_dump_context);
4627 ast_dump_context->print_indent();
4628 ast_dump_context->ostream() << "}";
4629 }
4630 ast_dump_context->ostream() << std::endl;
4631 }
4632
4633 // Return whether this switch may fall through.
4634
4635 bool
do_may_fall_through() const4636 Switch_statement::do_may_fall_through() const
4637 {
4638 if (this->clauses_ == NULL)
4639 return true;
4640
4641 // If we have a break label, then some case needed it. That implies
4642 // that the switch statement as a whole can fall through.
4643 if (this->break_label_ != NULL)
4644 return true;
4645
4646 return this->clauses_->may_fall_through();
4647 }
4648
4649 // Make a switch statement.
4650
4651 Switch_statement*
make_switch_statement(Expression * val,Location location)4652 Statement::make_switch_statement(Expression* val, Location location)
4653 {
4654 return new Switch_statement(val, location);
4655 }
4656
4657 // Class Type_case_clauses::Type_case_clause.
4658
4659 // Traversal.
4660
4661 int
traverse(Traverse * traverse)4662 Type_case_clauses::Type_case_clause::traverse(Traverse* traverse)
4663 {
4664 if (!this->is_default_
4665 && ((traverse->traverse_mask()
4666 & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0)
4667 && Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
4668 return TRAVERSE_EXIT;
4669 if (this->statements_ != NULL)
4670 return this->statements_->traverse(traverse);
4671 return TRAVERSE_CONTINUE;
4672 }
4673
4674 // Lower one clause in a type switch. Add statements to the block B.
4675 // The type descriptor we are switching on is in DESCRIPTOR_TEMP.
4676 // BREAK_LABEL is the label at the end of the type switch.
4677 // *STMTS_LABEL, if not NULL, is a label to put at the start of the
4678 // statements.
4679
4680 void
lower(Gogo * gogo,Type * switch_val_type,Block * b,Temporary_statement * descriptor_temp,Unnamed_label * break_label,Unnamed_label ** stmts_label) const4681 Type_case_clauses::Type_case_clause::lower(Gogo* gogo,
4682 Type* switch_val_type,
4683 Block* b,
4684 Temporary_statement* descriptor_temp,
4685 Unnamed_label* break_label,
4686 Unnamed_label** stmts_label) const
4687 {
4688 Location loc = this->location_;
4689
4690 Unnamed_label* next_case_label = NULL;
4691 if (!this->is_default_)
4692 {
4693 Type* type = this->type_;
4694
4695 std::string reason;
4696 if (switch_val_type->interface_type() != NULL
4697 && !type->is_nil_constant_as_type()
4698 && type->interface_type() == NULL
4699 && !switch_val_type->interface_type()->implements_interface(type,
4700 &reason))
4701 {
4702 if (reason.empty())
4703 go_error_at(this->location_, "impossible type switch case");
4704 else
4705 go_error_at(this->location_, "impossible type switch case (%s)",
4706 reason.c_str());
4707 }
4708
4709 Expression* ref = Expression::make_temporary_reference(descriptor_temp,
4710 loc);
4711
4712 Expression* cond;
4713 // The language permits case nil, which is of course a constant
4714 // rather than a type. It will appear here as an invalid
4715 // forwarding type.
4716 if (type->is_nil_constant_as_type())
4717 cond = Expression::make_binary(OPERATOR_EQEQ, ref,
4718 Expression::make_nil(loc),
4719 loc);
4720 else if (type->interface_type() == NULL)
4721 {
4722 if (!gogo->need_eqtype())
4723 cond = Expression::make_binary(OPERATOR_EQEQ, ref,
4724 Expression::make_type_descriptor(type, loc),
4725 loc);
4726 else
4727 cond = Runtime::make_call(Runtime::EQTYPE, loc, 2,
4728 Expression::make_type_descriptor(type, loc),
4729 ref);
4730 }
4731 else
4732 cond = Runtime::make_call(Runtime::IFACET2IP, loc, 2,
4733 Expression::make_type_descriptor(type, loc),
4734 ref);
4735
4736 Unnamed_label* dest;
4737 if (!this->is_fallthrough_)
4738 {
4739 // if !COND { goto NEXT_CASE_LABEL }
4740 next_case_label = new Unnamed_label(Linemap::unknown_location());
4741 dest = next_case_label;
4742 cond = Expression::make_unary(OPERATOR_NOT, cond, loc);
4743 }
4744 else
4745 {
4746 // if COND { goto STMTS_LABEL }
4747 go_assert(stmts_label != NULL);
4748 if (*stmts_label == NULL)
4749 *stmts_label = new Unnamed_label(Linemap::unknown_location());
4750 dest = *stmts_label;
4751 }
4752 Block* then_block = new Block(b, loc);
4753 Statement* s = Statement::make_goto_unnamed_statement(dest, loc);
4754 then_block->add_statement(s);
4755 s = Statement::make_if_statement(cond, then_block, NULL, loc);
4756 b->add_statement(s);
4757 }
4758
4759 if (this->statements_ != NULL
4760 || (!this->is_fallthrough_
4761 && stmts_label != NULL
4762 && *stmts_label != NULL))
4763 {
4764 go_assert(!this->is_fallthrough_);
4765 if (stmts_label != NULL && *stmts_label != NULL)
4766 {
4767 go_assert(!this->is_default_);
4768 if (this->statements_ != NULL)
4769 (*stmts_label)->set_location(this->statements_->start_location());
4770 Statement* s = Statement::make_unnamed_label_statement(*stmts_label);
4771 b->add_statement(s);
4772 *stmts_label = NULL;
4773 }
4774 if (this->statements_ != NULL)
4775 b->add_statement(Statement::make_block_statement(this->statements_,
4776 loc));
4777 }
4778
4779 if (this->is_fallthrough_)
4780 go_assert(next_case_label == NULL);
4781 else
4782 {
4783 Location gloc = (this->statements_ == NULL
4784 ? loc
4785 : this->statements_->end_location());
4786 b->add_statement(Statement::make_goto_unnamed_statement(break_label,
4787 gloc));
4788 if (next_case_label != NULL)
4789 {
4790 Statement* s =
4791 Statement::make_unnamed_label_statement(next_case_label);
4792 b->add_statement(s);
4793 }
4794 }
4795 }
4796
4797 // Return true if this type clause may fall through to the statements
4798 // following the switch.
4799
4800 bool
may_fall_through() const4801 Type_case_clauses::Type_case_clause::may_fall_through() const
4802 {
4803 if (this->is_fallthrough_)
4804 {
4805 // This case means that we automatically fall through to the
4806 // next case (it's used for T1 in case T1, T2:). It does not
4807 // mean that we fall through to the end of the type switch as a
4808 // whole. There is sure to be a next case and that next case
4809 // will determine whether we fall through to the statements
4810 // after the type switch.
4811 return false;
4812 }
4813 if (this->statements_ == NULL)
4814 return true;
4815 return this->statements_->may_fall_through();
4816 }
4817
4818 // Dump the AST representation for a type case clause
4819
4820 void
dump_clause(Ast_dump_context * ast_dump_context) const4821 Type_case_clauses::Type_case_clause::dump_clause(
4822 Ast_dump_context* ast_dump_context) const
4823 {
4824 ast_dump_context->print_indent();
4825 if (this->is_default_)
4826 {
4827 ast_dump_context->ostream() << "default:";
4828 }
4829 else
4830 {
4831 ast_dump_context->ostream() << "case ";
4832 ast_dump_context->dump_type(this->type_);
4833 ast_dump_context->ostream() << ":" ;
4834 }
4835 ast_dump_context->dump_block(this->statements_);
4836 if (this->is_fallthrough_)
4837 {
4838 ast_dump_context->print_indent();
4839 ast_dump_context->ostream() << " (fallthrough)" << std::endl;
4840 }
4841 }
4842
4843 // Class Type_case_clauses.
4844
4845 // Traversal.
4846
4847 int
traverse(Traverse * traverse)4848 Type_case_clauses::traverse(Traverse* traverse)
4849 {
4850 for (Type_clauses::iterator p = this->clauses_.begin();
4851 p != this->clauses_.end();
4852 ++p)
4853 {
4854 if (p->traverse(traverse) == TRAVERSE_EXIT)
4855 return TRAVERSE_EXIT;
4856 }
4857 return TRAVERSE_CONTINUE;
4858 }
4859
4860 // Check for duplicate types.
4861
4862 void
check_duplicates() const4863 Type_case_clauses::check_duplicates() const
4864 {
4865 typedef Unordered_set_hash(const Type*, Type_hash_identical,
4866 Type_identical) Types_seen;
4867 Types_seen types_seen;
4868 for (Type_clauses::const_iterator p = this->clauses_.begin();
4869 p != this->clauses_.end();
4870 ++p)
4871 {
4872 Type* t = p->type();
4873 if (t == NULL)
4874 continue;
4875 if (t->is_nil_constant_as_type())
4876 t = Type::make_nil_type();
4877 std::pair<Types_seen::iterator, bool> ins = types_seen.insert(t);
4878 if (!ins.second)
4879 go_error_at(p->location(), "duplicate type in switch");
4880 }
4881 }
4882
4883 // Lower the clauses in a type switch. Add statements to the block B.
4884 // The type descriptor we are switching on is in DESCRIPTOR_TEMP.
4885 // BREAK_LABEL is the label at the end of the type switch.
4886
4887 void
lower(Gogo * gogo,Type * switch_val_type,Block * b,Temporary_statement * descriptor_temp,Unnamed_label * break_label) const4888 Type_case_clauses::lower(Gogo* gogo, Type* switch_val_type,
4889 Block* b,
4890 Temporary_statement* descriptor_temp,
4891 Unnamed_label* break_label) const
4892 {
4893 const Type_case_clause* default_case = NULL;
4894
4895 Unnamed_label* stmts_label = NULL;
4896 for (Type_clauses::const_iterator p = this->clauses_.begin();
4897 p != this->clauses_.end();
4898 ++p)
4899 {
4900 if (!p->is_default())
4901 p->lower(gogo, switch_val_type, b, descriptor_temp, break_label,
4902 &stmts_label);
4903 else
4904 {
4905 // We are generating a series of tests, which means that we
4906 // need to move the default case to the end.
4907 default_case = &*p;
4908 }
4909 }
4910 go_assert(stmts_label == NULL);
4911
4912 if (default_case != NULL)
4913 default_case->lower(gogo, switch_val_type, b, descriptor_temp, break_label,
4914 NULL);
4915 }
4916
4917 // Return true if these clauses may fall through to the statements
4918 // following the switch statement.
4919
4920 bool
may_fall_through() const4921 Type_case_clauses::may_fall_through() const
4922 {
4923 bool found_default = false;
4924 for (Type_clauses::const_iterator p = this->clauses_.begin();
4925 p != this->clauses_.end();
4926 ++p)
4927 {
4928 if (p->may_fall_through())
4929 return true;
4930 if (p->is_default())
4931 found_default = true;
4932 }
4933 return !found_default;
4934 }
4935
4936 // Dump the AST representation for case clauses (from a switch statement)
4937
4938 void
dump_clauses(Ast_dump_context * ast_dump_context) const4939 Type_case_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
4940 {
4941 for (Type_clauses::const_iterator p = this->clauses_.begin();
4942 p != this->clauses_.end();
4943 ++p)
4944 p->dump_clause(ast_dump_context);
4945 }
4946
4947 // Class Type_switch_statement.
4948
4949 // Traversal.
4950
4951 int
do_traverse(Traverse * traverse)4952 Type_switch_statement::do_traverse(Traverse* traverse)
4953 {
4954 if (this->traverse_expression(traverse, &this->expr_) == TRAVERSE_EXIT)
4955 return TRAVERSE_EXIT;
4956 if (this->clauses_ != NULL)
4957 return this->clauses_->traverse(traverse);
4958 return TRAVERSE_CONTINUE;
4959 }
4960
4961 // Lower a type switch statement to a series of if statements. The gc
4962 // compiler is able to generate a table in some cases. However, that
4963 // does not work for us because we may have type descriptors in
4964 // different shared libraries, so we can't compare them with simple
4965 // equality testing.
4966
4967 Statement*
do_lower(Gogo * gogo,Named_object *,Block * enclosing,Statement_inserter *)4968 Type_switch_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
4969 Statement_inserter*)
4970 {
4971 const Location loc = this->location();
4972
4973 if (this->clauses_ != NULL)
4974 this->clauses_->check_duplicates();
4975
4976 Block* b = new Block(enclosing, loc);
4977
4978 Type* val_type = this->expr_->type();
4979 if (val_type->interface_type() == NULL)
4980 {
4981 if (!val_type->is_error())
4982 this->report_error(_("cannot type switch on non-interface value"));
4983 return Statement::make_error_statement(loc);
4984 }
4985
4986 Temporary_statement* val_temp =
4987 Statement::make_temporary(NULL, this->expr_, loc);
4988 b->add_statement(val_temp);
4989
4990 // var descriptor_temp DESCRIPTOR_TYPE
4991 Type* descriptor_type = Type::make_type_descriptor_ptr_type();
4992 Temporary_statement* descriptor_temp =
4993 Statement::make_temporary(descriptor_type, NULL, loc);
4994 b->add_statement(descriptor_temp);
4995
4996 // descriptor_temp = ifacetype(val_temp)
4997 Expression* ref = Expression::make_temporary_reference(val_temp, loc);
4998 Expression* td = Expression::get_interface_type_descriptor(ref);
4999 Temporary_reference_expression* lhs =
5000 Expression::make_temporary_reference(descriptor_temp, loc);
5001 lhs->set_is_lvalue();
5002 Statement* s = Statement::make_assignment(lhs, td, loc);
5003 b->add_statement(s);
5004
5005 if (this->clauses_ != NULL)
5006 this->clauses_->lower(gogo, val_type, b, descriptor_temp, this->break_label());
5007
5008 s = Statement::make_unnamed_label_statement(this->break_label_);
5009 b->add_statement(s);
5010
5011 return Statement::make_block_statement(b, loc);
5012 }
5013
5014 // Return whether this switch may fall through.
5015
5016 bool
do_may_fall_through() const5017 Type_switch_statement::do_may_fall_through() const
5018 {
5019 if (this->clauses_ == NULL)
5020 return true;
5021
5022 // If we have a break label, then some case needed it. That implies
5023 // that the switch statement as a whole can fall through.
5024 if (this->break_label_ != NULL)
5025 return true;
5026
5027 return this->clauses_->may_fall_through();
5028 }
5029
5030 // Return the break label for this type switch statement, creating it
5031 // if necessary.
5032
5033 Unnamed_label*
break_label()5034 Type_switch_statement::break_label()
5035 {
5036 if (this->break_label_ == NULL)
5037 this->break_label_ = new Unnamed_label(this->location());
5038 return this->break_label_;
5039 }
5040
5041 // Dump the AST representation for a type switch statement
5042
5043 void
do_dump_statement(Ast_dump_context * ast_dump_context) const5044 Type_switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
5045 const
5046 {
5047 ast_dump_context->print_indent();
5048 ast_dump_context->ostream() << "switch ";
5049 if (!this->name_.empty())
5050 ast_dump_context->ostream() << this->name_ << " = ";
5051 ast_dump_context->dump_expression(this->expr_);
5052 ast_dump_context->ostream() << " .(type)";
5053 if (ast_dump_context->dump_subblocks())
5054 {
5055 ast_dump_context->ostream() << " {" << dsuffix(location()) << std::endl;
5056 this->clauses_->dump_clauses(ast_dump_context);
5057 ast_dump_context->ostream() << "}";
5058 }
5059 ast_dump_context->ostream() << std::endl;
5060 }
5061
5062 // Make a type switch statement.
5063
5064 Type_switch_statement*
make_type_switch_statement(const std::string & name,Expression * expr,Location location)5065 Statement::make_type_switch_statement(const std::string& name, Expression* expr,
5066 Location location)
5067 {
5068 return new Type_switch_statement(name, expr, location);
5069 }
5070
5071 // Class Send_statement.
5072
5073 // Traversal.
5074
5075 int
do_traverse(Traverse * traverse)5076 Send_statement::do_traverse(Traverse* traverse)
5077 {
5078 if (this->traverse_expression(traverse, &this->channel_) == TRAVERSE_EXIT)
5079 return TRAVERSE_EXIT;
5080 return this->traverse_expression(traverse, &this->val_);
5081 }
5082
5083 // Determine types.
5084
5085 void
do_determine_types()5086 Send_statement::do_determine_types()
5087 {
5088 this->channel_->determine_type_no_context();
5089 Type* type = this->channel_->type();
5090 Type_context context;
5091 if (type->channel_type() != NULL)
5092 context.type = type->channel_type()->element_type();
5093 this->val_->determine_type(&context);
5094 }
5095
5096 // Check types.
5097
5098 void
do_check_types(Gogo *)5099 Send_statement::do_check_types(Gogo*)
5100 {
5101 Type* type = this->channel_->type();
5102 if (type->is_error())
5103 {
5104 this->set_is_error();
5105 return;
5106 }
5107 Channel_type* channel_type = type->channel_type();
5108 if (channel_type == NULL)
5109 {
5110 go_error_at(this->location(), "left operand of %<<-%> must be channel");
5111 this->set_is_error();
5112 return;
5113 }
5114 Type* element_type = channel_type->element_type();
5115 if (!Type::are_assignable(element_type, this->val_->type(), NULL))
5116 {
5117 this->report_error(_("incompatible types in send"));
5118 return;
5119 }
5120 if (!channel_type->may_send())
5121 {
5122 this->report_error(_("invalid send on receive-only channel"));
5123 return;
5124 }
5125 }
5126
5127 // Flatten a send statement. We may need a temporary for interface
5128 // conversion.
5129
5130 Statement*
do_flatten(Gogo *,Named_object *,Block *,Statement_inserter * inserter)5131 Send_statement::do_flatten(Gogo*, Named_object*, Block*,
5132 Statement_inserter* inserter)
5133 {
5134 if (this->channel_->is_error_expression()
5135 || this->channel_->type()->is_error_type())
5136 {
5137 go_assert(saw_errors());
5138 return Statement::make_error_statement(this->location());
5139 }
5140
5141 Type* element_type = this->channel_->type()->channel_type()->element_type();
5142 if (!Type::are_identical(element_type, this->val_->type(),
5143 Type::COMPARE_ERRORS | Type::COMPARE_TAGS,
5144 NULL)
5145 && this->val_->type()->interface_type() != NULL
5146 && !this->val_->is_multi_eval_safe())
5147 {
5148 Temporary_statement* temp =
5149 Statement::make_temporary(NULL, this->val_, this->location());
5150 inserter->insert(temp);
5151 this->val_ = Expression::make_temporary_reference(temp,
5152 this->location());
5153 }
5154 return this;
5155 }
5156
5157 // Add explicit type conversions.
5158
5159 void
do_add_conversions()5160 Send_statement::do_add_conversions()
5161 {
5162 Type* lt = this->channel_->type()->channel_type()->element_type();
5163 Type* rt = this->val_->type();
5164 if (!Type::are_identical(lt, rt, 0, NULL)
5165 && lt->interface_type() != NULL)
5166 this->val_ = Expression::make_cast(lt, this->val_, this->location());
5167 }
5168
5169 // Convert a send statement to the backend representation.
5170
5171 Bstatement*
do_get_backend(Translate_context * context)5172 Send_statement::do_get_backend(Translate_context* context)
5173 {
5174 Location loc = this->location();
5175
5176 Channel_type* channel_type = this->channel_->type()->channel_type();
5177 Type* element_type = channel_type->element_type();
5178 Expression* val = Expression::convert_for_assignment(context->gogo(),
5179 element_type,
5180 this->val_, loc);
5181
5182 bool can_take_address;
5183 switch (element_type->base()->classification())
5184 {
5185 case Type::TYPE_BOOLEAN:
5186 case Type::TYPE_INTEGER:
5187 case Type::TYPE_FUNCTION:
5188 case Type::TYPE_POINTER:
5189 case Type::TYPE_MAP:
5190 case Type::TYPE_CHANNEL:
5191 case Type::TYPE_FLOAT:
5192 case Type::TYPE_COMPLEX:
5193 case Type::TYPE_STRING:
5194 case Type::TYPE_INTERFACE:
5195 can_take_address = false;
5196 break;
5197
5198 case Type::TYPE_STRUCT:
5199 can_take_address = true;
5200 break;
5201
5202 case Type::TYPE_ARRAY:
5203 can_take_address = !element_type->is_slice_type();
5204 break;
5205
5206 default:
5207 case Type::TYPE_ERROR:
5208 case Type::TYPE_VOID:
5209 case Type::TYPE_SINK:
5210 case Type::TYPE_NIL:
5211 case Type::TYPE_NAMED:
5212 case Type::TYPE_FORWARD:
5213 go_assert(saw_errors());
5214 return context->backend()->error_statement();
5215 }
5216
5217 // Only try to take the address of a variable. We have already
5218 // moved variables to the heap, so this should not cause that to
5219 // happen unnecessarily.
5220 if (can_take_address
5221 && val->var_expression() == NULL
5222 && val->temporary_reference_expression() == NULL)
5223 can_take_address = false;
5224
5225 Bstatement* btemp = NULL;
5226 if (can_take_address)
5227 {
5228 // The function doesn't change the value, so just take its
5229 // address directly.
5230 val = Expression::make_unary(OPERATOR_AND, val, loc);
5231 }
5232 else
5233 {
5234 // The value is not in a variable, or is small enough that it
5235 // might be in a register, and taking the address would push it
5236 // on the stack. Copy it into a temporary variable to take the
5237 // address.
5238 Temporary_statement* temp = Statement::make_temporary(element_type,
5239 val, loc);
5240 Expression* ref = Expression::make_temporary_reference(temp, loc);
5241 val = Expression::make_unary(OPERATOR_AND, ref, loc);
5242 btemp = temp->get_backend(context);
5243 }
5244
5245 Expression* call = Runtime::make_call(Runtime::CHANSEND, loc, 2,
5246 this->channel_, val);
5247
5248 context->gogo()->lower_expression(context->function(), NULL, &call);
5249 Bexpression* bcall = call->get_backend(context);
5250 Bfunction* bfunction = context->function()->func_value()->get_decl();
5251 Bstatement* s = context->backend()->expression_statement(bfunction, bcall);
5252
5253 if (btemp == NULL)
5254 return s;
5255 else
5256 return context->backend()->compound_statement(btemp, s);
5257 }
5258
5259 // Dump the AST representation for a send statement
5260
5261 void
do_dump_statement(Ast_dump_context * ast_dump_context) const5262 Send_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
5263 {
5264 ast_dump_context->print_indent();
5265 ast_dump_context->dump_expression(this->channel_);
5266 ast_dump_context->ostream() << " <- ";
5267 ast_dump_context->dump_expression(this->val_);
5268 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
5269 }
5270
5271 // Make a send statement.
5272
5273 Send_statement*
make_send_statement(Expression * channel,Expression * val,Location location)5274 Statement::make_send_statement(Expression* channel, Expression* val,
5275 Location location)
5276 {
5277 return new Send_statement(channel, val, location);
5278 }
5279
5280 // Class Select_clauses::Select_clause.
5281
5282 // Traversal.
5283
5284 int
traverse(Traverse * traverse)5285 Select_clauses::Select_clause::traverse(Traverse* traverse)
5286 {
5287 if (!this->is_lowered_
5288 && (traverse->traverse_mask()
5289 & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0)
5290 {
5291 if (this->channel_ != NULL)
5292 {
5293 if (Expression::traverse(&this->channel_, traverse) == TRAVERSE_EXIT)
5294 return TRAVERSE_EXIT;
5295 }
5296 if (this->val_ != NULL)
5297 {
5298 if (Expression::traverse(&this->val_, traverse) == TRAVERSE_EXIT)
5299 return TRAVERSE_EXIT;
5300 }
5301 if (this->closed_ != NULL)
5302 {
5303 if (Expression::traverse(&this->closed_, traverse) == TRAVERSE_EXIT)
5304 return TRAVERSE_EXIT;
5305 }
5306 }
5307 if (this->statements_ != NULL)
5308 {
5309 if (this->statements_->traverse(traverse) == TRAVERSE_EXIT)
5310 return TRAVERSE_EXIT;
5311 }
5312 return TRAVERSE_CONTINUE;
5313 }
5314
5315 // Lowering. We call a function to register this clause, and arrange
5316 // to set any variables in any receive clause.
5317
5318 void
lower(Gogo * gogo,Named_object * function,Block * b,Temporary_statement * scases,int index,Temporary_statement * recvok)5319 Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
5320 Block* b, Temporary_statement* scases,
5321 int index, Temporary_statement* recvok)
5322 {
5323 Location loc = this->location_;
5324
5325 this->set_case_index(index);
5326
5327 if (this->is_default_)
5328 {
5329 go_assert(this->channel_ == NULL && this->val_ == NULL);
5330 this->is_lowered_ = true;
5331 return;
5332 }
5333
5334 Expression* scase = Expression::make_temporary_reference(scases, loc);
5335 Expression* index_expr = Expression::make_integer_sl(index, NULL, loc);
5336 scase = Expression::make_array_index(scase, index_expr, NULL, NULL, loc);
5337
5338 // Evaluate the channel before the select statement.
5339 Temporary_statement* channel_temp = Statement::make_temporary(NULL,
5340 this->channel_,
5341 loc);
5342 b->add_statement(channel_temp);
5343 Expression* chanref = Expression::make_temporary_reference(channel_temp,
5344 loc);
5345
5346 if (this->is_send_)
5347 this->lower_send(b, scase, chanref);
5348 else
5349 this->lower_recv(gogo, function, b, scase, chanref, recvok);
5350
5351 // Now all references should be handled through the statements, not
5352 // through here.
5353 this->is_lowered_ = true;
5354 this->val_ = NULL;
5355 }
5356
5357 // Lower a send clause in a select statement.
5358
5359 void
lower_send(Block * b,Expression * scase,Expression * chanref)5360 Select_clauses::Select_clause::lower_send(Block* b, Expression* scase,
5361 Expression* chanref)
5362 {
5363 Location loc = this->location_;
5364
5365 Channel_type* ct = this->channel_->type()->channel_type();
5366 if (ct == NULL)
5367 return;
5368
5369 Type* valtype = ct->element_type();
5370
5371 // Note that copying the value to a temporary here means that we
5372 // evaluate the send values in the required order.
5373 Temporary_statement* val = Statement::make_temporary(valtype, this->val_,
5374 loc);
5375 // The value here escapes, because it might be sent on a channel.
5376 // We record that via the Temporary_statement, so that the escape
5377 // analysis pass can pick it up. The gc compiler lowers select
5378 // statements after escape analysis, so it doesn't have to worry
5379 // about this.
5380 val->set_value_escapes();
5381 b->add_statement(val);
5382
5383 Expression* valref = Expression::make_temporary_reference(val, loc);
5384 Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc);
5385 Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type());
5386 valaddr = Expression::make_cast(unsafe_pointer_type, valaddr, loc);
5387
5388 this->set_case(b, scase, chanref, valaddr);
5389 }
5390
5391 // Lower a receive clause in a select statement.
5392
5393 void
lower_recv(Gogo * gogo,Named_object * function,Block * b,Expression * scase,Expression * chanref,Temporary_statement * recvok)5394 Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function,
5395 Block* b, Expression* scase,
5396 Expression* chanref,
5397 Temporary_statement* recvok)
5398 {
5399 Location loc = this->location_;
5400
5401 Channel_type* ct = this->channel_->type()->channel_type();
5402 if (ct == NULL)
5403 return;
5404
5405 Type* valtype = ct->element_type();
5406 Temporary_statement* val = Statement::make_temporary(valtype, NULL, loc);
5407 b->add_statement(val);
5408
5409 Expression* valref = Expression::make_temporary_reference(val, loc);
5410 Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc);
5411 Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type());
5412 valaddr = Expression::make_cast(unsafe_pointer_type, valaddr, loc);
5413
5414 this->set_case(b, scase, chanref, valaddr);
5415
5416 // If the block of statements is executed, arrange for the received
5417 // value to move from VAL to the place where the statements expect
5418 // it.
5419
5420 Block* init = NULL;
5421
5422 if (this->var_ != NULL)
5423 {
5424 go_assert(this->val_ == NULL);
5425 valref = Expression::make_temporary_reference(val, loc);
5426 this->var_->var_value()->set_init(valref);
5427 this->var_->var_value()->clear_type_from_chan_element();
5428 }
5429 else if (this->val_ != NULL && !this->val_->is_sink_expression())
5430 {
5431 init = new Block(b, loc);
5432 valref = Expression::make_temporary_reference(val, loc);
5433 init->add_statement(Statement::make_assignment(this->val_, valref, loc));
5434 }
5435
5436 if (this->closedvar_ != NULL)
5437 {
5438 go_assert(this->closed_ == NULL);
5439 Expression* cref = Expression::make_temporary_reference(recvok, loc);
5440 this->closedvar_->var_value()->set_init(cref);
5441 }
5442 else if (this->closed_ != NULL && !this->closed_->is_sink_expression())
5443 {
5444 if (init == NULL)
5445 init = new Block(b, loc);
5446 Expression* cref = Expression::make_temporary_reference(recvok, loc);
5447 init->add_statement(Statement::make_assignment(this->closed_, cref,
5448 loc));
5449 }
5450
5451 if (init != NULL)
5452 {
5453 gogo->lower_block(function, init);
5454
5455 if (this->statements_ != NULL)
5456 init->add_statement(Statement::make_block_statement(this->statements_,
5457 loc));
5458 this->statements_ = init;
5459 }
5460 }
5461
5462 // Set the fields of an scase struct, an element in the array that we
5463 // pass to the runtime function selectgo.
5464
5465 void
set_case(Block * b,Expression * scase,Expression * chanref,Expression * elem)5466 Select_clauses::Select_clause::set_case(Block* b,
5467 Expression* scase,
5468 Expression* chanref,
5469 Expression* elem)
5470 {
5471 Location loc = this->location_;
5472 Struct_type* scase_type = scase->type()->struct_type();
5473
5474 int field_index = 0;
5475 go_assert(scase_type->field(field_index)->is_field_name("c"));
5476 Expression* ref = Expression::make_field_reference(scase, field_index, loc);
5477 Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type());
5478 chanref = Expression::make_unsafe_cast(unsafe_pointer_type, chanref, loc);
5479 Statement* s = Statement::make_assignment(ref, chanref, loc);
5480 b->add_statement(s);
5481
5482 if (elem != NULL)
5483 {
5484 field_index = 1;
5485 go_assert(scase_type->field(field_index)->is_field_name("elem"));
5486 ref = Expression::make_field_reference(scase->copy(), field_index, loc);
5487 s = Statement::make_assignment(ref, elem, loc);
5488 b->add_statement(s);
5489 }
5490 }
5491
5492 // Determine types.
5493
5494 void
determine_types()5495 Select_clauses::Select_clause::determine_types()
5496 {
5497 go_assert(this->is_lowered_);
5498 if (this->statements_ != NULL)
5499 this->statements_->determine_types();
5500 }
5501
5502 // Check types.
5503
5504 void
check_types()5505 Select_clauses::Select_clause::check_types()
5506 {
5507 if (this->is_default_)
5508 return;
5509
5510 Channel_type* ct = this->channel_->type()->channel_type();
5511 if (ct == NULL)
5512 {
5513 go_error_at(this->channel_->location(), "expected channel");
5514 return;
5515 }
5516
5517 if (this->is_send_ && !ct->may_send())
5518 go_error_at(this->location(), "invalid send on receive-only channel");
5519 else if (!this->is_send_ && !ct->may_receive())
5520 go_error_at(this->location(), "invalid receive on send-only channel");
5521 }
5522
5523 // Whether this clause may fall through to the statement which follows
5524 // the overall select statement.
5525
5526 bool
may_fall_through() const5527 Select_clauses::Select_clause::may_fall_through() const
5528 {
5529 if (this->statements_ == NULL)
5530 return true;
5531 return this->statements_->may_fall_through();
5532 }
5533
5534 // Return the backend representation for the statements to execute.
5535
5536 Bstatement*
get_statements_backend(Translate_context * context)5537 Select_clauses::Select_clause::get_statements_backend(
5538 Translate_context* context)
5539 {
5540 if (this->statements_ == NULL)
5541 return NULL;
5542 Bblock* bblock = this->statements_->get_backend(context);
5543 return context->backend()->block_statement(bblock);
5544 }
5545
5546 // Dump the AST representation for a select case clause
5547
5548 void
dump_clause(Ast_dump_context * ast_dump_context) const5549 Select_clauses::Select_clause::dump_clause(
5550 Ast_dump_context* ast_dump_context) const
5551 {
5552 ast_dump_context->print_indent();
5553 if (this->is_default_)
5554 {
5555 ast_dump_context->ostream() << "default:";
5556 }
5557 else
5558 {
5559 ast_dump_context->ostream() << "case " ;
5560 if (this->is_send_)
5561 {
5562 ast_dump_context->dump_expression(this->channel_);
5563 ast_dump_context->ostream() << " <- " ;
5564 if (this->val_ != NULL)
5565 ast_dump_context->dump_expression(this->val_);
5566 }
5567 else
5568 {
5569 if (this->val_ != NULL)
5570 ast_dump_context->dump_expression(this->val_);
5571 if (this->closed_ != NULL)
5572 {
5573 // FIXME: can val_ == NULL and closed_ ! = NULL?
5574 ast_dump_context->ostream() << " , " ;
5575 ast_dump_context->dump_expression(this->closed_);
5576 }
5577 if (this->closedvar_ != NULL || this->var_ != NULL)
5578 ast_dump_context->ostream() << " := " ;
5579
5580 ast_dump_context->ostream() << " <- " ;
5581 ast_dump_context->dump_expression(this->channel_);
5582 }
5583 ast_dump_context->ostream() << ":" ;
5584 }
5585 ast_dump_context->dump_block(this->statements_);
5586 }
5587
5588 // Class Select_clauses.
5589
5590 // Whether there is a default case.
5591
5592 bool
has_default() const5593 Select_clauses::has_default() const
5594 {
5595 for (Clauses::const_iterator p = this->clauses_.begin();
5596 p != this->clauses_.end();
5597 ++p)
5598 if (p->is_default())
5599 return true;
5600 return false;
5601 }
5602
5603 // Traversal.
5604
5605 int
traverse(Traverse * traverse)5606 Select_clauses::traverse(Traverse* traverse)
5607 {
5608 for (Clauses::iterator p = this->clauses_.begin();
5609 p != this->clauses_.end();
5610 ++p)
5611 {
5612 if (p->traverse(traverse) == TRAVERSE_EXIT)
5613 return TRAVERSE_EXIT;
5614 }
5615 return TRAVERSE_CONTINUE;
5616 }
5617
5618 // Lowering. Here we pull out the channel and the send values, to
5619 // enforce the order of evaluation. We also add explicit send and
5620 // receive statements to the clauses. This builds the entries in the
5621 // local array of scase values. It sets *P_SEND_COUNT and
5622 // *P_RECV_COUNT.
5623
5624 void
lower(Gogo * gogo,Named_object * function,Block * b,Temporary_statement * scases,Temporary_statement * recvok,int * p_send_count,int * p_recv_count)5625 Select_clauses::lower(Gogo* gogo, Named_object* function, Block* b,
5626 Temporary_statement* scases, Temporary_statement* recvok,
5627 int *p_send_count, int *p_recv_count)
5628 {
5629 int send_count = 0;
5630 int recv_count = 0;
5631 bool has_default = false;
5632 for (Clauses::iterator p = this->clauses_.begin();
5633 p != this->clauses_.end();
5634 ++p)
5635 {
5636 if (p->is_default())
5637 has_default = true;
5638 else if (p->is_send())
5639 ++send_count;
5640 else
5641 ++recv_count;
5642 }
5643
5644 *p_send_count = send_count;
5645 *p_recv_count = recv_count;
5646
5647 int send_index = 0;
5648 int recv_index = send_count;
5649 for (Clauses::iterator p = this->clauses_.begin();
5650 p != this->clauses_.end();
5651 ++p)
5652 {
5653 int index;
5654 if (p->is_default())
5655 index = -1;
5656 else if (p->is_send())
5657 {
5658 index = send_index;
5659 ++send_index;
5660 }
5661 else
5662 {
5663 index = recv_index;
5664 ++recv_index;
5665 }
5666
5667 p->lower(gogo, function, b, scases, index, recvok);
5668 }
5669
5670 go_assert(send_index == send_count);
5671 go_assert(recv_index == send_count + recv_count);
5672 go_assert(static_cast<size_t>(recv_index + (has_default ? 1 : 0))
5673 == this->size());
5674 }
5675
5676 // Determine types.
5677
5678 void
determine_types()5679 Select_clauses::determine_types()
5680 {
5681 for (Clauses::iterator p = this->clauses_.begin();
5682 p != this->clauses_.end();
5683 ++p)
5684 p->determine_types();
5685 }
5686
5687 // Check types.
5688
5689 void
check_types()5690 Select_clauses::check_types()
5691 {
5692 for (Clauses::iterator p = this->clauses_.begin();
5693 p != this->clauses_.end();
5694 ++p)
5695 p->check_types();
5696 }
5697
5698 // Return whether these select clauses fall through to the statement
5699 // following the overall select statement.
5700
5701 bool
may_fall_through() const5702 Select_clauses::may_fall_through() const
5703 {
5704 for (Clauses::const_iterator p = this->clauses_.begin();
5705 p != this->clauses_.end();
5706 ++p)
5707 if (p->may_fall_through())
5708 return true;
5709 return false;
5710 }
5711
5712 // Convert to the backend representation. Assemble the clauses and
5713 // build a switch statement on the index value returned by the call to
5714 // selectgo.
5715
5716 Bstatement*
get_backend(Translate_context * context,Temporary_statement * index,Unnamed_label * break_label,Location location)5717 Select_clauses::get_backend(Translate_context* context,
5718 Temporary_statement* index,
5719 Unnamed_label *break_label,
5720 Location location)
5721 {
5722 size_t count = this->clauses_.size();
5723 std::vector<std::vector<Bexpression*> > cases(count + 1);
5724 std::vector<Bstatement*> clauses(count + 1);
5725
5726 Type* int_type = Type::lookup_integer_type("int");
5727
5728 int i = 0;
5729 for (Clauses::iterator p = this->clauses_.begin();
5730 p != this->clauses_.end();
5731 ++p, ++i)
5732 {
5733 Expression* index_expr = Expression::make_integer_sl(p->case_index(),
5734 int_type,
5735 location);
5736 cases[i].push_back(index_expr->get_backend(context));
5737
5738 Bstatement* s = p->get_statements_backend(context);
5739 Location gloc = (p->statements() == NULL
5740 ? p->location()
5741 : p->statements()->end_location());
5742 Bstatement* g = break_label->get_goto(context, gloc);
5743
5744 if (s == NULL)
5745 clauses[i] = g;
5746 else
5747 clauses[i] = context->backend()->compound_statement(s, g);
5748 }
5749
5750 Expression* ref = Expression::make_temporary_reference(index, location);
5751 Bexpression* bindex = ref->get_backend(context);
5752
5753 Bfunction* bfunction = context->function()->func_value()->get_decl();
5754
5755 if (count == 0)
5756 return context->backend()->expression_statement(bfunction, bindex);
5757
5758 Expression* crash = Runtime::make_call(Runtime::UNREACHABLE, location, 0);
5759 Bexpression* bcrash = crash->get_backend(context);
5760 clauses[count] = context->backend()->expression_statement(bfunction, bcrash);
5761
5762 std::vector<Bstatement*> statements;
5763 statements.reserve(2);
5764
5765 Bstatement* switch_stmt = context->backend()->switch_statement(bfunction,
5766 bindex,
5767 cases,
5768 clauses,
5769 location);
5770 statements.push_back(switch_stmt);
5771
5772 Bstatement* ldef = break_label->get_definition(context);
5773 statements.push_back(ldef);
5774
5775 return context->backend()->statement_list(statements);
5776 }
5777
5778 // Dump the AST representation for select clauses.
5779
5780 void
dump_clauses(Ast_dump_context * ast_dump_context) const5781 Select_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
5782 {
5783 for (Clauses::const_iterator p = this->clauses_.begin();
5784 p != this->clauses_.end();
5785 ++p)
5786 p->dump_clause(ast_dump_context);
5787 }
5788
5789 // Class Select_statement.
5790
5791 // Return the break label for this switch statement, creating it if
5792 // necessary.
5793
5794 Unnamed_label*
break_label()5795 Select_statement::break_label()
5796 {
5797 if (this->break_label_ == NULL)
5798 this->break_label_ = new Unnamed_label(this->location());
5799 return this->break_label_;
5800 }
5801
5802 // Lower a select statement. This will return a block containing this
5803 // select statement. The block will implement the order of evaluation
5804 // rules, include the send and receive statements as explicit
5805 // statements in the clauses, and call the runtime selectgo function.
5806
5807 Statement*
do_lower(Gogo * gogo,Named_object * function,Block * enclosing,Statement_inserter *)5808 Select_statement::do_lower(Gogo* gogo, Named_object* function,
5809 Block* enclosing, Statement_inserter*)
5810 {
5811 if (this->is_lowered_)
5812 return this;
5813
5814 Location loc = this->location();
5815
5816 Block* b = new Block(enclosing, loc);
5817
5818 int ncases = this->clauses_->size();
5819 bool has_default = this->clauses_->has_default();
5820
5821 // Zero-case select. Just block the execution.
5822 if (ncases == 0)
5823 {
5824 Expression* call = Runtime::make_call(Runtime::BLOCK, loc, 0);
5825 Statement *s = Statement::make_statement(call, false);
5826 b->add_statement(s);
5827 this->is_lowered_ = true;
5828 return Statement::make_block_statement(b, loc);
5829 }
5830
5831 // One-case select. It is mostly just to run the case.
5832 if (ncases == 1)
5833 return this->lower_one_case(b);
5834
5835 // Two-case select with one default case. It is a non-blocking
5836 // send/receive.
5837 if (ncases == 2 && has_default)
5838 return this->lower_two_case(b);
5839
5840 // We don't allocate an entry in scases for the default case.
5841 if (has_default)
5842 --ncases;
5843
5844 Type* scase_type = Channel_type::select_case_type();
5845 Expression* ncases_expr =
5846 Expression::make_integer_ul(ncases, NULL,
5847 Linemap::predeclared_location());
5848 Array_type* scases_type = Type::make_array_type(scase_type, ncases_expr);
5849 scases_type->set_is_array_incomparable();
5850
5851 Temporary_statement* scases = Statement::make_temporary(scases_type, NULL,
5852 loc);
5853 b->add_statement(scases);
5854
5855 Expression* ncases2_expr =
5856 Expression::make_integer_ul(ncases * 2, NULL,
5857 Linemap::predeclared_location());
5858 Type* uint16_type = Type::lookup_integer_type("uint16");
5859 Array_type* order_type = Type::make_array_type(uint16_type, ncases2_expr);
5860 order_type->set_is_array_incomparable();
5861
5862 Temporary_statement* order = Statement::make_temporary(order_type, NULL,
5863 loc);
5864 b->add_statement(order);
5865
5866 Type* int_type = Type::lookup_integer_type("int");
5867 this->index_ = Statement::make_temporary(int_type, NULL, loc);
5868 b->add_statement(this->index_);
5869
5870 Type* bool_type = Type::lookup_bool_type();
5871 Temporary_statement* recvok = Statement::make_temporary(bool_type, NULL,
5872 loc);
5873 b->add_statement(recvok);
5874
5875 // Initialize the scases array.
5876 int send_count;
5877 int recv_count;
5878 this->clauses_->lower(gogo, function, b, scases, recvok, &send_count,
5879 &recv_count);
5880
5881 // Build the call to selectgo. Later, in do_get_backend, we will
5882 // build a switch on the result that branches to the various cases.
5883
5884 Expression* scases_ref = Expression::make_temporary_reference(scases, loc);
5885 scases_ref = Expression::make_unary(OPERATOR_AND, scases_ref, loc);
5886 Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type());
5887 scases_ref = Expression::make_cast(unsafe_pointer_type, scases_ref, loc);
5888
5889 Expression* order_ref = Expression::make_temporary_reference(order, loc);
5890 order_ref = Expression::make_unary(OPERATOR_AND, order_ref, loc);
5891 order_ref = Expression::make_cast(unsafe_pointer_type, order_ref, loc);
5892
5893 Expression* send_count_expr = Expression::make_integer_sl(send_count,
5894 int_type,
5895 loc);
5896 Expression* recv_count_expr = Expression::make_integer_sl(recv_count,
5897 int_type,
5898 loc);
5899 Expression* block_expr = Expression::make_boolean(!has_default, loc);
5900
5901 Call_expression* call = Runtime::make_call(Runtime::SELECTGO, loc, 5,
5902 scases_ref, order_ref,
5903 send_count_expr, recv_count_expr,
5904 block_expr);
5905
5906 Expression* result = Expression::make_call_result(call, 0);
5907 Expression* ref = Expression::make_temporary_reference(this->index_, loc);
5908 Statement* s = Statement::make_assignment(ref, result, loc);
5909 b->add_statement(s);
5910
5911 result = Expression::make_call_result(call, 1);
5912 ref = Expression::make_temporary_reference(recvok, loc);
5913 s = Statement::make_assignment(ref, result, loc);
5914 b->add_statement(s);
5915
5916 this->is_lowered_ = true;
5917 b->add_statement(this);
5918
5919 return Statement::make_block_statement(b, loc);
5920 }
5921
5922 // Lower a one-case select statement.
5923
5924 Statement*
lower_one_case(Block * b)5925 Select_statement::lower_one_case(Block* b)
5926 {
5927 Select_clauses::Select_clause& scase = this->clauses_->at(0);
5928 Location loc = this->location();
5929 Expression* chan = scase.channel();
5930 if (chan != NULL)
5931 {
5932 // Lower this to
5933 // if chan == nil { block() }; send/recv; body
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 Expression* nil = Expression::make_nil(loc);
5939 Expression* cond = Expression::make_binary(OPERATOR_EQEQ, chanref, nil, loc);
5940 Block* bnil = new Block(b, loc);
5941 Expression* call = Runtime::make_call(Runtime::BLOCK, loc, 0);
5942 Statement* s = Statement::make_statement(call, false);
5943 bnil->add_statement(s);
5944 Statement* ifs = Statement::make_if_statement(cond, bnil, NULL, loc);
5945 b->add_statement(ifs);
5946
5947 chanref = chanref->copy();
5948 Location cloc = scase.location();
5949 if (scase.is_send())
5950 {
5951 s = Statement::make_send_statement(chanref, scase.val(), cloc);
5952 b->add_statement(s);
5953 }
5954 else
5955 {
5956 if (scase.closed() == NULL && scase.closedvar() == NULL)
5957 {
5958 // Simple receive.
5959 Expression* recv = Expression::make_receive(chanref, cloc);
5960 if (scase.val() != NULL)
5961 s = Statement::make_assignment(scase.val(), recv, cloc);
5962 else if (scase.var() != NULL)
5963 {
5964 Temporary_statement *ts =
5965 Statement::make_temporary(NULL, recv, cloc);
5966 Expression* ref =
5967 Expression::make_temporary_reference(ts, cloc);
5968 s = ts;
5969 scase.var()->var_value()->set_init(ref);
5970 scase.var()->var_value()->clear_type_from_chan_element();
5971 }
5972 else
5973 s = Statement::make_statement(recv, false);
5974 b->add_statement(s);
5975 }
5976 else
5977 {
5978 // Tuple receive.
5979 Expression* lhs;
5980 if (scase.val() != NULL)
5981 lhs = scase.val();
5982 else
5983 {
5984 Type* valtype = chan->type()->channel_type()->element_type();
5985 Temporary_statement *ts =
5986 Statement::make_temporary(valtype, NULL, cloc);
5987 lhs = Expression::make_temporary_reference(ts, cloc);
5988 b->add_statement(ts);
5989 }
5990
5991 Expression* lhs2;
5992 if (scase.closed() != NULL)
5993 lhs2 = scase.closed();
5994 else
5995 {
5996 Type* booltype = Type::make_boolean_type();
5997 Temporary_statement *ts =
5998 Statement::make_temporary(booltype, NULL, cloc);
5999 lhs2 = Expression::make_temporary_reference(ts, cloc);
6000 b->add_statement(ts);
6001 }
6002
6003 s = Statement::make_tuple_receive_assignment(lhs, lhs2, chanref, cloc);
6004 b->add_statement(s);
6005
6006 if (scase.var() != NULL)
6007 {
6008 scase.var()->var_value()->set_init(lhs->copy());
6009 scase.var()->var_value()->clear_type_from_chan_element();
6010 }
6011
6012 if (scase.closedvar() != NULL)
6013 scase.closedvar()->var_value()->set_init(lhs2->copy());
6014 }
6015 }
6016 }
6017
6018 Statement* bs =
6019 Statement::make_block_statement(scase.statements(), scase.location());
6020 b->add_statement(bs);
6021
6022 Statement* label =
6023 Statement::make_unnamed_label_statement(this->break_label());
6024 b->add_statement(label);
6025
6026 this->is_lowered_ = true;
6027 return Statement::make_block_statement(b, loc);
6028 }
6029
6030 // Lower a two-case select statement with one default case.
6031
6032 Statement*
lower_two_case(Block * b)6033 Select_statement::lower_two_case(Block* b)
6034 {
6035 Select_clauses::Select_clause& chancase =
6036 (this->clauses_->at(0).is_default()
6037 ? this->clauses_->at(1)
6038 : this->clauses_->at(0));
6039 Select_clauses::Select_clause& defcase =
6040 (this->clauses_->at(0).is_default()
6041 ? this->clauses_->at(0)
6042 : this->clauses_->at(1));
6043 Location loc = this->location();
6044 Expression* chan = chancase.channel();
6045 Type* valtype = chan->type()->channel_type()->element_type();
6046
6047 Temporary_statement* chantmp = Statement::make_temporary(NULL, chan, loc);
6048 b->add_statement(chantmp);
6049 Expression* chanref = Expression::make_temporary_reference(chantmp, loc);
6050
6051 Block* bchan;
6052 Expression* call;
6053 if (chancase.is_send())
6054 {
6055 // if selectnbsend(chan, &val) { body } else { default body }
6056
6057 Temporary_statement* ts =
6058 Statement::make_temporary(valtype, chancase.val(), loc);
6059 // Tell the escape analysis that the value escapes, as it may be sent
6060 // to a channel.
6061 ts->set_value_escapes();
6062 b->add_statement(ts);
6063
6064 Expression* ref = Expression::make_temporary_reference(ts, loc);
6065 Expression* addr = Expression::make_unary(OPERATOR_AND, ref, loc);
6066 call = Runtime::make_call(Runtime::SELECTNBSEND, loc, 2, chanref, addr);
6067 bchan = chancase.statements();
6068 }
6069 else
6070 {
6071 Temporary_statement* ts = Statement::make_temporary(valtype, NULL, loc);
6072 b->add_statement(ts);
6073
6074 Expression* ref = Expression::make_temporary_reference(ts, loc);
6075 Expression* addr = Expression::make_unary(OPERATOR_AND, ref, loc);
6076 Expression* okref = NULL;
6077 if (chancase.closed() == NULL && chancase.closedvar() == NULL)
6078 {
6079 // Simple receive.
6080 // if selectnbrecv(&lhs, chan) { body } else { default body }
6081 call = Runtime::make_call(Runtime::SELECTNBRECV, loc, 2, addr, chanref);
6082 }
6083 else
6084 {
6085 // Tuple receive.
6086 // if selectnbrecv2(&lhs, &ok, chan) { body } else { default body }
6087
6088 Type* booltype = Type::make_boolean_type();
6089 Temporary_statement* okts = Statement::make_temporary(booltype, NULL,
6090 loc);
6091 b->add_statement(okts);
6092
6093 okref = Expression::make_temporary_reference(okts, loc);
6094 Expression* okaddr = Expression::make_unary(OPERATOR_AND, okref, loc);
6095 call = Runtime::make_call(Runtime::SELECTNBRECV2, loc, 3, addr, okaddr,
6096 chanref);
6097 }
6098
6099 Location cloc = chancase.location();
6100 bchan = new Block(b, loc);
6101 if (chancase.val() != NULL && !chancase.val()->is_sink_expression())
6102 {
6103 Statement* as = Statement::make_assignment(chancase.val(), ref->copy(),
6104 cloc);
6105 bchan->add_statement(as);
6106 }
6107 else if (chancase.var() != NULL)
6108 {
6109 chancase.var()->var_value()->set_init(ref->copy());
6110 chancase.var()->var_value()->clear_type_from_chan_element();
6111 }
6112
6113 if (chancase.closed() != NULL && !chancase.closed()->is_sink_expression())
6114 {
6115 Statement* as = Statement::make_assignment(chancase.closed(),
6116 okref->copy(), cloc);
6117 bchan->add_statement(as);
6118 }
6119 else if (chancase.closedvar() != NULL)
6120 chancase.closedvar()->var_value()->set_init(okref->copy());
6121
6122 Statement* bs = Statement::make_block_statement(chancase.statements(),
6123 cloc);
6124 bchan->add_statement(bs);
6125 }
6126
6127 Statement* ifs =
6128 Statement::make_if_statement(call, bchan, defcase.statements(), loc);
6129 b->add_statement(ifs);
6130
6131 Statement* label =
6132 Statement::make_unnamed_label_statement(this->break_label());
6133 b->add_statement(label);
6134
6135 this->is_lowered_ = true;
6136 return Statement::make_block_statement(b, loc);
6137 }
6138
6139 // Whether the select statement itself may fall through to the following
6140 // statement.
6141
6142 bool
do_may_fall_through() const6143 Select_statement::do_may_fall_through() const
6144 {
6145 // A select statement is terminating if no break statement
6146 // refers to it and all of its clauses are terminating.
6147 if (this->break_label_ != NULL)
6148 return true;
6149 return this->clauses_->may_fall_through();
6150 }
6151
6152 // Return the backend representation for a select statement.
6153
6154 Bstatement*
do_get_backend(Translate_context * context)6155 Select_statement::do_get_backend(Translate_context* context)
6156 {
6157 return this->clauses_->get_backend(context, this->index_,
6158 this->break_label(), this->location());
6159 }
6160
6161 // Dump the AST representation for a select statement.
6162
6163 void
do_dump_statement(Ast_dump_context * ast_dump_context) const6164 Select_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
6165 {
6166 ast_dump_context->print_indent();
6167 ast_dump_context->ostream() << "select";
6168 if (ast_dump_context->dump_subblocks())
6169 {
6170 ast_dump_context->ostream() << " {" << dsuffix(location()) << std::endl;
6171 this->clauses_->dump_clauses(ast_dump_context);
6172 ast_dump_context->print_indent();
6173 ast_dump_context->ostream() << "}";
6174 }
6175 ast_dump_context->ostream() << std::endl;
6176 }
6177
6178 // Make a select statement.
6179
6180 Select_statement*
make_select_statement(Location location)6181 Statement::make_select_statement(Location location)
6182 {
6183 return new Select_statement(location);
6184 }
6185
6186 // Class For_statement.
6187
6188 // Traversal.
6189
6190 int
do_traverse(Traverse * traverse)6191 For_statement::do_traverse(Traverse* traverse)
6192 {
6193 if (this->init_ != NULL)
6194 {
6195 if (this->init_->traverse(traverse) == TRAVERSE_EXIT)
6196 return TRAVERSE_EXIT;
6197 }
6198 if (this->cond_ != NULL)
6199 {
6200 if (this->traverse_expression(traverse, &this->cond_) == TRAVERSE_EXIT)
6201 return TRAVERSE_EXIT;
6202 }
6203 if (this->post_ != NULL)
6204 {
6205 if (this->post_->traverse(traverse) == TRAVERSE_EXIT)
6206 return TRAVERSE_EXIT;
6207 }
6208 return this->statements_->traverse(traverse);
6209 }
6210
6211 // Lower a For_statement into if statements and gotos. Getting rid of
6212 // complex statements make it easier to handle garbage collection.
6213
6214 Statement*
do_lower(Gogo *,Named_object *,Block * enclosing,Statement_inserter *)6215 For_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
6216 Statement_inserter*)
6217 {
6218 Statement* s;
6219 Location loc = this->location();
6220
6221 Block* b = new Block(enclosing, this->location());
6222 if (this->init_ != NULL)
6223 {
6224 s = Statement::make_block_statement(this->init_,
6225 this->init_->start_location());
6226 b->add_statement(s);
6227 }
6228
6229 Unnamed_label* entry = NULL;
6230 if (this->cond_ != NULL)
6231 {
6232 entry = new Unnamed_label(this->location());
6233 b->add_statement(Statement::make_goto_unnamed_statement(entry, loc));
6234 }
6235
6236 Unnamed_label* top = new Unnamed_label(this->location());
6237 top->set_derived_from(this);
6238 b->add_statement(Statement::make_unnamed_label_statement(top));
6239
6240 s = Statement::make_block_statement(this->statements_,
6241 this->statements_->start_location());
6242 b->add_statement(s);
6243
6244 Location end_loc = this->statements_->end_location();
6245
6246 Unnamed_label* cont = this->continue_label_;
6247 if (cont != NULL)
6248 b->add_statement(Statement::make_unnamed_label_statement(cont));
6249
6250 if (this->post_ != NULL)
6251 {
6252 s = Statement::make_block_statement(this->post_,
6253 this->post_->start_location());
6254 b->add_statement(s);
6255 end_loc = this->post_->end_location();
6256 }
6257
6258 if (this->cond_ == NULL)
6259 b->add_statement(Statement::make_goto_unnamed_statement(top, end_loc));
6260 else
6261 {
6262 b->add_statement(Statement::make_unnamed_label_statement(entry));
6263
6264 Location cond_loc = this->cond_->location();
6265 Block* then_block = new Block(b, cond_loc);
6266 s = Statement::make_goto_unnamed_statement(top, cond_loc);
6267 then_block->add_statement(s);
6268
6269 s = Statement::make_if_statement(this->cond_, then_block, NULL, cond_loc);
6270 b->add_statement(s);
6271 }
6272
6273 Unnamed_label* brk = this->break_label_;
6274 if (brk != NULL)
6275 b->add_statement(Statement::make_unnamed_label_statement(brk));
6276
6277 b->set_end_location(end_loc);
6278
6279 Statement* bs = Statement::make_block_statement(b, loc);
6280 bs->block_statement()->set_is_lowered_for_statement();
6281 return bs;
6282 }
6283
6284 // Return the break label, creating it if necessary.
6285
6286 Unnamed_label*
break_label()6287 For_statement::break_label()
6288 {
6289 if (this->break_label_ == NULL)
6290 this->break_label_ = new Unnamed_label(this->location());
6291 return this->break_label_;
6292 }
6293
6294 // Return the continue LABEL_EXPR.
6295
6296 Unnamed_label*
continue_label()6297 For_statement::continue_label()
6298 {
6299 if (this->continue_label_ == NULL)
6300 this->continue_label_ = new Unnamed_label(this->location());
6301 return this->continue_label_;
6302 }
6303
6304 // Set the break and continue labels a for statement. This is used
6305 // when lowering a for range statement.
6306
6307 void
set_break_continue_labels(Unnamed_label * break_label,Unnamed_label * continue_label)6308 For_statement::set_break_continue_labels(Unnamed_label* break_label,
6309 Unnamed_label* continue_label)
6310 {
6311 go_assert(this->break_label_ == NULL && this->continue_label_ == NULL);
6312 this->break_label_ = break_label;
6313 this->continue_label_ = continue_label;
6314 }
6315
6316 // Whether the overall statement may fall through.
6317
6318 bool
do_may_fall_through() const6319 For_statement::do_may_fall_through() const
6320 {
6321 // A for loop is terminating if it has no condition and
6322 // no break statement.
6323 if(this->cond_ != NULL)
6324 return true;
6325 if(this->break_label_ != NULL)
6326 return true;
6327 return false;
6328 }
6329
6330 // Dump the AST representation for a for statement.
6331
6332 void
do_dump_statement(Ast_dump_context * ast_dump_context) const6333 For_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
6334 {
6335 if (this->init_ != NULL && ast_dump_context->dump_subblocks())
6336 {
6337 ast_dump_context->print_indent();
6338 ast_dump_context->indent();
6339 ast_dump_context->ostream() << "// INIT " << std::endl;
6340 ast_dump_context->dump_block(this->init_);
6341 ast_dump_context->unindent();
6342 }
6343 ast_dump_context->print_indent();
6344 ast_dump_context->ostream() << "for ";
6345 if (this->cond_ != NULL)
6346 ast_dump_context->dump_expression(this->cond_);
6347
6348 if (ast_dump_context->dump_subblocks())
6349 {
6350 ast_dump_context->ostream() << " {" << std::endl;
6351 ast_dump_context->dump_block(this->statements_);
6352 if (this->init_ != NULL)
6353 {
6354 ast_dump_context->print_indent();
6355 ast_dump_context->ostream() << "// POST " << std::endl;
6356 ast_dump_context->dump_block(this->post_);
6357 }
6358 ast_dump_context->unindent();
6359
6360 ast_dump_context->print_indent();
6361 ast_dump_context->ostream() << "}";
6362 }
6363
6364 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
6365 }
6366
6367 // Make a for statement.
6368
6369 For_statement*
make_for_statement(Block * init,Expression * cond,Block * post,Location location)6370 Statement::make_for_statement(Block* init, Expression* cond, Block* post,
6371 Location location)
6372 {
6373 return new For_statement(init, cond, post, location);
6374 }
6375
6376 // Class For_range_statement.
6377
6378 // Traversal.
6379
6380 int
do_traverse(Traverse * traverse)6381 For_range_statement::do_traverse(Traverse* traverse)
6382 {
6383 if (this->index_var_ != NULL)
6384 {
6385 if (this->traverse_expression(traverse, &this->index_var_)
6386 == TRAVERSE_EXIT)
6387 return TRAVERSE_EXIT;
6388 }
6389 if (this->value_var_ != NULL)
6390 {
6391 if (this->traverse_expression(traverse, &this->value_var_)
6392 == TRAVERSE_EXIT)
6393 return TRAVERSE_EXIT;
6394 }
6395 if (this->traverse_expression(traverse, &this->range_) == TRAVERSE_EXIT)
6396 return TRAVERSE_EXIT;
6397 return this->statements_->traverse(traverse);
6398 }
6399
6400 // Lower a for range statement. For simplicity we lower this into a
6401 // for statement, which will then be lowered in turn to goto
6402 // statements.
6403
6404 Statement*
do_lower(Gogo * gogo,Named_object *,Block * enclosing,Statement_inserter *)6405 For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
6406 Statement_inserter*)
6407 {
6408 Type* range_type = this->range_->type();
6409 if (range_type->points_to() != NULL
6410 && range_type->points_to()->array_type() != NULL
6411 && !range_type->points_to()->is_slice_type())
6412 range_type = range_type->points_to();
6413
6414 Type* index_type;
6415 Type* value_type = NULL;
6416 if (range_type->array_type() != NULL)
6417 {
6418 index_type = Type::lookup_integer_type("int");
6419 value_type = range_type->array_type()->element_type();
6420 }
6421 else if (range_type->is_string_type())
6422 {
6423 index_type = Type::lookup_integer_type("int");
6424 value_type = Type::lookup_integer_type("rune");
6425 }
6426 else if (range_type->map_type() != NULL)
6427 {
6428 index_type = range_type->map_type()->key_type();
6429 value_type = range_type->map_type()->val_type();
6430 }
6431 else if (range_type->channel_type() != NULL)
6432 {
6433 index_type = range_type->channel_type()->element_type();
6434 if (this->value_var_ != NULL)
6435 {
6436 if (!this->value_var_->type()->is_error())
6437 this->report_error(_("too many variables for range clause "
6438 "with channel"));
6439 return Statement::make_error_statement(this->location());
6440 }
6441 }
6442 else
6443 {
6444 this->report_error(_("range clause must have "
6445 "array, slice, string, map, or channel type"));
6446 return Statement::make_error_statement(this->location());
6447 }
6448
6449 // If there is only one iteration variable, and len(this->range_) is
6450 // constant, then we do not evaluate the range variable. len(x) is
6451 // a contant if x is a string constant or if x is an array. If x is
6452 // a constant then evaluating it won't make any difference, so the
6453 // only case to consider is when x is an array whose length is constant.
6454 bool eval = true;
6455 if ((this->value_var_ == NULL || this->value_var_->is_sink_expression())
6456 && range_type->array_type() != NULL
6457 && !range_type->is_slice_type()
6458 && Builtin_call_expression::array_len_is_constant(this->range_))
6459 eval = false;
6460
6461 Location loc = this->location();
6462 Block* temp_block = new Block(enclosing, loc);
6463
6464 Expression* orig_range_expr = this->range_;
6465 Named_object* range_object = NULL;
6466 Temporary_statement* range_temp = NULL;
6467 if (eval)
6468 {
6469 Var_expression* ve = this->range_->var_expression();
6470 if (ve != NULL)
6471 range_object = ve->named_object();
6472 else
6473 {
6474 range_temp = Statement::make_temporary(NULL, this->range_, loc);
6475 temp_block->add_statement(range_temp);
6476 this->range_ = NULL;
6477 }
6478 }
6479
6480 // Try to match "range clear" patterns and rewrite to simple runtime
6481 // calls.
6482 if (range_type->map_type() != NULL)
6483 {
6484 Statement* clear = this->lower_map_range_clear(range_type,
6485 enclosing,
6486 orig_range_expr,
6487 range_object,
6488 range_temp, loc);
6489 if (clear != NULL)
6490 {
6491 if (gogo->debug_optimization())
6492 go_debug(loc, "map range clear");
6493 temp_block->add_statement(clear);
6494 return Statement::make_block_statement(temp_block, loc);
6495 }
6496 }
6497 else if (range_type->array_type() != NULL)
6498 {
6499 // Slice or array.
6500 Statement* clear = this->lower_array_range_clear(gogo,
6501 range_type,
6502 orig_range_expr,
6503 temp_block,
6504 range_object,
6505 range_temp, loc);
6506 if (clear != NULL)
6507 {
6508 if (gogo->debug_optimization())
6509 go_debug(loc, "array range clear");
6510 temp_block->add_statement(clear);
6511 return Statement::make_block_statement(temp_block, loc);
6512 }
6513 }
6514
6515 Temporary_statement* index_temp = Statement::make_temporary(index_type,
6516 NULL, loc);
6517 temp_block->add_statement(index_temp);
6518
6519 Temporary_statement* value_temp = NULL;
6520 if (this->value_var_ != NULL && !this->value_var_->is_sink_expression())
6521 {
6522 value_temp = Statement::make_temporary(value_type, NULL, loc);
6523 temp_block->add_statement(value_temp);
6524 }
6525
6526 Block* body = new Block(temp_block, loc);
6527
6528 Block* init;
6529 Expression* cond;
6530 Block* iter_init;
6531 Block* post;
6532
6533 // Arrange to do a loop appropriate for the type. We will produce
6534 // for INIT ; COND ; POST {
6535 // ITER_INIT
6536 // INDEX = INDEX_TEMP
6537 // VALUE = VALUE_TEMP // If there is a value
6538 // original statements
6539 // }
6540
6541 if (range_type->is_slice_type())
6542 this->lower_range_slice(gogo, temp_block, body, range_object, range_temp,
6543 index_temp, value_temp, &init, &cond, &iter_init,
6544 &post);
6545 else if (range_type->array_type() != NULL)
6546 this->lower_range_array(gogo, temp_block, body, range_object, range_temp,
6547 index_temp, value_temp, &init, &cond, &iter_init,
6548 &post);
6549 else if (range_type->is_string_type())
6550 this->lower_range_string(gogo, temp_block, body, range_object, range_temp,
6551 index_temp, value_temp, &init, &cond, &iter_init,
6552 &post);
6553 else if (range_type->map_type() != NULL)
6554 this->lower_range_map(gogo, range_type->map_type(), temp_block, body,
6555 range_object, range_temp, index_temp, value_temp,
6556 &init, &cond, &iter_init, &post);
6557 else if (range_type->channel_type() != NULL)
6558 this->lower_range_channel(gogo, temp_block, body, range_object, range_temp,
6559 index_temp, value_temp, &init, &cond, &iter_init,
6560 &post);
6561 else
6562 go_unreachable();
6563
6564 if (iter_init != NULL)
6565 body->add_statement(Statement::make_block_statement(iter_init, loc));
6566
6567 if (this->index_var_ != NULL)
6568 {
6569 Statement* assign;
6570 Expression* index_ref =
6571 Expression::make_temporary_reference(index_temp, loc);
6572 if (this->value_var_ == NULL || this->value_var_->is_sink_expression())
6573 assign = Statement::make_assignment(this->index_var_, index_ref, loc);
6574 else
6575 {
6576 Expression_list* lhs = new Expression_list();
6577 lhs->push_back(this->index_var_);
6578 lhs->push_back(this->value_var_);
6579
6580 Expression_list* rhs = new Expression_list();
6581 rhs->push_back(index_ref);
6582 rhs->push_back(Expression::make_temporary_reference(value_temp, loc));
6583
6584 assign = Statement::make_tuple_assignment(lhs, rhs, loc);
6585 }
6586 body->add_statement(assign);
6587 }
6588
6589 body->add_statement(Statement::make_block_statement(this->statements_, loc));
6590
6591 body->set_end_location(this->statements_->end_location());
6592
6593 For_statement* loop = Statement::make_for_statement(init, cond, post,
6594 this->location());
6595 loop->add_statements(body);
6596 loop->set_break_continue_labels(this->break_label_, this->continue_label_);
6597
6598 temp_block->add_statement(loop);
6599
6600 return Statement::make_block_statement(temp_block, loc);
6601 }
6602
6603 // Return a reference to the range, which may be in RANGE_OBJECT or in
6604 // RANGE_TEMP.
6605
6606 Expression*
make_range_ref(Named_object * range_object,Temporary_statement * range_temp,Location loc)6607 For_range_statement::make_range_ref(Named_object* range_object,
6608 Temporary_statement* range_temp,
6609 Location loc)
6610 {
6611 if (range_object != NULL)
6612 return Expression::make_var_reference(range_object, loc);
6613 else
6614 return Expression::make_temporary_reference(range_temp, loc);
6615 }
6616
6617 // Return a call to the predeclared function FUNCNAME passing a
6618 // reference to the temporary variable ARG.
6619
6620 Call_expression*
call_builtin(Gogo * gogo,const char * funcname,Expression * arg,Location loc)6621 For_range_statement::call_builtin(Gogo* gogo, const char* funcname,
6622 Expression* arg,
6623 Location loc)
6624 {
6625 Named_object* no = gogo->lookup_global(funcname);
6626 go_assert(no != NULL && no->is_function_declaration());
6627 Expression* func = Expression::make_func_reference(no, NULL, loc);
6628 Expression_list* params = new Expression_list();
6629 params->push_back(arg);
6630 return Expression::make_call(func, params, false, loc);
6631 }
6632
6633 // Lower a for range over an array.
6634
6635 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)6636 For_range_statement::lower_range_array(Gogo* gogo,
6637 Block* enclosing,
6638 Block* body_block,
6639 Named_object* range_object,
6640 Temporary_statement* range_temp,
6641 Temporary_statement* index_temp,
6642 Temporary_statement* value_temp,
6643 Block** pinit,
6644 Expression** pcond,
6645 Block** piter_init,
6646 Block** ppost)
6647 {
6648 Location loc = this->location();
6649
6650 // The loop we generate:
6651 // len_temp := len(range)
6652 // range_temp := range
6653 // for index_temp = 0; index_temp < len_temp; index_temp++ {
6654 // value_temp = range_temp[index_temp]
6655 // index = index_temp
6656 // value = value_temp
6657 // original body
6658 // }
6659
6660 // Set *PINIT to
6661 // var len_temp int
6662 // len_temp = len(range)
6663 // index_temp = 0
6664
6665 Block* init = new Block(enclosing, loc);
6666
6667 Expression* len_arg;
6668 if (range_object == NULL && range_temp == NULL)
6669 {
6670 // Don't evaluate this->range_, just get its length.
6671 len_arg = this->range_;
6672 }
6673 else
6674 {
6675 Expression* ref = this->make_range_ref(range_object, range_temp, loc);
6676 range_temp = Statement::make_temporary(NULL, ref, loc);
6677 init->add_statement(range_temp);
6678 len_arg = ref;
6679 }
6680 Expression* len_call = this->call_builtin(gogo, "len", len_arg, loc);
6681 Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(),
6682 len_call, loc);
6683 init->add_statement(len_temp);
6684
6685 Expression* zexpr = Expression::make_integer_ul(0, NULL, loc);
6686
6687 Temporary_reference_expression* tref =
6688 Expression::make_temporary_reference(index_temp, loc);
6689 tref->set_is_lvalue();
6690 Statement* s = Statement::make_assignment(tref, zexpr, loc);
6691 init->add_statement(s);
6692
6693 *pinit = init;
6694
6695 // Set *PCOND to
6696 // index_temp < len_temp
6697
6698 Expression* ref = Expression::make_temporary_reference(index_temp, loc);
6699 Expression* ref2 = Expression::make_temporary_reference(len_temp, loc);
6700 Expression* lt = Expression::make_binary(OPERATOR_LT, ref, ref2, loc);
6701
6702 *pcond = lt;
6703
6704 // Set *PITER_INIT to
6705 // value_temp = range[index_temp]
6706
6707 Block* iter_init = NULL;
6708 if (value_temp != NULL)
6709 {
6710 iter_init = new Block(body_block, loc);
6711
6712 ref = Expression::make_temporary_reference(range_temp, loc);
6713 ref2 = Expression::make_temporary_reference(index_temp, loc);
6714 Expression* index = Expression::make_index(ref, ref2, NULL, NULL, loc);
6715
6716 tref = Expression::make_temporary_reference(value_temp, loc);
6717 tref->set_is_lvalue();
6718 s = Statement::make_assignment(tref, index, loc);
6719
6720 iter_init->add_statement(s);
6721 }
6722 *piter_init = iter_init;
6723
6724 // Set *PPOST to
6725 // index_temp++
6726
6727 Block* post = new Block(enclosing, loc);
6728 tref = Expression::make_temporary_reference(index_temp, loc);
6729 tref->set_is_lvalue();
6730 s = Statement::make_inc_statement(tref);
6731 post->add_statement(s);
6732 *ppost = post;
6733 }
6734
6735 // Lower a for range over a slice.
6736
6737 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)6738 For_range_statement::lower_range_slice(Gogo* gogo,
6739 Block* enclosing,
6740 Block* body_block,
6741 Named_object* range_object,
6742 Temporary_statement* range_temp,
6743 Temporary_statement* index_temp,
6744 Temporary_statement* value_temp,
6745 Block** pinit,
6746 Expression** pcond,
6747 Block** piter_init,
6748 Block** ppost)
6749 {
6750 Location loc = this->location();
6751
6752 // The loop we generate:
6753 // for_temp := range
6754 // len_temp := len(for_temp)
6755 // for index_temp = 0; index_temp < len_temp; index_temp++ {
6756 // value_temp = for_temp[index_temp]
6757 // index = index_temp
6758 // value = value_temp
6759 // original body
6760 // }
6761 //
6762 // Using for_temp means that we don't need to check bounds when
6763 // fetching range_temp[index_temp].
6764
6765 // Set *PINIT to
6766 // range_temp := range
6767 // var len_temp int
6768 // len_temp = len(range_temp)
6769 // index_temp = 0
6770
6771 Block* init = new Block(enclosing, loc);
6772
6773 Expression* ref = this->make_range_ref(range_object, range_temp, loc);
6774 Temporary_statement* for_temp = Statement::make_temporary(NULL, ref, loc);
6775 init->add_statement(for_temp);
6776
6777 ref = Expression::make_temporary_reference(for_temp, loc);
6778 Expression* len_call = this->call_builtin(gogo, "len", ref, loc);
6779 Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(),
6780 len_call, loc);
6781 init->add_statement(len_temp);
6782
6783 Expression* zexpr = Expression::make_integer_ul(0, NULL, loc);
6784
6785 Temporary_reference_expression* tref =
6786 Expression::make_temporary_reference(index_temp, loc);
6787 tref->set_is_lvalue();
6788 Statement* s = Statement::make_assignment(tref, zexpr, loc);
6789 init->add_statement(s);
6790
6791 *pinit = init;
6792
6793 // Set *PCOND to
6794 // index_temp < len_temp
6795
6796 ref = Expression::make_temporary_reference(index_temp, loc);
6797 Expression* ref2 = Expression::make_temporary_reference(len_temp, loc);
6798 Expression* lt = Expression::make_binary(OPERATOR_LT, ref, ref2, loc);
6799
6800 *pcond = lt;
6801
6802 // Set *PITER_INIT to
6803 // value_temp = range[index_temp]
6804
6805 Block* iter_init = NULL;
6806 if (value_temp != NULL)
6807 {
6808 iter_init = new Block(body_block, loc);
6809
6810 ref = Expression::make_temporary_reference(for_temp, loc);
6811 ref2 = Expression::make_temporary_reference(index_temp, loc);
6812 Expression* index = Expression::make_index(ref, ref2, NULL, NULL, loc);
6813
6814 tref = Expression::make_temporary_reference(value_temp, loc);
6815 tref->set_is_lvalue();
6816 s = Statement::make_assignment(tref, index, loc);
6817
6818 iter_init->add_statement(s);
6819 }
6820 *piter_init = iter_init;
6821
6822 // Set *PPOST to
6823 // index_temp++
6824
6825 Block* post = new Block(enclosing, loc);
6826 tref = Expression::make_temporary_reference(index_temp, loc);
6827 tref->set_is_lvalue();
6828 s = Statement::make_inc_statement(tref);
6829 post->add_statement(s);
6830 *ppost = post;
6831 }
6832
6833 // Lower a for range over a string.
6834
6835 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)6836 For_range_statement::lower_range_string(Gogo* gogo,
6837 Block* enclosing,
6838 Block* body_block,
6839 Named_object* range_object,
6840 Temporary_statement* range_temp,
6841 Temporary_statement* index_temp,
6842 Temporary_statement* value_temp,
6843 Block** pinit,
6844 Expression** pcond,
6845 Block** piter_init,
6846 Block** ppost)
6847 {
6848 Location loc = this->location();
6849
6850 // The loop we generate:
6851 // len_temp := len(range)
6852 // var next_index_temp int
6853 // for index_temp = 0; index_temp < len_temp; index_temp = next_index_temp {
6854 // value_temp = rune(range[index_temp])
6855 // if value_temp < utf8.RuneSelf {
6856 // next_index_temp = index_temp + 1
6857 // } else {
6858 // value_temp, next_index_temp = decoderune(range, index_temp)
6859 // }
6860 // index = index_temp
6861 // value = value_temp
6862 // // original body
6863 // }
6864
6865 // Set *PINIT to
6866 // len_temp := len(range)
6867 // var next_index_temp int
6868 // index_temp = 0
6869 // var value_temp rune // if value_temp not passed in
6870
6871 Block* init = new Block(enclosing, loc);
6872
6873 Expression* ref = this->make_range_ref(range_object, range_temp, loc);
6874 Call_expression* call = this->call_builtin(gogo, "len", ref, loc);
6875 Temporary_statement* len_temp =
6876 Statement::make_temporary(index_temp->type(), call, loc);
6877 init->add_statement(len_temp);
6878
6879 Temporary_statement* next_index_temp =
6880 Statement::make_temporary(index_temp->type(), NULL, loc);
6881 init->add_statement(next_index_temp);
6882
6883 Temporary_reference_expression* index_ref =
6884 Expression::make_temporary_reference(index_temp, loc);
6885 index_ref->set_is_lvalue();
6886 Expression* zexpr = Expression::make_integer_ul(0, index_temp->type(), loc);
6887 Statement* s = Statement::make_assignment(index_ref, zexpr, loc);
6888 init->add_statement(s);
6889
6890 Type* rune_type;
6891 if (value_temp != NULL)
6892 rune_type = value_temp->type();
6893 else
6894 {
6895 rune_type = Type::lookup_integer_type("rune");
6896 value_temp = Statement::make_temporary(rune_type, NULL, loc);
6897 init->add_statement(value_temp);
6898 }
6899
6900 *pinit = init;
6901
6902 // Set *PCOND to
6903 // index_temp < len_temp
6904
6905 index_ref = Expression::make_temporary_reference(index_temp, loc);
6906 Expression* len_ref =
6907 Expression::make_temporary_reference(len_temp, loc);
6908 *pcond = Expression::make_binary(OPERATOR_LT, index_ref, len_ref, loc);
6909
6910 // Set *PITER_INIT to
6911 // value_temp = rune(range[index_temp])
6912 // if value_temp < utf8.RuneSelf {
6913 // next_index_temp = index_temp + 1
6914 // } else {
6915 // value_temp, next_index_temp = decoderune(range, index_temp)
6916 // }
6917
6918 Block* iter_init = new Block(body_block, loc);
6919
6920 ref = this->make_range_ref(range_object, range_temp, loc);
6921 index_ref = Expression::make_temporary_reference(index_temp, loc);
6922 ref = Expression::make_string_index(ref, index_ref, NULL, loc);
6923 ref = Expression::make_cast(rune_type, ref, loc);
6924 Temporary_reference_expression* value_ref =
6925 Expression::make_temporary_reference(value_temp, loc);
6926 value_ref->set_is_lvalue();
6927 s = Statement::make_assignment(value_ref, ref, loc);
6928 iter_init->add_statement(s);
6929
6930 value_ref = Expression::make_temporary_reference(value_temp, loc);
6931 Expression* rune_self = Expression::make_integer_ul(0x80, rune_type, loc);
6932 Expression* cond = Expression::make_binary(OPERATOR_LT, value_ref, rune_self,
6933 loc);
6934
6935 Block* then_block = new Block(iter_init, loc);
6936
6937 Temporary_reference_expression* lhs =
6938 Expression::make_temporary_reference(next_index_temp, loc);
6939 lhs->set_is_lvalue();
6940 index_ref = Expression::make_temporary_reference(index_temp, loc);
6941 Expression* one = Expression::make_integer_ul(1, index_temp->type(), loc);
6942 Expression* sum = Expression::make_binary(OPERATOR_PLUS, index_ref, one,
6943 loc);
6944 s = Statement::make_assignment(lhs, sum, loc);
6945 then_block->add_statement(s);
6946
6947 Block* else_block = new Block(iter_init, loc);
6948
6949 ref = this->make_range_ref(range_object, range_temp, loc);
6950 index_ref = Expression::make_temporary_reference(index_temp, loc);
6951 call = Runtime::make_call(Runtime::DECODERUNE, loc, 2, ref, index_ref);
6952
6953 value_ref = Expression::make_temporary_reference(value_temp, loc);
6954 value_ref->set_is_lvalue();
6955 Expression* res = Expression::make_call_result(call, 0);
6956 s = Statement::make_assignment(value_ref, res, loc);
6957 else_block->add_statement(s);
6958
6959 lhs = Expression::make_temporary_reference(next_index_temp, loc);
6960 lhs->set_is_lvalue();
6961 res = Expression::make_call_result(call, 1);
6962 s = Statement::make_assignment(lhs, res, loc);
6963 else_block->add_statement(s);
6964
6965 s = Statement::make_if_statement(cond, then_block, else_block, loc);
6966 iter_init->add_statement(s);
6967
6968 *piter_init = iter_init;
6969
6970 // Set *PPOST to
6971 // index_temp = next_index_temp
6972
6973 Block* post = new Block(enclosing, loc);
6974
6975 index_ref = Expression::make_temporary_reference(index_temp, loc);
6976 index_ref->set_is_lvalue();
6977 ref = Expression::make_temporary_reference(next_index_temp, loc);
6978 s = Statement::make_assignment(index_ref, ref, loc);
6979
6980 post->add_statement(s);
6981 *ppost = post;
6982 }
6983
6984 // Lower a for range over a map.
6985
6986 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)6987 For_range_statement::lower_range_map(Gogo* gogo,
6988 Map_type* map_type,
6989 Block* enclosing,
6990 Block* body_block,
6991 Named_object* range_object,
6992 Temporary_statement* range_temp,
6993 Temporary_statement* index_temp,
6994 Temporary_statement* value_temp,
6995 Block** pinit,
6996 Expression** pcond,
6997 Block** piter_init,
6998 Block** ppost)
6999 {
7000 Location loc = this->location();
7001
7002 // The runtime uses a struct to handle ranges over a map. The
7003 // struct is built by Map_type::hiter_type for a specific map type.
7004
7005 // The loop we generate:
7006 // var hiter map_iteration_struct
7007 // for mapiterinit(type, range, &hiter); hiter.key != nil; mapiternext(&hiter) {
7008 // index_temp = *hiter.key
7009 // value_temp = *hiter.val
7010 // index = index_temp
7011 // value = value_temp
7012 // original body
7013 // }
7014
7015 // Set *PINIT to
7016 // var hiter map_iteration_struct
7017 // runtime.mapiterinit(type, range, &hiter)
7018
7019 Block* init = new Block(enclosing, loc);
7020
7021 Type* map_iteration_type = map_type->hiter_type(gogo);
7022 Temporary_statement* hiter = Statement::make_temporary(map_iteration_type,
7023 NULL, loc);
7024 init->add_statement(hiter);
7025
7026 Expression* p1 = Expression::make_type_descriptor(map_type, loc);
7027 Expression* p2 = this->make_range_ref(range_object, range_temp, loc);
7028 Expression* ref = Expression::make_temporary_reference(hiter, loc);
7029 Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
7030 Expression* call = Runtime::make_call(Runtime::MAPITERINIT, loc, 3,
7031 p1, p2, p3);
7032 init->add_statement(Statement::make_statement(call, true));
7033
7034 *pinit = init;
7035
7036 // Set *PCOND to
7037 // hiter.key != nil
7038
7039 ref = Expression::make_temporary_reference(hiter, loc);
7040 ref = Expression::make_field_reference(ref, 0, loc);
7041 Expression* ne = Expression::make_binary(OPERATOR_NOTEQ, ref,
7042 Expression::make_nil(loc),
7043 loc);
7044 *pcond = ne;
7045
7046 // Set *PITER_INIT to
7047 // index_temp = *hiter.key
7048 // value_temp = *hiter.val
7049
7050 Block* iter_init = new Block(body_block, loc);
7051
7052 Expression* lhs = Expression::make_temporary_reference(index_temp, loc);
7053 Expression* rhs = Expression::make_temporary_reference(hiter, loc);
7054 rhs = Expression::make_field_reference(ref, 0, loc);
7055 rhs = Expression::make_dereference(ref, Expression::NIL_CHECK_NOT_NEEDED,
7056 loc);
7057 Statement* set = Statement::make_assignment(lhs, rhs, loc);
7058 iter_init->add_statement(set);
7059
7060 if (value_temp != NULL)
7061 {
7062 lhs = Expression::make_temporary_reference(value_temp, loc);
7063 rhs = Expression::make_temporary_reference(hiter, loc);
7064 rhs = Expression::make_field_reference(rhs, 1, loc);
7065 rhs = Expression::make_dereference(rhs, Expression::NIL_CHECK_NOT_NEEDED,
7066 loc);
7067 set = Statement::make_assignment(lhs, rhs, loc);
7068 iter_init->add_statement(set);
7069 }
7070
7071 *piter_init = iter_init;
7072
7073 // Set *PPOST to
7074 // mapiternext(&hiter)
7075
7076 Block* post = new Block(enclosing, loc);
7077
7078 ref = Expression::make_temporary_reference(hiter, loc);
7079 p1 = Expression::make_unary(OPERATOR_AND, ref, loc);
7080 call = Runtime::make_call(Runtime::MAPITERNEXT, loc, 1, p1);
7081 post->add_statement(Statement::make_statement(call, true));
7082
7083 *ppost = post;
7084 }
7085
7086 // Lower a for range over a channel.
7087
7088 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)7089 For_range_statement::lower_range_channel(Gogo*,
7090 Block*,
7091 Block* body_block,
7092 Named_object* range_object,
7093 Temporary_statement* range_temp,
7094 Temporary_statement* index_temp,
7095 Temporary_statement* value_temp,
7096 Block** pinit,
7097 Expression** pcond,
7098 Block** piter_init,
7099 Block** ppost)
7100 {
7101 go_assert(value_temp == NULL);
7102
7103 Location loc = this->location();
7104
7105 // The loop we generate:
7106 // for {
7107 // index_temp, ok_temp = <-range
7108 // if !ok_temp {
7109 // break
7110 // }
7111 // index = index_temp
7112 // original body
7113 // }
7114
7115 // We have no initialization code, no condition, and no post code.
7116
7117 *pinit = NULL;
7118 *pcond = NULL;
7119 *ppost = NULL;
7120
7121 // Set *PITER_INIT to
7122 // index_temp, ok_temp = <-range
7123 // if !ok_temp {
7124 // break
7125 // }
7126
7127 Block* iter_init = new Block(body_block, loc);
7128
7129 Temporary_statement* ok_temp =
7130 Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
7131 iter_init->add_statement(ok_temp);
7132
7133 Expression* cref = this->make_range_ref(range_object, range_temp, loc);
7134 Temporary_reference_expression* iref =
7135 Expression::make_temporary_reference(index_temp, loc);
7136 iref->set_is_lvalue();
7137 Temporary_reference_expression* oref =
7138 Expression::make_temporary_reference(ok_temp, loc);
7139 oref->set_is_lvalue();
7140 Statement* s = Statement::make_tuple_receive_assignment(iref, oref, cref,
7141 loc);
7142 iter_init->add_statement(s);
7143
7144 Block* then_block = new Block(iter_init, loc);
7145 s = Statement::make_break_statement(this->break_label(), loc);
7146 then_block->add_statement(s);
7147
7148 oref = Expression::make_temporary_reference(ok_temp, loc);
7149 Expression* cond = Expression::make_unary(OPERATOR_NOT, oref, loc);
7150 s = Statement::make_if_statement(cond, then_block, NULL, loc);
7151 iter_init->add_statement(s);
7152
7153 *piter_init = iter_init;
7154 }
7155
7156 // Match
7157 //
7158 // for k := range m { delete(m, k) }
7159 //
7160 // Lower it to runtime.mapclear(TYPE, m) on match, return the statement
7161 // containing the call. Return NULL otherwise.
7162
7163 Statement*
lower_map_range_clear(Type * map_type,Block * enclosing,Expression * orig_range_expr,Named_object * range_object,Temporary_statement * range_temp,Location loc)7164 For_range_statement::lower_map_range_clear(Type* map_type,
7165 Block* enclosing,
7166 Expression* orig_range_expr,
7167 Named_object* range_object,
7168 Temporary_statement* range_temp,
7169 Location loc)
7170 {
7171 if (this->value_var_ != NULL)
7172 return NULL;
7173 if (this->index_var_ == NULL)
7174 return NULL;
7175
7176 // Require the loop index be a new variable. We cannot rewrite
7177 // if it is used outside of the loop.
7178 Var_expression* index_ve = this->index_var_->var_expression();
7179 if (index_ve == NULL)
7180 return NULL;
7181 Named_object* index_no = index_ve->named_object();
7182 if (enclosing->bindings()->lookup_local(index_no->name()) != index_no)
7183 return NULL;
7184
7185 // Match the body, a single call statement delete(m, k).
7186 const std::vector<Statement*>* statements = this->statements_->statements();
7187 if (statements->size() != 1)
7188 return NULL;
7189 Expression_statement* es = statements->at(0)->expression_statement();
7190 if (es == NULL)
7191 return NULL;
7192 Call_expression* call = es->expr()->call_expression();
7193 if (call == NULL || !call->is_builtin()
7194 || call->builtin_call_expression()->code()
7195 != Builtin_call_expression::BUILTIN_DELETE)
7196 return NULL;
7197 if (!Expression::is_same_variable(call->args()->at(0), orig_range_expr)
7198 || !Expression::is_same_variable(call->args()->at(1), this->index_var_))
7199 return NULL;
7200
7201 // Everything matches. Rewrite to mapclear(TYPE, MAP).
7202 Expression* e1 = Expression::make_type_descriptor(map_type, loc);
7203 Expression* e2 = this->make_range_ref(range_object, range_temp, loc);
7204 call = Runtime::make_call(Runtime::MAPCLEAR, loc, 2, e1, e2);
7205 return Statement::make_statement(call, true);
7206 }
7207
7208 // Match
7209 //
7210 // for i := range a { a[i] = zero }
7211 //
7212 // Lower it to call memclr on match, and return the statement. Return
7213 // NULL otherwise.
7214
7215 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)7216 For_range_statement::lower_array_range_clear(Gogo* gogo,
7217 Type* array_type,
7218 Expression* orig_range_expr,
7219 Block* temp_block,
7220 Named_object* range_object,
7221 Temporary_statement* range_temp,
7222 Location loc)
7223 {
7224 if (this->value_var_ != NULL)
7225 return NULL;
7226 if (this->index_var_ == NULL)
7227 return NULL;
7228
7229 // Match the body, a single assignment statement a[i] = zero.
7230 const std::vector<Statement*>* statements = this->statements_->statements();
7231 if (statements->size() != 1)
7232 return NULL;
7233 Assignment_statement* as = statements->at(0)->assignment_statement();
7234 if (as == NULL || !as->rhs()->is_zero_value())
7235 return NULL;
7236 if (as->lhs()->type()->interface_type() != NULL
7237 && as->rhs()->type()->interface_type() == NULL
7238 && !as->rhs()->type()->is_nil_type())
7239 // Implicit type conversion may change a zero value to non-zero, like
7240 // interface{}(0).
7241 return NULL;
7242 Array_index_expression* aie = as->lhs()->array_index_expression();
7243 if (aie == NULL || aie->end() != NULL
7244 || !Expression::is_same_variable(orig_range_expr, aie->array())
7245 || !Expression::is_same_variable(this->index_var_, aie->start()))
7246 return NULL;
7247
7248 // Everything matches. Rewrite to
7249 //
7250 // if len(a) != 0 {
7251 // tmp1 = &a[0]
7252 // tmp2 = len(a)*sizeof(elem(a))
7253 // memclr{NoHeap,Has}Pointers(tmp1, tmp2)
7254 // i = len(a) - 1
7255 // }
7256
7257 Type* elem_type = array_type->array_type()->element_type();
7258 int64_t elme_sz;
7259 bool ok = elem_type->backend_type_size(gogo, &elme_sz);
7260 if (!ok)
7261 return NULL;
7262
7263 Block* b = new Block(temp_block, loc);
7264
7265 Expression* ref;
7266 if (range_object == NULL && range_temp == NULL)
7267 // is_same_variable implies no side effect, so it is ok to copy.
7268 ref = orig_range_expr->copy();
7269 else
7270 ref = this->make_range_ref(range_object, range_temp, loc);
7271 Expression* len = this->call_builtin(gogo, "len", ref, loc);
7272 Temporary_statement* tslen = Statement::make_temporary(NULL, len, loc);
7273 temp_block->add_statement(tslen);
7274
7275 Expression* zero = Expression::make_integer_ul(0, this->index_var_->type(), loc);
7276 ref = ref->copy();
7277 Expression* elem = Expression::make_array_index(ref, zero, NULL, NULL, loc);
7278 elem->array_index_expression()->set_needs_bounds_check(false);
7279 Expression* e1 = Expression::make_unary(OPERATOR_AND, elem, loc);
7280 Temporary_statement* ts1 = Statement::make_temporary(NULL, e1, loc);
7281 b->add_statement(ts1);
7282
7283 len = Expression::make_temporary_reference(tslen, loc);
7284 Expression* sz = Expression::make_integer_int64(elme_sz, len->type(), loc);
7285 Expression* e2 = Expression::make_binary(OPERATOR_MULT, len, sz, loc);
7286 Temporary_statement* ts2 = Statement::make_temporary(NULL, e2, loc);
7287 b->add_statement(ts2);
7288
7289 Expression* ptr_arg = Expression::make_temporary_reference(ts1, loc);
7290 Expression* sz_arg = Expression::make_temporary_reference(ts2, loc);
7291 Expression* call;
7292 if (elem_type->has_pointer())
7293 call = Runtime::make_call(Runtime::MEMCLRHASPTR, loc, 2, ptr_arg, sz_arg);
7294 else
7295 {
7296 Type* int32_type = Type::lookup_integer_type("int32");
7297 Expression* zero32 = Expression::make_integer_ul(0, int32_type, loc);
7298 call = Runtime::make_call(Runtime::BUILTIN_MEMSET, loc, 3, ptr_arg,
7299 zero32, sz_arg);
7300 }
7301 Statement* cs3 = Statement::make_statement(call, true);
7302 b->add_statement(cs3);
7303
7304 len = Expression::make_temporary_reference(tslen, loc);
7305 Expression* one = Expression::make_integer_ul(1, len->type(), loc);
7306 Expression* rhs = Expression::make_binary(OPERATOR_MINUS, len, one, loc);
7307 Expression* lhs = this->index_var_->copy();
7308 Statement* as4 = Statement::make_assignment(lhs, rhs, loc);
7309 b->add_statement(as4);
7310
7311 len = Expression::make_temporary_reference(tslen, loc);
7312 zero = zero->copy();
7313 Expression* cond = Expression::make_binary(OPERATOR_NOTEQ, len, zero, loc);
7314 return Statement::make_if_statement(cond, b, NULL, loc);
7315 }
7316
7317 // Return the break LABEL_EXPR.
7318
7319 Unnamed_label*
break_label()7320 For_range_statement::break_label()
7321 {
7322 if (this->break_label_ == NULL)
7323 this->break_label_ = new Unnamed_label(this->location());
7324 return this->break_label_;
7325 }
7326
7327 // Return the continue LABEL_EXPR.
7328
7329 Unnamed_label*
continue_label()7330 For_range_statement::continue_label()
7331 {
7332 if (this->continue_label_ == NULL)
7333 this->continue_label_ = new Unnamed_label(this->location());
7334 return this->continue_label_;
7335 }
7336
7337 // Dump the AST representation for a for range statement.
7338
7339 void
do_dump_statement(Ast_dump_context * ast_dump_context) const7340 For_range_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
7341 {
7342
7343 ast_dump_context->print_indent();
7344 ast_dump_context->ostream() << "for ";
7345 ast_dump_context->dump_expression(this->index_var_);
7346 if (this->value_var_ != NULL)
7347 {
7348 ast_dump_context->ostream() << ", ";
7349 ast_dump_context->dump_expression(this->value_var_);
7350 }
7351
7352 ast_dump_context->ostream() << " = range ";
7353 ast_dump_context->dump_expression(this->range_);
7354 if (ast_dump_context->dump_subblocks())
7355 {
7356 ast_dump_context->ostream() << " {" << std::endl;
7357
7358 ast_dump_context->indent();
7359
7360 ast_dump_context->dump_block(this->statements_);
7361
7362 ast_dump_context->unindent();
7363 ast_dump_context->print_indent();
7364 ast_dump_context->ostream() << "}";
7365 }
7366 ast_dump_context->ostream() << dsuffix(location()) << std::endl;
7367 }
7368
7369 // Make a for statement with a range clause.
7370
7371 For_range_statement*
make_for_range_statement(Expression * index_var,Expression * value_var,Expression * range,Location location)7372 Statement::make_for_range_statement(Expression* index_var,
7373 Expression* value_var,
7374 Expression* range,
7375 Location location)
7376 {
7377 return new For_range_statement(index_var, value_var, range, location);
7378 }
7379