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