| ... | @@ -1524,47 +1524,93 @@ static AstNode *trans_create_post_crement(Context *c, bool result_used, AstNode | ... | @@ -1524,47 +1524,93 @@ static AstNode *trans_create_post_crement(Context *c, bool result_used, AstNode |
| 1524 | trans_expr(c, true, block, op_expr, TransLValue), | 1524 | trans_expr(c, true, block, op_expr, TransLValue), |
| 1525 | assign_op, | 1525 | assign_op, |
| 1526 | trans_create_node_unsigned(c, 1)); | 1526 | trans_create_node_unsigned(c, 1)); |
| 1527 | } else { | 1527 | } |
| 1528 | // worst case | 1528 | // worst case |
| 1529 | // c: expr++ | 1529 | // c: expr++ |
| 1530 | // zig: { | 1530 | // zig: { |
| 1531 | // zig: const _ref = &expr; | 1531 | // zig: const _ref = &expr; |
| 1532 | // zig: const _tmp = *_ref; | 1532 | // zig: const _tmp = *_ref; |
| 1533 | // zig: *_ref += 1; | 1533 | // zig: *_ref += 1; |
| 1534 | // zig: _tmp | 1534 | // zig: _tmp |
| 1535 | // zig: } | 1535 | // zig: } |
| 1536 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); | 1536 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); |
| 1537 | | 1537 | |
| 1538 | // const _ref = &expr; | 1538 | // const _ref = &expr; |
| 1539 | AstNode *expr = trans_expr(c, true, child_block, op_expr, TransLValue); | 1539 | AstNode *expr = trans_expr(c, true, child_block, op_expr, TransLValue); |
| 1540 | if (expr == nullptr) return nullptr; | 1540 | if (expr == nullptr) return nullptr; |
| 1541 | AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr); | 1541 | AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr); |
| 1542 | // TODO: avoid name collisions with generated variable names | 1542 | // TODO: avoid name collisions with generated variable names |
| 1543 | Buf* ref_var_name = buf_create_from_str("_ref"); | 1543 | Buf* ref_var_name = buf_create_from_str("_ref"); |
| 1544 | AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr); | 1544 | AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr); |
| 1545 | child_block->data.block.statements.append(ref_var_decl); | 1545 | child_block->data.block.statements.append(ref_var_decl); |
| | 1546 | |
| | 1547 | // const _tmp = *_ref; |
| | 1548 | Buf* tmp_var_name = buf_create_from_str("_tmp"); |
| | 1549 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, |
| | 1550 | trans_create_node_prefix_op(c, PrefixOpDereference, |
| | 1551 | trans_create_node_symbol(c, ref_var_name))); |
| | 1552 | child_block->data.block.statements.append(tmp_var_decl); |
| | 1553 | |
| | 1554 | // *_ref += 1; |
| | 1555 | AstNode *assign_statement = trans_create_node_bin_op(c, |
| | 1556 | trans_create_node_prefix_op(c, PrefixOpDereference, |
| | 1557 | trans_create_node_symbol(c, ref_var_name)), |
| | 1558 | assign_op, |
| | 1559 | trans_create_node_unsigned(c, 1)); |
| | 1560 | child_block->data.block.statements.append(assign_statement); |
| | 1561 | |
| | 1562 | // _tmp |
| | 1563 | child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name)); |
| | 1564 | child_block->data.block.last_statement_is_result_expression = true; |
| 1546 | | 1565 | |
| 1547 | // const _tmp = *_ref; | 1566 | return child_block; |
| 1548 | Buf* tmp_var_name = buf_create_from_str("_tmp"); | 1567 | } |
| 1549 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, | | |
| 1550 | trans_create_node_prefix_op(c, PrefixOpDereference, | | |
| 1551 | trans_create_node_symbol(c, ref_var_name))); | | |
| 1552 | child_block->data.block.statements.append(tmp_var_decl); | | |
| 1553 | | 1568 | |
| 1554 | // *_ref += 1; | 1569 | static AstNode *trans_create_pre_crement(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt, BinOpType assign_op) { |
| 1555 | AstNode *assign_statement = trans_create_node_bin_op(c, | 1570 | Expr *op_expr = stmt->getSubExpr(); |
| 1556 | trans_create_node_prefix_op(c, PrefixOpDereference, | 1571 | |
| 1557 | trans_create_node_symbol(c, ref_var_name)), | 1572 | if (!result_used) { |
| | 1573 | // common case |
| | 1574 | // c: ++expr |
| | 1575 | // zig: expr += 1 |
| | 1576 | return trans_create_node_bin_op(c, |
| | 1577 | trans_expr(c, true, block, op_expr, TransLValue), |
| 1558 | assign_op, | 1578 | assign_op, |
| 1559 | trans_create_node_unsigned(c, 1)); | 1579 | trans_create_node_unsigned(c, 1)); |
| 1560 | child_block->data.block.statements.append(assign_statement); | 1580 | } |
| | 1581 | // worst case |
| | 1582 | // c: ++expr |
| | 1583 | // zig: { |
| | 1584 | // zig: const _ref = &expr; |
| | 1585 | // zig: *_ref += 1; |
| | 1586 | // zig: *_ref |
| | 1587 | // zig: } |
| | 1588 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); |
| 1561 | | 1589 | |
| 1562 | // _tmp | 1590 | // const _ref = &expr; |
| 1563 | child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name)); | 1591 | AstNode *expr = trans_expr(c, true, child_block, op_expr, TransLValue); |
| 1564 | child_block->data.block.last_statement_is_result_expression = true; | 1592 | if (expr == nullptr) return nullptr; |
| | 1593 | AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr); |
| | 1594 | // TODO: avoid name collisions with generated variable names |
| | 1595 | Buf* ref_var_name = buf_create_from_str("_ref"); |
| | 1596 | AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr); |
| | 1597 | child_block->data.block.statements.append(ref_var_decl); |
| | 1598 | |
| | 1599 | // *_ref += 1; |
| | 1600 | AstNode *assign_statement = trans_create_node_bin_op(c, |
| | 1601 | trans_create_node_prefix_op(c, PrefixOpDereference, |
| | 1602 | trans_create_node_symbol(c, ref_var_name)), |
| | 1603 | assign_op, |
| | 1604 | trans_create_node_unsigned(c, 1)); |
| | 1605 | child_block->data.block.statements.append(assign_statement); |
| | 1606 | |
| | 1607 | // *_ref |
| | 1608 | AstNode *deref_expr = trans_create_node_prefix_op(c, PrefixOpDereference, |
| | 1609 | trans_create_node_symbol(c, ref_var_name)); |
| | 1610 | child_block->data.block.statements.append(deref_expr); |
| | 1611 | child_block->data.block.last_statement_is_result_expression = true; |
| 1565 | | 1612 | |
| 1566 | return child_block; | 1613 | return child_block; |
| 1567 | } | | |
| 1568 | } | 1614 | } |
| 1569 | | 1615 | |
| 1570 | static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt) { | 1616 | static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt) { |
| ... | @@ -1580,11 +1626,15 @@ static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *bloc | ... | @@ -1580,11 +1626,15 @@ static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *bloc |
| 1580 | else | 1626 | else |
| 1581 | return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinus); | 1627 | return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinus); |
| 1582 | case UO_PreInc: | 1628 | case UO_PreInc: |
| 1583 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreInc"); | 1629 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) |
| 1584 | return nullptr; | 1630 | return trans_create_pre_crement(c, result_used, block, stmt, BinOpTypeAssignPlusWrap); |
| | 1631 | else |
| | 1632 | return trans_create_pre_crement(c, result_used, block, stmt, BinOpTypeAssignPlus); |
| 1585 | case UO_PreDec: | 1633 | case UO_PreDec: |
| 1586 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreDec"); | 1634 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) |
| 1587 | return nullptr; | 1635 | return trans_create_pre_crement(c, result_used, block, stmt, BinOpTypeAssignMinusWrap); |
| | 1636 | else |
| | 1637 | return trans_create_pre_crement(c, result_used, block, stmt, BinOpTypeAssignMinus); |
| 1588 | case UO_AddrOf: | 1638 | case UO_AddrOf: |
| 1589 | { | 1639 | { |
| 1590 | AstNode *value_node = trans_expr(c, result_used, block, stmt->getSubExpr(), TransLValue); | 1640 | AstNode *value_node = trans_expr(c, result_used, block, stmt->getSubExpr(), TransLValue); |