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