| ... | @@ -1596,6 +1596,11 @@ fn transBinaryOperator( | ... | @@ -1596,6 +1596,11 @@ fn transBinaryOperator( |
| 1596 | // @divExact(@bitCast(<platform-ptrdiff_t>, @intFromPtr(lhs) -% @intFromPtr(rhs)), @sizeOf(<lhs target type>)) | 1596 | // @divExact(@bitCast(<platform-ptrdiff_t>, @intFromPtr(lhs) -% @intFromPtr(rhs)), @sizeOf(<lhs target type>)) |
| 1597 | const ptrdiff_type = try transQualTypeIntWidthOf(c, qt, true); | 1597 | const ptrdiff_type = try transQualTypeIntWidthOf(c, qt, true); |
| 1598 | | 1598 | |
| | 1599 | const bitcast = try Tag.as.create(c.arena, .{ |
| | 1600 | .lhs = ptrdiff_type, |
| | 1601 | .rhs = try Tag.bit_cast.create(c.arena, infixOpNode), |
| | 1602 | }); |
| | 1603 | |
| 1599 | // C standard requires that pointer subtraction operands are of the same type, | 1604 | // C standard requires that pointer subtraction operands are of the same type, |
| 1600 | // otherwise it is undefined behavior. So we can assume the left and right | 1605 | // otherwise it is undefined behavior. So we can assume the left and right |
| 1601 | // sides are the same QualType and arbitrarily choose left. | 1606 | // sides are the same QualType and arbitrarily choose left. |
| ... | @@ -1603,18 +1608,19 @@ fn transBinaryOperator( | ... | @@ -1603,18 +1608,19 @@ fn transBinaryOperator( |
| 1603 | const lhs_qt = getExprQualType(c, lhs_expr); | 1608 | const lhs_qt = getExprQualType(c, lhs_expr); |
| 1604 | const lhs_qt_translated = try transQualType(c, scope, lhs_qt, lhs_expr.getBeginLoc()); | 1609 | const lhs_qt_translated = try transQualType(c, scope, lhs_qt, lhs_expr.getBeginLoc()); |
| 1605 | const c_pointer = getContainer(c, lhs_qt_translated).?; | 1610 | const c_pointer = getContainer(c, lhs_qt_translated).?; |
| 1606 | const elem_type = c_pointer.castTag(.c_pointer).?.data.elem_type; | | |
| 1607 | const sizeof = try Tag.sizeof.create(c.arena, elem_type); | | |
| 1608 | | | |
| 1609 | const bitcast = try Tag.as.create(c.arena, .{ | | |
| 1610 | .lhs = ptrdiff_type, | | |
| 1611 | .rhs = try Tag.bit_cast.create(c.arena, infixOpNode), | | |
| 1612 | }); | | |
| 1613 | | 1611 | |
| 1614 | return Tag.div_exact.create(c.arena, .{ | 1612 | if (c_pointer.castTag(.c_pointer)) |c_pointer_payload| { |
| 1615 | .lhs = bitcast, | 1613 | const sizeof = try Tag.sizeof.create(c.arena, c_pointer_payload.data.elem_type); |
| 1616 | .rhs = sizeof, | 1614 | return Tag.div_exact.create(c.arena, .{ |
| 1617 | }); | 1615 | .lhs = bitcast, |
| | 1616 | .rhs = sizeof, |
| | 1617 | }); |
| | 1618 | } else { |
| | 1619 | // This is an opaque/incomplete type. This subtraction exhibits Undefined Behavior by the C99 spec. |
| | 1620 | // However, allowing subtraction on `void *` and function pointers is a commonly used extension. |
| | 1621 | // So, just return the value in byte units, mirroring the behavior of this language extension as implemented by GCC and Clang. |
| | 1622 | return bitcast; |
| | 1623 | } |
| 1618 | } | 1624 | } |
| 1619 | return infixOpNode; | 1625 | return infixOpNode; |
| 1620 | } | 1626 | } |