| ... | @@ -1127,6 +1127,44 @@ fn transOffsetOfExpr( | ... | @@ -1127,6 +1127,44 @@ fn transOffsetOfExpr( |
| 1127 | return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO: implement complex OffsetOfExpr translation", .{}); | 1127 | return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO: implement complex OffsetOfExpr translation", .{}); |
| 1128 | } | 1128 | } |
| 1129 | | 1129 | |
| | 1130 | /// Translate an arithmetic expression with a pointer operand and a signed-integer operand. |
| | 1131 | /// Zig requires a usize argument for pointer arithmetic, so we intCast to isize and then |
| | 1132 | /// bitcast to usize; pointer wraparound make the math work. |
| | 1133 | /// Zig pointer addition is not commutative (unlike C); the pointer operand needs to be on the left. |
| | 1134 | /// The + operator in C is not a sequence point so it should be safe to switch the order if necessary. |
| | 1135 | fn transCreatePointerArithmeticSignedOp( |
| | 1136 | c: *Context, |
| | 1137 | scope: *Scope, |
| | 1138 | stmt: *const clang.BinaryOperator, |
| | 1139 | result_used: ResultUsed, |
| | 1140 | ) TransError!Node { |
| | 1141 | const is_add = stmt.getOpcode() == .Add; |
| | 1142 | const lhs = stmt.getLHS(); |
| | 1143 | const rhs = stmt.getRHS(); |
| | 1144 | const swap_operands = is_add and cIsSignedInteger(getExprQualType(c, lhs)); |
| | 1145 | |
| | 1146 | const swizzled_lhs = if (swap_operands) rhs else lhs; |
| | 1147 | const swizzled_rhs = if (swap_operands) lhs else rhs; |
| | 1148 | |
| | 1149 | const lhs_node = try transExpr(c, scope, swizzled_lhs, .used); |
| | 1150 | const rhs_node = try transExpr(c, scope, swizzled_rhs, .used); |
| | 1151 | |
| | 1152 | const intcast_node = try Tag.int_cast.create(c.arena, .{ |
| | 1153 | .lhs = try Tag.identifier.create(c.arena, "isize"), |
| | 1154 | .rhs = rhs_node, |
| | 1155 | }); |
| | 1156 | |
| | 1157 | const bitcast_node = try Tag.bit_cast.create(c.arena, .{ |
| | 1158 | .lhs = try Tag.identifier.create(c.arena, "usize"), |
| | 1159 | .rhs = intcast_node, |
| | 1160 | }); |
| | 1161 | |
| | 1162 | const arith_args = .{ .lhs = lhs_node, .rhs = bitcast_node }; |
| | 1163 | const arith_node = try if (is_add) Tag.add.create(c.arena, arith_args) else Tag.sub.create(c.arena, arith_args); |
| | 1164 | |
| | 1165 | return maybeSuppressResult(c, scope, result_used, arith_node); |
| | 1166 | } |
| | 1167 | |
| 1130 | fn transBinaryOperator( | 1168 | fn transBinaryOperator( |
| 1131 | c: *Context, | 1169 | c: *Context, |
| 1132 | scope: *Scope, | 1170 | scope: *Scope, |
| ... | @@ -1184,6 +1222,12 @@ fn transBinaryOperator( | ... | @@ -1184,6 +1222,12 @@ fn transBinaryOperator( |
| 1184 | .LOr => { | 1222 | .LOr => { |
| 1185 | return transCreateNodeBoolInfixOp(c, scope, stmt, .@"or", result_used); | 1223 | return transCreateNodeBoolInfixOp(c, scope, stmt, .@"or", result_used); |
| 1186 | }, | 1224 | }, |
| | 1225 | .Add, .Sub => { |
| | 1226 | // `ptr + idx` and `idx + ptr` -> ptr + @bitCast(usize, @intCast(isize, idx)) |
| | 1227 | // `ptr - idx` -> ptr - @bitCast(usize, @intCast(isize, idx)) |
| | 1228 | if (qualTypeIsPtr(qt) and (cIsSignedInteger(getExprQualType(c, stmt.getLHS())) or |
| | 1229 | cIsSignedInteger(getExprQualType(c, stmt.getRHS())))) return transCreatePointerArithmeticSignedOp(c, scope, stmt, result_used); |
| | 1230 | }, |
| 1187 | else => {}, | 1231 | else => {}, |
| 1188 | } | 1232 | } |
| 1189 | var op_id: Tag = undefined; | 1233 | var op_id: Tag = undefined; |