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