Commit 4c2cdf6f4d
Changed files (2)
src
test
src/parsec.cpp
@@ -1034,7 +1034,7 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo
// unsigned/float division uses the operator
return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeMod, stmt->getRHS());
} else {
- // signed integer division uses @divTrunc
+ // signed integer division uses @rem
AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "rem");
AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);
if (lhs == nullptr) return nullptr;
@@ -1081,36 +1081,6 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo
return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS());
case BO_Assign:
return trans_create_assign(c, result_used, block, stmt->getLHS(), stmt->getRHS());
- case BO_MulAssign:
- emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_MulAssign");
- return nullptr;
- case BO_DivAssign:
- emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_DivAssign");
- return nullptr;
- case BO_RemAssign:
- emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_RemAssign");
- return nullptr;
- case BO_AddAssign:
- emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_AddAssign");
- return nullptr;
- case BO_SubAssign:
- emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_SubAssign");
- return nullptr;
- case BO_ShlAssign:
- emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_ShlAssign");
- return nullptr;
- case BO_ShrAssign:
- emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_ShrAssign");
- return nullptr;
- case BO_AndAssign:
- emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_AndAssign");
- return nullptr;
- case BO_XorAssign:
- emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_XorAssign");
- return nullptr;
- case BO_OrAssign:
- emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_OrAssign");
- return nullptr;
case BO_Comma:
{
block = trans_create_node(c, NodeTypeBlock);
@@ -1123,112 +1093,181 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo
block->data.block.last_statement_is_result_expression = true;
return block;
}
- }
-
- zig_unreachable();
-}
-
-static AstNode *trans_compound_assign_operator(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt) {
- switch (stmt->getOpcode()) {
case BO_MulAssign:
- emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_MulAssign");
- return nullptr;
case BO_DivAssign:
- emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_DivAssign");
- return nullptr;
case BO_RemAssign:
- emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_RemAssign");
- return nullptr;
case BO_AddAssign:
- emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_AddAssign");
- return nullptr;
case BO_SubAssign:
- emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_SubAssign");
- return nullptr;
case BO_ShlAssign:
- emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_ShlAssign");
- return nullptr;
- case BO_ShrAssign: {
- BinOpType bin_op = BinOpTypeBitShiftRight;
+ case BO_ShrAssign:
+ case BO_AndAssign:
+ case BO_XorAssign:
+ case BO_OrAssign:
+ zig_unreachable();
+ }
- const SourceLocation &rhs_location = stmt->getRHS()->getLocStart();
- AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location);
+ zig_unreachable();
+}
- bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr();
- if (!use_intermediate_casts && !result_used) {
- // simple common case, where the C and Zig are identical:
- // lhs >>= rh* s
- AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);
- if (lhs == nullptr) return nullptr;
+static AstNode *trans_create_compound_assign_shift(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) {
+ const SourceLocation &rhs_location = stmt->getRHS()->getLocStart();
+ AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location);
- AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue);
- if (rhs == nullptr) return nullptr;
- AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
+ bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr();
+ if (!use_intermediate_casts && !result_used) {
+ // simple common case, where the C and Zig are identical:
+ // lhs >>= rhs
+ AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);
+ if (lhs == nullptr) return nullptr;
- return trans_create_node_bin_op(c, lhs, BinOpTypeAssignBitShiftRight, coerced_rhs);
- } else {
- // need more complexity. worst case, this looks like this:
- // c: lhs >>= rhs
- // zig: {
- // zig: const _ref = &lhs;
- // zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs));
- // zig: *_ref
- // zig: }
- // where u5 is the appropriate type
+ AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue);
+ if (rhs == nullptr) return nullptr;
+ AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
- // TODO: avoid mess when we don't need the assignment value for chained assignments or anything.
- AstNode *child_block = trans_create_node(c, NodeTypeBlock);
+ return trans_create_node_bin_op(c, lhs, assign_op, coerced_rhs);
+ } else {
+ // need more complexity. worst case, this looks like this:
+ // c: lhs >>= rhs
+ // zig: {
+ // zig: const _ref = &lhs;
+ // zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs));
+ // zig: *_ref
+ // zig: }
+ // where u5 is the appropriate type
- // const _ref = &lhs;
- AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue);
- if (lhs == nullptr) return nullptr;
- AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs);
- // TODO: avoid name collisions with generated variable names
- Buf* tmp_var_name = buf_create_from_str("_ref");
- AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs);
- child_block->data.block.statements.append(tmp_var_decl);
+ AstNode *child_block = trans_create_node(c, NodeTypeBlock);
- // *_ref = result_type(operation_type(*_ref) >> u5(rhs));
+ // const _ref = &lhs;
+ AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue);
+ if (lhs == nullptr) return nullptr;
+ AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs);
+ // TODO: avoid name collisions with generated variable names
+ Buf* tmp_var_name = buf_create_from_str("_ref");
+ AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs);
+ child_block->data.block.statements.append(tmp_var_decl);
- AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue);
- if (rhs == nullptr) return nullptr;
- AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
+ // *_ref = result_type(operation_type(*_ref) >> u5(rhs));
- AstNode *assign_statement = trans_create_node_bin_op(c,
- trans_create_node_prefix_op(c, PrefixOpDereference,
- trans_create_node_symbol(c, tmp_var_name)),
- BinOpTypeAssign,
+ AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue);
+ if (rhs == nullptr) return nullptr;
+ AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
+
+ AstNode *assign_statement = trans_create_node_bin_op(c,
+ trans_create_node_prefix_op(c, PrefixOpDereference,
+ trans_create_node_symbol(c, tmp_var_name)),
+ BinOpTypeAssign,
+ trans_c_cast(c, rhs_location,
+ stmt->getComputationResultType(),
+ trans_create_node_bin_op(c,
trans_c_cast(c, rhs_location,
- stmt->getComputationResultType(),
- trans_create_node_bin_op(c,
- trans_c_cast(c, rhs_location,
- stmt->getComputationLHSType(),
- trans_create_node_prefix_op(c, PrefixOpDereference,
- trans_create_node_symbol(c, tmp_var_name))),
- bin_op,
- coerced_rhs)));
- child_block->data.block.statements.append(assign_statement);
-
- if (result_used) {
- // *_ref
- child_block->data.block.statements.append(
+ stmt->getComputationLHSType(),
trans_create_node_prefix_op(c, PrefixOpDereference,
- trans_create_node_symbol(c, tmp_var_name)));
- child_block->data.block.last_statement_is_result_expression = true;
- }
-
- return child_block;
- }
+ trans_create_node_symbol(c, tmp_var_name))),
+ bin_op,
+ coerced_rhs)));
+ child_block->data.block.statements.append(assign_statement);
+
+ if (result_used) {
+ // *_ref
+ child_block->data.block.statements.append(
+ trans_create_node_prefix_op(c, PrefixOpDereference,
+ trans_create_node_symbol(c, tmp_var_name)));
+ child_block->data.block.last_statement_is_result_expression = true;
}
- case BO_AndAssign:
- emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_AndAssign");
+
+ return child_block;
+ }
+}
+
+static AstNode *trans_create_compound_assign(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) {
+ if (!result_used) {
+ // simple common case, where the C and Zig are identical:
+ // lhs += rhs
+ AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);
+ if (lhs == nullptr) return nullptr;
+ AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue);
+ if (rhs == nullptr) return nullptr;
+ return trans_create_node_bin_op(c, lhs, assign_op, rhs);
+ } else {
+ // need more complexity. worst case, this looks like this:
+ // c: lhs += rhs
+ // zig: {
+ // zig: const _ref = &lhs;
+ // zig: *_ref = *_ref + rhs;
+ // zig: *_ref
+ // zig: }
+
+ AstNode *child_block = trans_create_node(c, NodeTypeBlock);
+
+ // const _ref = &lhs;
+ AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue);
+ if (lhs == nullptr) return nullptr;
+ AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs);
+ // TODO: avoid name collisions with generated variable names
+ Buf* tmp_var_name = buf_create_from_str("_ref");
+ AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs);
+ child_block->data.block.statements.append(tmp_var_decl);
+
+ // *_ref = *_ref + rhs;
+
+ AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue);
+ if (rhs == nullptr) return nullptr;
+
+ AstNode *assign_statement = trans_create_node_bin_op(c,
+ trans_create_node_prefix_op(c, PrefixOpDereference,
+ trans_create_node_symbol(c, tmp_var_name)),
+ BinOpTypeAssign,
+ trans_create_node_bin_op(c,
+ trans_create_node_prefix_op(c, PrefixOpDereference,
+ trans_create_node_symbol(c, tmp_var_name)),
+ bin_op,
+ rhs));
+ child_block->data.block.statements.append(assign_statement);
+
+ // *_ref
+ child_block->data.block.statements.append(
+ trans_create_node_prefix_op(c, PrefixOpDereference,
+ trans_create_node_symbol(c, tmp_var_name)));
+ child_block->data.block.last_statement_is_result_expression = true;
+
+ return child_block;
+ }
+}
+
+
+static AstNode *trans_compound_assign_operator(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt) {
+ switch (stmt->getOpcode()) {
+ case BO_MulAssign:
+ if (qual_type_has_wrapping_overflow(c, stmt->getType()))
+ return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignTimesWrap, BinOpTypeMultWrap);
+ else
+ return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignTimes, BinOpTypeMult);
+ case BO_DivAssign:
+ emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_DivAssign");
return nullptr;
- case BO_XorAssign:
- emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_XorAssign");
+ case BO_RemAssign:
+ emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_RemAssign");
return nullptr;
+ case BO_AddAssign:
+ if (qual_type_has_wrapping_overflow(c, stmt->getType()))
+ return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignPlusWrap, BinOpTypeAddWrap);
+ else
+ return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignPlus, BinOpTypeAdd);
+ case BO_SubAssign:
+ if (qual_type_has_wrapping_overflow(c, stmt->getType()))
+ return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignMinusWrap, BinOpTypeSubWrap);
+ else
+ return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignMinus, BinOpTypeSub);
+ case BO_ShlAssign:
+ return trans_create_compound_assign_shift(c, result_used, block, stmt, BinOpTypeAssignBitShiftLeft, BinOpTypeBitShiftLeft);
+ case BO_ShrAssign:
+ return trans_create_compound_assign_shift(c, result_used, block, stmt, BinOpTypeAssignBitShiftRight, BinOpTypeBitShiftRight);
+ case BO_AndAssign:
+ return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitAnd, BinOpTypeBinAnd);
+ case BO_XorAssign:
+ return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitXor, BinOpTypeBinXor);
case BO_OrAssign:
- emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_OrAssign");
- return nullptr;
+ return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitOr, BinOpTypeBinOr);
case BO_PtrMemD:
case BO_PtrMemI:
case BO_Assign:
@@ -1251,7 +1290,7 @@ static AstNode *trans_compound_assign_operator(Context *c, bool result_used, Ast
case BO_LAnd:
case BO_LOr:
case BO_Comma:
- zig_panic("compound assign expected to be handled by binary operator");
+ zig_unreachable();
}
zig_unreachable();
test/parsec.zig
@@ -630,6 +630,63 @@ pub fn addCases(cases: &tests.ParseCContext) {
\\}
);
+ cases.addC("compound assignment operators",
+ \\void foo(void) {
+ \\ int 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_int = 0;
+ \\ a += {
+ \\ const _ref = &a;
+ \\ (*_ref) = ((*_ref) + 1);
+ \\ *_ref
+ \\ };
+ \\ a -= {
+ \\ const _ref = &a;
+ \\ (*_ref) = ((*_ref) - 1);
+ \\ *_ref
+ \\ };
+ \\ a *= {
+ \\ const _ref = &a;
+ \\ (*_ref) = ((*_ref) * 1);
+ \\ *_ref
+ \\ };
+ \\ a &= {
+ \\ const _ref = &a;
+ \\ (*_ref) = ((*_ref) & 1);
+ \\ *_ref
+ \\ };
+ \\ a |= {
+ \\ const _ref = &a;
+ \\ (*_ref) = ((*_ref) | 1);
+ \\ *_ref
+ \\ };
+ \\ a ^= {
+ \\ const _ref = &a;
+ \\ (*_ref) = ((*_ref) ^ 1);
+ \\ *_ref
+ \\ };
+ \\ a >>= @import("std").math.Log2Int(c_int)({
+ \\ const _ref = &a;
+ \\ (*_ref) = c_int(c_int(*_ref) >> @import("std").math.Log2Int(c_int)(1));
+ \\ *_ref
+ \\ });
+ \\ a <<= @import("std").math.Log2Int(c_int)({
+ \\ const _ref = &a;
+ \\ (*_ref) = c_int(c_int(*_ref) << @import("std").math.Log2Int(c_int)(1));
+ \\ *_ref
+ \\ });
+ \\}
+ );
cases.addC("duplicate typedef",
\\typedef long foo;
\\typedef int bar;