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