| ... | ... | @@ -1127,6 +1127,44 @@ fn transOffsetOfExpr( |
| 1127 | 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 | 1168 | fn transBinaryOperator( |
| 1131 | 1169 | c: *Context, |
| 1132 | 1170 | scope: *Scope, |
| ... | ... | @@ -1184,6 +1222,12 @@ fn transBinaryOperator( |
| 1184 | 1222 | .LOr => { |
| 1185 | 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 | 1231 | else => {}, |
| 1188 | 1232 | } |
| 1189 | 1233 | var op_id: Tag = undefined; |