Mercurial > hg > CbC > CbC_gcc
comparison gcc/go/gofrontend/escape.cc @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | 84e7813d76e9 |
children |
comparison
equal
deleted
inserted
replaced
131:84e7813d76e9 | 145:1830386684a0 |
---|---|
509 || t->is_sink_type() | 509 || t->is_sink_type() |
510 || t->is_void_type() | 510 || t->is_void_type() |
511 || t->is_abstract()) | 511 || t->is_abstract()) |
512 return false; | 512 return false; |
513 | 513 |
514 int64_t size; | 514 bool big = false; |
515 bool ok = t->backend_type_size(context->gogo(), &size); | 515 if (t->struct_type() != NULL |
516 bool big = ok && (size < 0 || size > 10 * 1024 * 1024); | 516 || (t->array_type() != NULL && !t->is_slice_type())) |
517 { | |
518 int64_t size; | |
519 bool ok = t->backend_type_size(context->gogo(), &size); | |
520 big = ok && (size < 0 || size > 10 * 1024 * 1024); | |
521 } | |
517 | 522 |
518 if (this->expr() != NULL) | 523 if (this->expr() != NULL) |
519 { | 524 { |
520 if (this->expr()->allocation_expression() != NULL) | 525 if (this->expr()->allocation_expression() != NULL) |
521 { | 526 { |
522 ok = t->deref()->backend_type_size(context->gogo(), &size); | 527 Type* pt = t->deref(); |
523 big = big || size <= 0 || size >= (1 << 16); | 528 if (pt->struct_type() != NULL |
529 || (pt->array_type() != NULL && !pt->is_slice_type())) | |
530 { | |
531 int64_t size; | |
532 bool ok = pt->backend_type_size(context->gogo(), &size); | |
533 if (ok) | |
534 big = big || size <= 0 || size >= (1 << 16); | |
535 } | |
524 } | 536 } |
525 else if (this->expr()->call_expression() != NULL) | 537 else if (this->expr()->call_expression() != NULL) |
526 { | 538 { |
527 Call_expression* call = this->expr()->call_expression(); | 539 Call_expression* call = this->expr()->call_expression(); |
528 Func_expression* fn = call->fn()->func_expression(); | 540 Func_expression* fn = call->fn()->func_expression(); |
565 && this->expr()->is_sink_expression()) | 577 && this->expr()->is_sink_expression()) |
566 return true; | 578 return true; |
567 return false; | 579 return false; |
568 } | 580 } |
569 | 581 |
570 std::map<Named_object*, Node*> Node::objects; | 582 Unordered_map(Named_object*, Node*) Node::objects; |
571 std::map<Expression*, Node*> Node::expressions; | 583 Unordered_map(Expression*, Node*) Node::expressions; |
572 std::map<Statement*, Node*> Node::statements; | 584 Unordered_map(Statement*, Node*) Node::statements; |
573 std::vector<Node*> Node::indirects; | 585 std::vector<Node*> Node::indirects; |
574 | 586 |
575 // Make a object node or return a cached node for this object. | 587 // Make a object node or return a cached node for this object. |
576 | 588 |
577 Node* | 589 Node* |
578 Node::make_node(Named_object* no) | 590 Node::make_node(Named_object* no) |
579 { | 591 { |
580 if (Node::objects.find(no) != Node::objects.end()) | 592 std::pair<Named_object*, Node*> val(no, NULL); |
581 return Node::objects[no]; | 593 std::pair<Unordered_map(Named_object*, Node*)::iterator, bool> ins = |
582 | 594 Node::objects.insert(val); |
583 Node* n = new Node(no); | 595 if (ins.second) |
584 std::pair<Named_object*, Node*> val(no, n); | 596 ins.first->second = new Node(no); |
585 Node::objects.insert(val); | 597 return ins.first->second; |
586 return n; | |
587 } | 598 } |
588 | 599 |
589 // Make an expression node or return a cached node for this expression. | 600 // Make an expression node or return a cached node for this expression. |
590 | 601 |
591 Node* | 602 Node* |
592 Node::make_node(Expression* e) | 603 Node::make_node(Expression* e) |
593 { | 604 { |
594 if (Node::expressions.find(e) != Node::expressions.end()) | 605 std::pair<Expression*, Node*> val(e, NULL); |
595 return Node::expressions[e]; | 606 std::pair<Unordered_map(Expression*, Node*)::iterator, bool> ins = |
596 | 607 Node::expressions.insert(val); |
597 Node* n = new Node(e); | 608 if (ins.second) |
598 std::pair<Expression*, Node*> val(e, n); | 609 ins.first->second = new Node(e); |
599 Node::expressions.insert(val); | 610 return ins.first->second; |
600 return n; | |
601 } | 611 } |
602 | 612 |
603 // Make a statement node or return a cached node for this statement. | 613 // Make a statement node or return a cached node for this statement. |
604 | 614 |
605 Node* | 615 Node* |
606 Node::make_node(Statement* s) | 616 Node::make_node(Statement* s) |
607 { | 617 { |
608 if (Node::statements.find(s) != Node::statements.end()) | 618 std::pair<Statement*, Node*> val(s, NULL); |
609 return Node::statements[s]; | 619 std::pair<Unordered_map(Statement*, Node*)::iterator, bool> ins = |
610 | 620 Node::statements.insert(val); |
611 Node* n = new Node(s); | 621 if (ins.second) |
612 std::pair<Statement*, Node*> val(s, n); | 622 ins.first->second = new Node(s); |
613 Node::statements.insert(val); | 623 return ins.first->second; |
614 return n; | |
615 } | 624 } |
616 | 625 |
617 // Make an indirect node with given child. | 626 // Make an indirect node with given child. |
618 | 627 |
619 Node* | 628 Node* |
962 continue; | 971 continue; |
963 if (escapes[*n] != (*n)->encoding()) | 972 if (escapes[*n] != (*n)->encoding()) |
964 { | 973 { |
965 done = false; | 974 done = false; |
966 if (this->debug_escape_level() > 2) | 975 if (this->debug_escape_level() > 2) |
967 go_inform((*n)->location(), "Reflooding %s %s", | 976 go_debug((*n)->location(), "Reflooding %s %s", |
968 debug_function_name((*n)->state(context, NULL)->fn).c_str(), | 977 debug_function_name((*n)->state(context, NULL)->fn).c_str(), |
969 (*n)->ast_format(this).c_str()); | 978 (*n)->ast_format(this).c_str()); |
970 escapes[*n] = (*n)->encoding(); | 979 escapes[*n] = (*n)->encoding(); |
971 this->propagate_escape(context, *n); | 980 this->propagate_escape(context, *n); |
972 } | 981 } |
973 } | 982 } |
974 if (done) | 983 if (done) |
988 n != noesc.end(); | 997 n != noesc.end(); |
989 ++n) | 998 ++n) |
990 { | 999 { |
991 Node::Escape_state* state = (*n)->state(context, NULL); | 1000 Node::Escape_state* state = (*n)->state(context, NULL); |
992 if ((*n)->encoding() == Node::ESCAPE_NONE) | 1001 if ((*n)->encoding() == Node::ESCAPE_NONE) |
993 go_inform((*n)->location(), "%s %s does not escape", | 1002 go_debug((*n)->location(), "%s %s does not escape", |
994 strip_packed_prefix(this, debug_function_name(state->fn)).c_str(), | 1003 strip_packed_prefix(this, debug_function_name(state->fn)).c_str(), |
995 (*n)->ast_format(this).c_str()); | 1004 (*n)->ast_format(this).c_str()); |
996 } | 1005 } |
997 } | 1006 } |
998 delete context; | 1007 delete context; |
999 } | 1008 } |
1000 } | 1009 } |
1331 && s->expression_statement() == NULL | 1340 && s->expression_statement() == NULL |
1332 && !s->is_block_statement()) | 1341 && !s->is_block_statement()) |
1333 { | 1342 { |
1334 Node* n = Node::make_node(s); | 1343 Node* n = Node::make_node(s); |
1335 std::string fn_name = this->context_->current_function_name(); | 1344 std::string fn_name = this->context_->current_function_name(); |
1336 go_inform(s->location(), "[%d] %s esc: %s", | 1345 go_debug(s->location(), "[%d] %s esc: %s", |
1337 this->context_->loop_depth(), fn_name.c_str(), | 1346 this->context_->loop_depth(), fn_name.c_str(), |
1338 n->ast_format(gogo).c_str()); | 1347 n->ast_format(gogo).c_str()); |
1339 } | 1348 } |
1340 | 1349 |
1341 switch (s->classification()) | 1350 switch (s->classification()) |
1342 { | 1351 { |
1343 case Statement::STATEMENT_VARIABLE_DECLARATION: | 1352 case Statement::STATEMENT_VARIABLE_DECLARATION: |
1493 && !no->var_value()->is_global()) | 1502 && !no->var_value()->is_global()) |
1494 || no->is_result_variable()) | 1503 || no->is_result_variable()) |
1495 { | 1504 { |
1496 Node* n = Node::make_node(expr); | 1505 Node* n = Node::make_node(expr); |
1497 if (gogo->debug_escape_level() != 0) | 1506 if (gogo->debug_escape_level() != 0) |
1498 go_inform(n->definition_location(), | 1507 go_debug(n->definition_location(), |
1499 "moved to heap: %s", | 1508 "moved to heap: %s", |
1500 n->ast_format(gogo).c_str()); | 1509 n->ast_format(gogo).c_str()); |
1501 if (gogo->compiling_runtime() && gogo->package_name() == "runtime") | 1510 if (gogo->compiling_runtime() && gogo->package_name() == "runtime") |
1502 go_error_at(expr->location(), | 1511 go_error_at(expr->location(), |
1503 "%s escapes to heap, not allowed in runtime", | 1512 "%s escapes to heap, not allowed in runtime", |
1504 n->ast_format(gogo).c_str()); | 1513 n->ast_format(gogo).c_str()); |
1505 } | 1514 } |
1517 Node* n = Node::make_node(*pexpr); | 1526 Node* n = Node::make_node(*pexpr); |
1518 if ((n->encoding() & ESCAPE_MASK) != int(Node::ESCAPE_HEAP) | 1527 if ((n->encoding() & ESCAPE_MASK) != int(Node::ESCAPE_HEAP) |
1519 && n->is_big(this->context_)) | 1528 && n->is_big(this->context_)) |
1520 { | 1529 { |
1521 if (debug_level > 1) | 1530 if (debug_level > 1) |
1522 go_inform((*pexpr)->location(), "%s too large for stack", | 1531 go_debug((*pexpr)->location(), "%s too large for stack", |
1523 n->ast_format(gogo).c_str()); | 1532 n->ast_format(gogo).c_str()); |
1524 move_to_heap(gogo, *pexpr); | 1533 move_to_heap(gogo, *pexpr); |
1525 n->set_encoding(Node::ESCAPE_HEAP); | 1534 n->set_encoding(Node::ESCAPE_HEAP); |
1526 (*pexpr)->address_taken(true); | 1535 (*pexpr)->address_taken(true); |
1527 this->assign(this->context_->sink(), n); | 1536 this->assign(this->context_->sink(), n); |
1528 } | 1537 } |
1530 if ((*pexpr)->func_expression() == NULL) | 1539 if ((*pexpr)->func_expression() == NULL) |
1531 (*pexpr)->traverse_subexpressions(this); | 1540 (*pexpr)->traverse_subexpressions(this); |
1532 | 1541 |
1533 if (debug_level > 1) | 1542 if (debug_level > 1) |
1534 { | 1543 { |
1535 Node* n = Node::make_node(*pexpr); | |
1536 std::string fn_name = this->context_->current_function_name(); | 1544 std::string fn_name = this->context_->current_function_name(); |
1537 go_inform((*pexpr)->location(), "[%d] %s esc: %s", | 1545 go_debug((*pexpr)->location(), "[%d] %s esc: %s", |
1538 this->context_->loop_depth(), fn_name.c_str(), | 1546 this->context_->loop_depth(), fn_name.c_str(), |
1539 n->ast_format(gogo).c_str()); | 1547 n->ast_format(gogo).c_str()); |
1540 } | 1548 } |
1541 | 1549 |
1542 switch ((*pexpr)->classification()) | 1550 switch ((*pexpr)->classification()) |
1543 { | 1551 { |
1544 case Expression::EXPRESSION_CALL: | 1552 case Expression::EXPRESSION_CALL: |
1564 { | 1572 { |
1565 // append(slice1, slice2...) -- slice2 itself does not escape, but contents do | 1573 // append(slice1, slice2...) -- slice2 itself does not escape, but contents do |
1566 Node* appended = Node::make_node(call->args()->back()); | 1574 Node* appended = Node::make_node(call->args()->back()); |
1567 this->assign_deref(this->context_->sink(), appended); | 1575 this->assign_deref(this->context_->sink(), appended); |
1568 if (debug_level > 2) | 1576 if (debug_level > 2) |
1569 go_inform((*pexpr)->location(), | 1577 go_debug((*pexpr)->location(), |
1570 "special treatment of append(slice1, slice2...)"); | 1578 "special treatment of append(slice1, slice2...)"); |
1571 } | 1579 } |
1572 else | 1580 else |
1573 { | 1581 { |
1574 for (Expression_list::const_iterator pa = | 1582 for (Expression_list::const_iterator pa = |
1575 call->args()->begin() + 1; | 1583 call->args()->begin() + 1; |
1617 { | 1625 { |
1618 // Map key escapes. The last argument is the address | 1626 // Map key escapes. The last argument is the address |
1619 // of the key. | 1627 // of the key. |
1620 Node* key_node = Node::make_node(call->args()->back()); | 1628 Node* key_node = Node::make_node(call->args()->back()); |
1621 this->assign_deref(this->context_->sink(), key_node); | 1629 this->assign_deref(this->context_->sink(), key_node); |
1630 } | |
1631 break; | |
1632 | |
1633 case Runtime::MAPASSIGN_FAST32PTR: | |
1634 case Runtime::MAPASSIGN_FAST64PTR: | |
1635 case Runtime::MAPASSIGN_FASTSTR: | |
1636 { | |
1637 // Map key escapes. The last argument is the key. | |
1638 Node* key_node = Node::make_node(call->args()->back()); | |
1639 this->assign(this->context_->sink(), key_node); | |
1622 } | 1640 } |
1623 break; | 1641 break; |
1624 | 1642 |
1625 case Runtime::IFACEE2T2: | 1643 case Runtime::IFACEE2T2: |
1626 case Runtime::IFACEI2T2: | 1644 case Runtime::IFACEI2T2: |
1694 | 1712 |
1695 this->assign(tce_node, converted); | 1713 this->assign(tce_node, converted); |
1696 } | 1714 } |
1697 break; | 1715 break; |
1698 | 1716 |
1717 case Expression::EXPRESSION_UNSAFE_CONVERSION: | |
1718 { | |
1719 Unsafe_type_conversion_expression* uce = | |
1720 (*pexpr)->unsafe_conversion_expression(); | |
1721 Node* expr_node = Node::make_node(uce->expr()); | |
1722 this->assign(n, expr_node); | |
1723 } | |
1724 break; | |
1725 | |
1699 case Expression::EXPRESSION_FIXED_ARRAY_CONSTRUCTION: | 1726 case Expression::EXPRESSION_FIXED_ARRAY_CONSTRUCTION: |
1700 case Expression::EXPRESSION_SLICE_CONSTRUCTION: | 1727 case Expression::EXPRESSION_SLICE_CONSTRUCTION: |
1701 { | 1728 { |
1702 Node* array_node = Node::make_node(*pexpr); | 1729 Node* array_node = Node::make_node(*pexpr); |
1703 if ((*pexpr)->slice_literal() != NULL) | 1730 if ((*pexpr)->slice_literal() != NULL) |
1735 } | 1762 } |
1736 } | 1763 } |
1737 } | 1764 } |
1738 break; | 1765 break; |
1739 | 1766 |
1767 case Expression::EXPRESSION_SLICE_VALUE: | |
1768 { | |
1769 // Connect the pointer field to the slice value. | |
1770 Node* slice_node = Node::make_node(*pexpr); | |
1771 Node* ptr_node = | |
1772 Node::make_node((*pexpr)->slice_value_expression()->valmem()); | |
1773 this->assign(slice_node, ptr_node); | |
1774 } | |
1775 break; | |
1776 | |
1740 case Expression::EXPRESSION_HEAP: | 1777 case Expression::EXPRESSION_HEAP: |
1741 { | 1778 { |
1742 Node* pointer_node = Node::make_node(*pexpr); | 1779 Node* pointer_node = Node::make_node(*pexpr); |
1743 Node* lit_node = Node::make_node((*pexpr)->heap_expression()->expr()); | 1780 Node* lit_node = Node::make_node((*pexpr)->heap_expression()->expr()); |
1744 this->context_->track(pointer_node); | 1781 this->context_->track(pointer_node); |
1867 Node* addr_node = Node::make_node(addr); | 1904 Node* addr_node = Node::make_node(addr); |
1868 n->set_child(addr_node); | 1905 n->set_child(addr_node); |
1869 this->context_->track(addr_node); | 1906 this->context_->track(addr_node); |
1870 | 1907 |
1871 Node::Escape_state* addr_state = addr_node->state(this->context_, NULL); | 1908 Node::Escape_state* addr_state = addr_node->state(this->context_, NULL); |
1872 addr_state->loop_depth = array_state->loop_depth; | 1909 if (array_state->loop_depth != 0) |
1910 addr_state->loop_depth = array_state->loop_depth; | |
1873 } | 1911 } |
1874 } | 1912 } |
1875 break; | 1913 break; |
1876 | 1914 |
1877 case Expression::EXPRESSION_FIELD_REFERENCE: | 1915 case Expression::EXPRESSION_FIELD_REFERENCE: |
1938 for (std::vector<Node*>::iterator p = arg_nodes.begin(); | 1976 for (std::vector<Node*>::iterator p = arg_nodes.begin(); |
1939 p != arg_nodes.end(); | 1977 p != arg_nodes.end(); |
1940 ++p) | 1978 ++p) |
1941 { | 1979 { |
1942 if (debug_level > 2) | 1980 if (debug_level > 2) |
1943 go_inform(call->location(), | 1981 go_debug(call->location(), |
1944 "esccall:: indirect call <- %s, untracked", | 1982 "esccall:: indirect call <- %s, untracked", |
1945 (*p)->ast_format(gogo).c_str()); | 1983 (*p)->ast_format(gogo).c_str()); |
1946 this->assign(this->context_->sink(), *p); | 1984 this->assign(this->context_->sink(), *p); |
1947 } | 1985 } |
1948 | 1986 |
1949 this->context_->init_retvals(call_node, fntype); | 1987 this->context_->init_retvals(call_node, fntype); |
1950 | 1988 |
1965 if (fn != NULL | 2003 if (fn != NULL |
1966 && fn->named_object()->is_function() | 2004 && fn->named_object()->is_function() |
1967 && !fntype->is_tagged()) | 2005 && !fntype->is_tagged()) |
1968 { | 2006 { |
1969 if (debug_level > 2) | 2007 if (debug_level > 2) |
1970 go_inform(call->location(), "esccall:: %s in recursive group", | 2008 go_debug(call->location(), "esccall:: %s in recursive group", |
1971 call_node->ast_format(gogo).c_str()); | 2009 call_node->ast_format(gogo).c_str()); |
1972 | 2010 |
1973 Function* f = fn->named_object()->func_value(); | 2011 Function* f = fn->named_object()->func_value(); |
1974 const Bindings* callee_bindings = f->block()->bindings(); | 2012 const Bindings* callee_bindings = f->block()->bindings(); |
1975 Function::Results* results = f->result_variables(); | 2013 Function::Results* results = f->result_variables(); |
1976 if (results != NULL) | 2014 if (results != NULL) |
2037 } | 2075 } |
2038 | 2076 |
2039 for (; p != arg_nodes.end(); ++p) | 2077 for (; p != arg_nodes.end(); ++p) |
2040 { | 2078 { |
2041 if (debug_level > 2) | 2079 if (debug_level > 2) |
2042 go_inform(call->location(), "esccall:: ... <- %s, untracked", | 2080 go_debug(call->location(), "esccall:: ... <- %s, untracked", |
2043 (*p)->ast_format(gogo).c_str()); | 2081 (*p)->ast_format(gogo).c_str()); |
2044 this->assign(this->context_->sink(), *p); | 2082 this->assign(this->context_->sink(), *p); |
2045 } | 2083 } |
2046 } | 2084 } |
2047 | 2085 |
2048 return; | 2086 return; |
2049 } | 2087 } |
2050 | 2088 |
2051 if (debug_level > 2) | 2089 if (debug_level > 2) |
2052 go_inform(call->location(), "esccall:: %s not recursive", | 2090 go_debug(call->location(), "esccall:: %s not recursive", |
2053 call_node->ast_format(gogo).c_str()); | 2091 call_node->ast_format(gogo).c_str()); |
2054 | 2092 |
2055 Node::Escape_state* call_state = call_node->state(this->context_, NULL); | 2093 Node::Escape_state* call_state = call_node->state(this->context_, NULL); |
2056 if (!call_state->retvals.empty()) | 2094 if (!call_state->retvals.empty()) |
2057 go_error_at(Linemap::unknown_location(), | 2095 go_error_at(Linemap::unknown_location(), |
2058 "esc already decorated call %s", | 2096 "esc already decorated call %s", |
2124 } | 2162 } |
2125 | 2163 |
2126 for (; p != arg_nodes.end(); ++p) | 2164 for (; p != arg_nodes.end(); ++p) |
2127 { | 2165 { |
2128 if (debug_level > 2) | 2166 if (debug_level > 2) |
2129 go_inform(call->location(), "esccall:: ... <- %s, untracked", | 2167 go_debug(call->location(), "esccall:: ... <- %s, untracked", |
2130 (*p)->ast_format(gogo).c_str()); | 2168 (*p)->ast_format(gogo).c_str()); |
2131 this->assign(this->context_->sink(), *p); | 2169 this->assign(this->context_->sink(), *p); |
2132 } | 2170 } |
2133 } | 2171 } |
2134 } | 2172 } |
2135 | 2173 |
2143 Escape_analysis_assign::assign(Node* dst, Node* src) | 2181 Escape_analysis_assign::assign(Node* dst, Node* src) |
2144 { | 2182 { |
2145 Gogo* gogo = this->context_->gogo(); | 2183 Gogo* gogo = this->context_->gogo(); |
2146 int debug_level = gogo->debug_escape_level(); | 2184 int debug_level = gogo->debug_escape_level(); |
2147 if (debug_level > 1) | 2185 if (debug_level > 1) |
2148 go_inform(dst->location(), "[%d] %s escassign: %s(%s)[%s] = %s(%s)[%s]", | 2186 go_debug(dst->location(), "[%d] %s escassign: %s(%s)[%s] = %s(%s)[%s]", |
2149 this->context_->loop_depth(), | 2187 this->context_->loop_depth(), |
2150 strip_packed_prefix(gogo, this->context_->current_function_name()).c_str(), | 2188 strip_packed_prefix(gogo, this->context_->current_function_name()).c_str(), |
2151 dst->ast_format(gogo).c_str(), dst->details().c_str(), | 2189 dst->ast_format(gogo).c_str(), dst->details().c_str(), |
2152 dst->op_format().c_str(), | 2190 dst->op_format().c_str(), |
2153 src->ast_format(gogo).c_str(), src->details().c_str(), | 2191 src->ast_format(gogo).c_str(), src->details().c_str(), |
2154 src->op_format().c_str()); | 2192 src->op_format().c_str()); |
2155 | 2193 |
2156 if (dst->is_indirect()) | 2194 if (dst->is_indirect()) |
2157 // Lose track of the dereference. | 2195 // Lose track of the dereference. |
2158 dst = this->context_->sink(); | 2196 dst = this->context_->sink(); |
2159 else if (dst->expr() != NULL) | 2197 else if (dst->expr() != NULL) |
2261 // DST = [...]T{...}. | 2299 // DST = [...]T{...}. |
2262 case Expression::EXPRESSION_MAP_CONSTRUCTION: | 2300 case Expression::EXPRESSION_MAP_CONSTRUCTION: |
2263 // DST = map[T]V{...}. | 2301 // DST = map[T]V{...}. |
2264 case Expression::EXPRESSION_STRUCT_CONSTRUCTION: | 2302 case Expression::EXPRESSION_STRUCT_CONSTRUCTION: |
2265 // DST = T{...}. | 2303 // DST = T{...}. |
2304 case Expression::EXPRESSION_SLICE_VALUE: | |
2305 // DST = slice{ptr, len, cap} | |
2266 case Expression::EXPRESSION_ALLOCATION: | 2306 case Expression::EXPRESSION_ALLOCATION: |
2267 // DST = new(T). | 2307 // DST = new(T). |
2268 case Expression::EXPRESSION_BOUND_METHOD: | 2308 case Expression::EXPRESSION_BOUND_METHOD: |
2269 // DST = x.M. | 2309 // DST = x.M. |
2270 case Expression::EXPRESSION_STRING_CONCAT: | 2310 case Expression::EXPRESSION_STRING_CONCAT: |
2393 Type_conversion_expression* tce = e->conversion_expression(); | 2433 Type_conversion_expression* tce = e->conversion_expression(); |
2394 Type* ft = tce->expr()->type(); | 2434 Type* ft = tce->expr()->type(); |
2395 Type* tt = tce->type(); | 2435 Type* tt = tce->type(); |
2396 if ((ft->is_string_type() && tt->is_slice_type()) | 2436 if ((ft->is_string_type() && tt->is_slice_type()) |
2397 || (ft->is_slice_type() && tt->is_string_type()) | 2437 || (ft->is_slice_type() && tt->is_string_type()) |
2398 || (ft->integer_type() != NULL && tt->is_string_type())) | 2438 || (ft->integer_type() != NULL && tt->is_string_type()) |
2439 || tt->interface_type() != NULL) | |
2399 { | 2440 { |
2400 // string([]byte), string([]rune), []byte(string), []rune(string), string(rune) | 2441 // string([]byte), string([]rune), []byte(string), []rune(string), string(rune), |
2442 // interface(T) | |
2401 this->flows(dst, src); | 2443 this->flows(dst, src); |
2402 break; | 2444 break; |
2403 } | 2445 } |
2404 // Conversion preserves input value. | 2446 // Conversion preserves input value. |
2405 Expression* underlying = tce->expr(); | 2447 Expression* underlying = tce->expr(); |
2611 break; | 2653 break; |
2612 } | 2654 } |
2613 } | 2655 } |
2614 | 2656 |
2615 if (this->context_->gogo()->debug_escape_level() > 2) | 2657 if (this->context_->gogo()->debug_escape_level() > 2) |
2616 go_inform(src->location(), "assignfromtag:: src=%s em=%s", | 2658 go_debug(src->location(), "assignfromtag:: src=%s em=%s", |
2617 src->ast_format(context_->gogo()).c_str(), | 2659 src->ast_format(context_->gogo()).c_str(), |
2618 Escape_note::make_tag(enc).c_str()); | 2660 Escape_note::make_tag(enc).c_str()); |
2619 | 2661 |
2620 if (enc == Node::ESCAPE_UNKNOWN) | 2662 if (enc == Node::ESCAPE_UNKNOWN) |
2621 { | 2663 { |
2622 // Lost track of the value. | 2664 // Lost track of the value. |
2623 this->assign(this->context_->sink(), src); | 2665 this->assign(this->context_->sink(), src); |
2681 || dst_state->flows.find(src) != dst_state->flows.end()) | 2723 || dst_state->flows.find(src) != dst_state->flows.end()) |
2682 return; | 2724 return; |
2683 | 2725 |
2684 Gogo* gogo = this->context_->gogo(); | 2726 Gogo* gogo = this->context_->gogo(); |
2685 if (gogo->debug_escape_level() > 2) | 2727 if (gogo->debug_escape_level() > 2) |
2686 go_inform(Linemap::unknown_location(), "flows:: %s <- %s", | 2728 go_debug(Linemap::unknown_location(), "flows:: %s <- %s", |
2687 dst->ast_format(gogo).c_str(), src->ast_format(gogo).c_str()); | 2729 dst->ast_format(gogo).c_str(), src->ast_format(gogo).c_str()); |
2688 | 2730 |
2689 if (dst_state->flows.empty()) | 2731 if (dst_state->flows.empty()) |
2690 this->context_->add_dst(dst); | 2732 this->context_->add_dst(dst); |
2691 | 2733 |
2692 dst_state->flows.insert(src); | 2734 dst_state->flows.insert(src); |
2747 param_state->loop_depth = 1; | 2789 param_state->loop_depth = 1; |
2748 | 2790 |
2749 if (!p->type()->has_pointer()) | 2791 if (!p->type()->has_pointer()) |
2750 continue; | 2792 continue; |
2751 | 2793 |
2752 // External function? Parameters must escape unless //go:noescape is set. | 2794 param_node->set_encoding(Node::ESCAPE_NONE); |
2753 // TODO(cmang): Implement //go:noescape directive. | 2795 context->track(param_node); |
2754 if (fn->package() != NULL) | |
2755 param_node->set_encoding(Node::ESCAPE_HEAP); | |
2756 else | |
2757 { | |
2758 param_node->set_encoding(Node::ESCAPE_NONE); | |
2759 context->track(param_node); | |
2760 } | |
2761 } | 2796 } |
2762 | 2797 |
2763 Escape_analysis_loop el; | 2798 Escape_analysis_loop el; |
2764 fn->func_value()->traverse(&el); | 2799 fn->func_value()->traverse(&el); |
2765 | 2800 |
2845 int mod_loop_depth = std::max(extra_loop_depth, src_state->loop_depth); | 2880 int mod_loop_depth = std::max(extra_loop_depth, src_state->loop_depth); |
2846 | 2881 |
2847 Gogo* gogo = this->context_->gogo(); | 2882 Gogo* gogo = this->context_->gogo(); |
2848 int debug_level = gogo->debug_escape_level(); | 2883 int debug_level = gogo->debug_escape_level(); |
2849 if (debug_level > 1) | 2884 if (debug_level > 1) |
2850 go_inform(Linemap::unknown_location(), | 2885 go_debug(Linemap::unknown_location(), |
2851 "escwalk: level:{%d %d} depth:%d " | 2886 "escwalk: level:{%d %d} depth:%d " |
2852 "op=%s %s(%s) " | 2887 "op=%s %s(%s) " |
2853 "scope:%s[%d] " | 2888 "scope:%s[%d] " |
2854 "extraloopdepth=%d", | 2889 "extraloopdepth=%d", |
2855 level.value(), level.suffix_value(), this->context_->pdepth(), | 2890 level.value(), level.suffix_value(), this->context_->pdepth(), |
2856 src->op_format().c_str(), | 2891 src->op_format().c_str(), |
2857 src->ast_format(gogo).c_str(), | 2892 src->ast_format(gogo).c_str(), |
2858 src->details().c_str(), | 2893 src->details().c_str(), |
2859 debug_function_name(src_state->fn).c_str(), | 2894 debug_function_name(src_state->fn).c_str(), |
2860 src_state->loop_depth, | 2895 src_state->loop_depth, |
2861 extra_loop_depth); | 2896 extra_loop_depth); |
2862 | 2897 |
2863 this->context_->increase_pdepth(); | 2898 this->context_->increase_pdepth(); |
2864 | 2899 |
2865 // Input parameter flowing into output parameter? | 2900 // Input parameter flowing into output parameter? |
2866 Named_object* src_no = NULL; | 2901 Named_object* src_no = NULL; |
2892 // 3. tmp := in; return &tmp | 2927 // 3. tmp := in; return &tmp |
2893 // 4. return *in | 2928 // 4. return *in |
2894 if (debug_level != 0) | 2929 if (debug_level != 0) |
2895 { | 2930 { |
2896 if (debug_level == 1) | 2931 if (debug_level == 1) |
2897 go_inform(src->definition_location(), | 2932 go_debug(src->definition_location(), |
2898 "leaking param: %s to result %s level=%d", | 2933 "leaking param: %s to result %s level=%d", |
2899 src->ast_format(gogo).c_str(), | 2934 src->ast_format(gogo).c_str(), |
2900 dst->ast_format(gogo).c_str(), | 2935 dst->ast_format(gogo).c_str(), |
2901 level.value()); | 2936 level.value()); |
2902 else | 2937 else |
2903 go_inform(src->definition_location(), | 2938 go_debug(src->definition_location(), |
2904 "leaking param: %s to result %s level={%d %d}", | 2939 "leaking param: %s to result %s level={%d %d}", |
2905 src->ast_format(gogo).c_str(), | 2940 src->ast_format(gogo).c_str(), |
2906 dst->ast_format(gogo).c_str(), | 2941 dst->ast_format(gogo).c_str(), |
2907 level.value(), level.suffix_value()); | 2942 level.value(), level.suffix_value()); |
2908 } | 2943 } |
2909 | 2944 |
2910 if ((src->encoding() & ESCAPE_MASK) != Node::ESCAPE_RETURN) | 2945 if ((src->encoding() & ESCAPE_MASK) != Node::ESCAPE_RETURN) |
2911 { | 2946 { |
2912 int enc = | 2947 int enc = |
2940 int enc = | 2975 int enc = |
2941 Node::max_encoding((src->encoding() | ESCAPE_CONTENT_ESCAPES), | 2976 Node::max_encoding((src->encoding() | ESCAPE_CONTENT_ESCAPES), |
2942 Node::ESCAPE_NONE); | 2977 Node::ESCAPE_NONE); |
2943 src->set_encoding(enc); | 2978 src->set_encoding(enc); |
2944 if (debug_level != 0) | 2979 if (debug_level != 0) |
2945 go_inform(src->definition_location(), "mark escaped content: %s", | 2980 go_debug(src->definition_location(), "mark escaped content: %s", |
2946 src->ast_format(gogo).c_str()); | 2981 src->ast_format(gogo).c_str()); |
2947 } | 2982 } |
2948 | 2983 |
2949 // A src object leaks if its value or address is assigned to a dst object | 2984 // A src object leaks if its value or address is assigned to a dst object |
2950 // in a different scope (at a different loop depth). | 2985 // in a different scope (at a different loop depth). |
2951 bool src_leaks = (level.value() <= 0 | 2986 bool src_leaks = (level.value() <= 0 |
2965 int enc = | 3000 int enc = |
2966 Node::max_encoding((src->encoding() | ESCAPE_CONTENT_ESCAPES), | 3001 Node::max_encoding((src->encoding() | ESCAPE_CONTENT_ESCAPES), |
2967 Node::ESCAPE_NONE); | 3002 Node::ESCAPE_NONE); |
2968 src->set_encoding(enc); | 3003 src->set_encoding(enc); |
2969 if (debug_level != 0 && osrcesc != src->encoding()) | 3004 if (debug_level != 0 && osrcesc != src->encoding()) |
2970 go_inform(src->definition_location(), "leaking param content: %s", | 3005 go_debug(src->definition_location(), "leaking param content: %s", |
2971 src->ast_format(gogo).c_str()); | 3006 src->ast_format(gogo).c_str()); |
2972 } | 3007 } |
2973 else | 3008 else |
2974 { | 3009 { |
2975 if (debug_level != 0) | 3010 if (debug_level != 0) |
2976 go_inform(src->definition_location(), "leaking param: %s", | 3011 go_debug(src->definition_location(), "leaking param: %s", |
2977 src->ast_format(gogo).c_str()); | 3012 src->ast_format(gogo).c_str()); |
2978 src->set_encoding(Node::ESCAPE_HEAP); | 3013 src->set_encoding(Node::ESCAPE_HEAP); |
2979 } | 3014 } |
2980 } | 3015 } |
2981 else if (src->expr() != NULL) | 3016 else if (src->expr() != NULL) |
2982 { | 3017 { |
2983 Expression* e = src->expr(); | 3018 Expression* e = src->expr(); |
2984 if (e->enclosed_var_expression() != NULL) | 3019 if (e->enclosed_var_expression() != NULL) |
2985 { | 3020 { |
2986 if (src_leaks && debug_level != 0) | 3021 if (src_leaks && debug_level != 0) |
2987 go_inform(src->location(), "leaking closure reference %s", | 3022 go_debug(src->location(), "leaking closure reference %s", |
2988 src->ast_format(gogo).c_str()); | 3023 src->ast_format(gogo).c_str()); |
2989 | 3024 |
2990 Node* enclosed_node = | 3025 Node* enclosed_node = |
2991 Node::make_node(e->enclosed_var_expression()->variable()); | 3026 Node::make_node(e->enclosed_var_expression()->variable()); |
2992 this->flood(level, dst, enclosed_node, -1); | 3027 this->flood(level, dst, enclosed_node, -1); |
2993 } | 3028 } |
3011 src->set_encoding(Node::ESCAPE_HEAP); | 3046 src->set_encoding(Node::ESCAPE_HEAP); |
3012 if (osrcesc != src->encoding()) | 3047 if (osrcesc != src->encoding()) |
3013 { | 3048 { |
3014 move_to_heap(gogo, underlying); | 3049 move_to_heap(gogo, underlying); |
3015 if (debug_level > 1) | 3050 if (debug_level > 1) |
3016 go_inform(src->location(), | 3051 go_debug(src->location(), |
3017 "%s escapes to heap, level={%d %d}, " | 3052 "%s escapes to heap, level={%d %d}, " |
3018 "dst.eld=%d, src.eld=%d", | 3053 "dst.eld=%d, src.eld=%d", |
3019 src->ast_format(gogo).c_str(), level.value(), | 3054 src->ast_format(gogo).c_str(), level.value(), |
3020 level.suffix_value(), dst_state->loop_depth, | 3055 level.suffix_value(), dst_state->loop_depth, |
3021 mod_loop_depth); | 3056 mod_loop_depth); |
3022 else if (debug_level > 0) | 3057 else if (debug_level > 0) |
3023 go_inform(src->location(), "%s escapes to heap", | 3058 go_debug(src->location(), "%s escapes to heap", |
3024 src->ast_format(gogo).c_str()); | 3059 src->ast_format(gogo).c_str()); |
3025 } | 3060 } |
3026 | 3061 |
3027 this->flood(level.decrease(), dst, | 3062 this->flood(level.decrease(), dst, |
3028 underlying_node, mod_loop_depth); | 3063 underlying_node, mod_loop_depth); |
3029 extra_loop_depth = mod_loop_depth; | 3064 extra_loop_depth = mod_loop_depth; |
3049 } | 3084 } |
3050 if (src_leaks) | 3085 if (src_leaks) |
3051 { | 3086 { |
3052 src->set_encoding(Node::ESCAPE_HEAP); | 3087 src->set_encoding(Node::ESCAPE_HEAP); |
3053 if (debug_level != 0 && osrcesc != src->encoding()) | 3088 if (debug_level != 0 && osrcesc != src->encoding()) |
3054 go_inform(src->location(), "%s escapes to heap", | 3089 go_debug(src->location(), "%s escapes to heap", |
3055 src->ast_format(gogo).c_str()); | 3090 src->ast_format(gogo).c_str()); |
3056 extra_loop_depth = mod_loop_depth; | 3091 extra_loop_depth = mod_loop_depth; |
3057 } | 3092 } |
3058 } | 3093 } |
3059 else if (e->call_expression() != NULL) | 3094 else if (e->call_expression() != NULL) |
3060 { | 3095 { |
3081 case Runtime::MAKESLICE64: | 3116 case Runtime::MAKESLICE64: |
3082 if (src_leaks) | 3117 if (src_leaks) |
3083 { | 3118 { |
3084 src->set_encoding(Node::ESCAPE_HEAP); | 3119 src->set_encoding(Node::ESCAPE_HEAP); |
3085 if (debug_level != 0 && osrcesc != src->encoding()) | 3120 if (debug_level != 0 && osrcesc != src->encoding()) |
3086 go_inform(src->location(), "%s escapes to heap", | 3121 go_debug(src->location(), "%s escapes to heap", |
3087 src->ast_format(gogo).c_str()); | 3122 src->ast_format(gogo).c_str()); |
3088 extra_loop_depth = mod_loop_depth; | 3123 extra_loop_depth = mod_loop_depth; |
3089 } | 3124 } |
3090 break; | 3125 break; |
3091 | 3126 |
3092 default: | 3127 default: |
3100 // themselves link to the inputs with levels adjusted. | 3135 // themselves link to the inputs with levels adjusted. |
3101 // See e.g. #10466. | 3136 // See e.g. #10466. |
3102 // This can only happen with functions returning a single result. | 3137 // This can only happen with functions returning a single result. |
3103 go_assert(src_state->retvals.size() == 1); | 3138 go_assert(src_state->retvals.size() == 1); |
3104 if (debug_level > 2) | 3139 if (debug_level > 2) |
3105 go_inform(src->location(), "[%d] dst %s escwalk replace src: %s with %s", | 3140 go_debug(src->location(), "[%d] dst %s escwalk replace src: %s with %s", |
3106 this->context_->loop_depth(), | 3141 this->context_->loop_depth(), |
3107 dst->ast_format(gogo).c_str(), | 3142 dst->ast_format(gogo).c_str(), |
3108 src->ast_format(gogo).c_str(), | 3143 src->ast_format(gogo).c_str(), |
3109 src_state->retvals[0]->ast_format(gogo).c_str()); | 3144 src_state->retvals[0]->ast_format(gogo).c_str()); |
3110 src = src_state->retvals[0]; | 3145 src = src_state->retvals[0]; |
3111 src_state = src->state(this->context_, NULL); | 3146 src_state = src->state(this->context_, NULL); |
3112 } | 3147 } |
3113 } | 3148 } |
3114 else if (e->allocation_expression() != NULL && src_leaks) | 3149 else if (e->allocation_expression() != NULL && src_leaks) |
3115 { | 3150 { |
3116 // Calls to Runtime::NEW get lowered into an allocation expression. | 3151 // Calls to Runtime::NEW get lowered into an allocation expression. |
3117 src->set_encoding(Node::ESCAPE_HEAP); | 3152 src->set_encoding(Node::ESCAPE_HEAP); |
3118 if (debug_level != 0 && osrcesc != src->encoding()) | 3153 if (debug_level != 0 && osrcesc != src->encoding()) |
3119 go_inform(src->location(), "%s escapes to heap", | 3154 go_debug(src->location(), "%s escapes to heap", |
3120 src->ast_format(gogo).c_str()); | 3155 src->ast_format(gogo).c_str()); |
3121 extra_loop_depth = mod_loop_depth; | 3156 extra_loop_depth = mod_loop_depth; |
3122 } | 3157 } |
3123 else if ((e->map_literal() != NULL | 3158 else if ((e->map_literal() != NULL |
3124 || e->string_concat_expression() != NULL | 3159 || e->string_concat_expression() != NULL |
3125 || (e->func_expression() != NULL && e->func_expression()->closure() != NULL) | 3160 || (e->func_expression() != NULL && e->func_expression()->closure() != NULL) |
3126 || e->bound_method_expression() != NULL) | 3161 || e->bound_method_expression() != NULL) |
3127 && src_leaks) | 3162 && src_leaks) |
3128 { | 3163 { |
3129 src->set_encoding(Node::ESCAPE_HEAP); | 3164 src->set_encoding(Node::ESCAPE_HEAP); |
3130 if (debug_level != 0 && osrcesc != src->encoding()) | 3165 if (debug_level != 0 && osrcesc != src->encoding()) |
3131 go_inform(src->location(), "%s escapes to heap", | 3166 go_debug(src->location(), "%s escapes to heap", |
3132 src->ast_format(gogo).c_str()); | 3167 src->ast_format(gogo).c_str()); |
3133 extra_loop_depth = mod_loop_depth; | 3168 extra_loop_depth = mod_loop_depth; |
3134 } | 3169 } |
3135 else if (e->conversion_expression() != NULL && src_leaks) | 3170 else if (e->conversion_expression() != NULL && src_leaks) |
3136 { | 3171 { |
3137 Type_conversion_expression* tce = e->conversion_expression(); | 3172 Type_conversion_expression* tce = e->conversion_expression(); |
3138 Type* ft = tce->expr()->type(); | 3173 Type* ft = tce->expr()->type(); |
3139 Type* tt = tce->type(); | 3174 Type* tt = tce->type(); |
3140 if ((ft->is_string_type() && tt->is_slice_type()) | 3175 if ((ft->is_string_type() && tt->is_slice_type()) |
3141 || (ft->is_slice_type() && tt->is_string_type()) | 3176 || (ft->is_slice_type() && tt->is_string_type()) |
3142 || (ft->integer_type() != NULL && tt->is_string_type())) | 3177 || (ft->integer_type() != NULL && tt->is_string_type()) |
3178 || tt->interface_type() != NULL) | |
3143 { | 3179 { |
3144 // string([]byte), string([]rune), []byte(string), []rune(string), string(rune) | 3180 // string([]byte), string([]rune), []byte(string), []rune(string), string(rune), |
3181 // interface(T) | |
3145 src->set_encoding(Node::ESCAPE_HEAP); | 3182 src->set_encoding(Node::ESCAPE_HEAP); |
3146 if (debug_level != 0 && osrcesc != src->encoding()) | 3183 if (debug_level != 0 && osrcesc != src->encoding()) |
3147 go_inform(src->location(), "%s escapes to heap", | 3184 go_debug(src->location(), "%s escapes to heap", |
3148 src->ast_format(gogo).c_str()); | 3185 src->ast_format(gogo).c_str()); |
3149 extra_loop_depth = mod_loop_depth; | 3186 extra_loop_depth = mod_loop_depth; |
3187 if (tt->interface_type() != NULL | |
3188 && ft->has_pointer() | |
3189 && !ft->is_direct_iface_type()) | |
3190 // We're converting from a non-direct interface type. | |
3191 // The interface will hold a heap copy of the data | |
3192 // Flow the data to heap. See issue 29353. | |
3193 this->flood(level, this->context_->sink(), | |
3194 Node::make_node(tce->expr()), -1); | |
3150 } | 3195 } |
3151 } | 3196 } |
3152 else if (e->array_index_expression() != NULL | 3197 else if (e->array_index_expression() != NULL |
3153 && !e->array_index_expression()->array()->type()->is_slice_type()) | 3198 && !e->array_index_expression()->array()->type()->is_slice_type()) |
3154 { | 3199 { |
3247 return; | 3292 return; |
3248 | 3293 |
3249 Node::Escape_state* state = dst->state(context, NULL); | 3294 Node::Escape_state* state = dst->state(context, NULL); |
3250 Gogo* gogo = context->gogo(); | 3295 Gogo* gogo = context->gogo(); |
3251 if (gogo->debug_escape_level() > 1) | 3296 if (gogo->debug_escape_level() > 1) |
3252 go_inform(Linemap::unknown_location(), "escflood:%d: dst %s scope:%s[%d]", | 3297 go_debug(Linemap::unknown_location(), "escflood:%d: dst %s scope:%s[%d]", |
3253 context->flood_id(), dst->ast_format(gogo).c_str(), | 3298 context->flood_id(), dst->ast_format(gogo).c_str(), |
3254 debug_function_name(state->fn).c_str(), | 3299 debug_function_name(state->fn).c_str(), |
3255 state->loop_depth); | 3300 state->loop_depth); |
3256 | 3301 |
3257 Escape_analysis_flood eaf(context); | 3302 Escape_analysis_flood eaf(context); |
3258 for (std::set<Node*>::const_iterator p = state->flows.begin(); | 3303 for (std::set<Node*>::const_iterator p = state->flows.begin(); |
3259 p != state->flows.end(); | 3304 p != state->flows.end(); |
3260 ++p) | 3305 ++p) |
3283 void | 3328 void |
3284 Escape_analysis_tag::tag(Named_object* fn) | 3329 Escape_analysis_tag::tag(Named_object* fn) |
3285 { | 3330 { |
3286 // External functions are assumed unsafe | 3331 // External functions are assumed unsafe |
3287 // unless //go:noescape is given before the declaration. | 3332 // unless //go:noescape is given before the declaration. |
3288 if (fn->package() != NULL) | |
3289 return; | |
3290 | |
3291 if (fn->is_function_declaration()) | 3333 if (fn->is_function_declaration()) |
3292 { | 3334 { |
3293 Function_declaration* fdcl = fn->func_declaration_value(); | 3335 Function_declaration* fdcl = fn->func_declaration_value(); |
3294 if ((fdcl->pragmas() & GOPRAGMA_NOESCAPE) != 0) | 3336 if ((fdcl->pragmas() & GOPRAGMA_NOESCAPE) != 0) |
3295 { | 3337 { |
3400 } | 3442 } |
3401 | 3443 |
3402 void | 3444 void |
3403 Node::reclaim_nodes() | 3445 Node::reclaim_nodes() |
3404 { | 3446 { |
3405 for (std::map<Named_object*, Node*>::iterator p = Node::objects.begin(); | 3447 for (Unordered_map(Named_object*, Node*)::iterator p = |
3448 Node::objects.begin(); | |
3406 p != Node::objects.end(); | 3449 p != Node::objects.end(); |
3407 ++p) | 3450 ++p) |
3408 delete p->second; | 3451 delete p->second; |
3409 Node::objects.clear(); | 3452 Node::objects.clear(); |
3410 | 3453 |
3411 for (std::map<Expression*, Node*>::iterator p = Node::expressions.begin(); | 3454 for (Unordered_map(Expression*, Node*)::iterator p = |
3455 Node::expressions.begin(); | |
3412 p != Node::expressions.end(); | 3456 p != Node::expressions.end(); |
3413 ++p) | 3457 ++p) |
3414 delete p->second; | 3458 delete p->second; |
3415 Node::expressions.clear(); | 3459 Node::expressions.clear(); |
3416 | 3460 |
3417 for (std::map<Statement*, Node*>::iterator p = Node::statements.begin(); | 3461 for (Unordered_map(Statement*, Node*)::iterator p = |
3462 Node::statements.begin(); | |
3418 p != Node::statements.end(); | 3463 p != Node::statements.end(); |
3419 ++p) | 3464 ++p) |
3420 delete p->second; | 3465 delete p->second; |
3421 Node::statements.clear(); | 3466 Node::statements.clear(); |
3422 | 3467 |