Commit 012ce1481e
Changed files (2)
src
test
src/parsec.cpp
@@ -1499,38 +1499,72 @@ static AstNode *trans_decl_ref_expr(Context *c, DeclRefExpr *stmt, TransLRValue
return trans_create_node_symbol(c, symbol_name);
}
+static AstNode *trans_create_post_crement(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt, BinOpType assign_op) {
+ Expr *op_expr = stmt->getSubExpr();
+
+ if (!result_used) {
+ // common case
+ // c: expr++
+ // zig: expr += 1
+ return trans_create_node_bin_op(c,
+ trans_expr(c, true, block, op_expr, TransLValue),
+ assign_op,
+ trans_create_node_unsigned(c, 1));
+ } else {
+ // worst case
+ // c: expr++
+ // zig: {
+ // zig: const _ref = &expr;
+ // zig: const _tmp = *_ref;
+ // zig: *_ref += 1;
+ // zig: _tmp
+ // zig: }
+ AstNode *child_block = trans_create_node(c, NodeTypeBlock);
+
+ // const _ref = &expr;
+ AstNode *expr = trans_expr(c, true, child_block, op_expr, TransLValue);
+ if (expr == nullptr) return nullptr;
+ AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr);
+ // TODO: avoid name collisions with generated variable names
+ Buf* ref_var_name = buf_create_from_str("_ref");
+ AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr);
+ child_block->data.block.statements.append(ref_var_decl);
+
+ // const _tmp = *_ref;
+ Buf* tmp_var_name = buf_create_from_str("_tmp");
+ AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr,
+ trans_create_node_prefix_op(c, PrefixOpDereference,
+ trans_create_node_symbol(c, ref_var_name)));
+ child_block->data.block.statements.append(tmp_var_decl);
+
+ // *_ref += 1;
+ AstNode *assign_statement = trans_create_node_bin_op(c,
+ trans_create_node_prefix_op(c, PrefixOpDereference,
+ trans_create_node_symbol(c, ref_var_name)),
+ assign_op,
+ trans_create_node_unsigned(c, 1));
+ child_block->data.block.statements.append(assign_statement);
+
+ // _tmp
+ child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name));
+ child_block->data.block.last_statement_is_result_expression = true;
+
+ return child_block;
+ }
+}
+
static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt) {
switch (stmt->getOpcode()) {
- case UO_PostInc: {
- Expr *op_expr = stmt->getSubExpr();
- BinOpType bin_op = qual_type_has_wrapping_overflow(c, op_expr->getType())
- ? BinOpTypeAssignPlusWrap
- : BinOpTypeAssignPlus;
-
- if (!result_used) {
- // common case
- // c: expr++
- // zig: expr += 1
- return trans_create_node_bin_op(c,
- trans_expr(c, true, block, op_expr, TransLValue),
- bin_op,
- trans_create_node_unsigned(c, 1));
- } else {
- // worst case
- // c: expr++
- // zig: {
- // zig: const _ref = &expr;
- // zig: const _tmp = *_ref;
- // zig: *_ref += 1;
- // zig: _tmp
- // zig: }
- emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PostInc with result_used");
- return nullptr;
- }
- }
+ case UO_PostInc:
+ if (qual_type_has_wrapping_overflow(c, stmt->getType()))
+ return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignPlusWrap);
+ else
+ return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignPlus);
case UO_PostDec:
- emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PostDec");
- return nullptr;
+ if (qual_type_has_wrapping_overflow(c, stmt->getType()))
+ return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinusWrap);
+ else
+ return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinus);
case UO_PreInc:
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreInc");
return nullptr;
test/parsec.zig
@@ -687,6 +687,65 @@ pub fn addCases(cases: &tests.ParseCContext) {
\\ });
\\}
);
+
+ cases.addC("compound assignment operators unsigned",
+ \\void foo(void) {
+ \\ unsigned a = 0;
+ \\ a += (a += 1);
+ \\ a -= (a -= 1);
+ \\ a *= (a *= 1);
+ \\ a &= (a &= 1);
+ \\ a |= (a |= 1);
+ \\ a ^= (a ^= 1);
+ \\ a >>= (a >>= 1);
+ \\ a <<= (a <<= 1);
+ \\}
+ ,
+ \\export fn foo() {
+ \\ var a: c_uint = c_uint(0);
+ \\ a +%= {
+ \\ const _ref = &a;
+ \\ (*_ref) = ((*_ref) +% c_uint(1));
+ \\ *_ref
+ \\ };
+ \\ a -%= {
+ \\ const _ref = &a;
+ \\ (*_ref) = ((*_ref) -% c_uint(1));
+ \\ *_ref
+ \\ };
+ \\ a *%= {
+ \\ const _ref = &a;
+ \\ (*_ref) = ((*_ref) *% c_uint(1));
+ \\ *_ref
+ \\ };
+ \\ a &= {
+ \\ const _ref = &a;
+ \\ (*_ref) = ((*_ref) & c_uint(1));
+ \\ *_ref
+ \\ };
+ \\ a |= {
+ \\ const _ref = &a;
+ \\ (*_ref) = ((*_ref) | c_uint(1));
+ \\ *_ref
+ \\ };
+ \\ a ^= {
+ \\ const _ref = &a;
+ \\ (*_ref) = ((*_ref) ^ c_uint(1));
+ \\ *_ref
+ \\ };
+ \\ a >>= @import("std").math.Log2Int(c_uint)({
+ \\ const _ref = &a;
+ \\ (*_ref) = c_uint(c_uint(*_ref) >> @import("std").math.Log2Int(c_uint)(1));
+ \\ *_ref
+ \\ });
+ \\ a <<= @import("std").math.Log2Int(c_uint)({
+ \\ const _ref = &a;
+ \\ (*_ref) = c_uint(c_uint(*_ref) << @import("std").math.Log2Int(c_uint)(1));
+ \\ *_ref
+ \\ });
+ \\}
+ );
+
cases.addC("duplicate typedef",
\\typedef long foo;
\\typedef int bar;
@@ -697,6 +756,54 @@ pub fn addCases(cases: &tests.ParseCContext) {
\\pub const bar = c_int;
\\pub const baz = c_int;
);
+
+ cases.addC("post increment/decrement",
+ \\void foo(void) {
+ \\ int i = 0;
+ \\ unsigned u = 0;
+ \\ i++;
+ \\ i--;
+ \\ u++;
+ \\ u--;
+ \\ i = i++;
+ \\ i = i--;
+ \\ u = u++;
+ \\ u = u--;
+ \\}
+ ,
+ \\export fn foo() {
+ \\ var i: c_int = 0;
+ \\ var u: c_uint = c_uint(0);
+ \\ i += 1;
+ \\ i -= 1;
+ \\ u +%= 1;
+ \\ u -%= 1;
+ \\ i = {
+ \\ const _ref = &i;
+ \\ const _tmp = *_ref;
+ \\ (*_ref) += 1;
+ \\ _tmp
+ \\ };
+ \\ i = {
+ \\ const _ref = &i;
+ \\ const _tmp = *_ref;
+ \\ (*_ref) -= 1;
+ \\ _tmp
+ \\ };
+ \\ u = {
+ \\ const _ref = &u;
+ \\ const _tmp = *_ref;
+ \\ (*_ref) +%= 1;
+ \\ _tmp
+ \\ };
+ \\ u = {
+ \\ const _ref = &u;
+ \\ const _tmp = *_ref;
+ \\ (*_ref) -%= 1;
+ \\ _tmp
+ \\ };
+ \\}
+ );
}