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