authorgravatar for twostepted@gmail.comTravis Staloch <twostepted@gmail.com> 2020-01-09 21:08:24-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-01-10 00:08:24-05:00
log3f98756f8542e5ca6b45322f17eb59b74706fb62
tree609251a690623f262f5657b7cd649bd7cccb0e9d
parentae324985a67b1258c226a799f2680906686670f2

Fix translation of signed array indices (#4113)

* cast only if the index is long long or signed * cast long long to usize rather than c_uint closes #4075

3 files changed, 90 insertions(+), 3 deletions(-)

src-self-hosted/translate_c.zig+30-2
...@@ -2577,8 +2577,27 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangArrayS...@@ -2577,8 +2577,27 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangArrayS
25772577
2578 const container_node = try transExpr(rp, scope, base_stmt, .used, .r_value);2578 const container_node = try transExpr(rp, scope, base_stmt, .used, .r_value);
2579 const node = try transCreateNodeArrayAccess(rp.c, container_node);2579 const node = try transCreateNodeArrayAccess(rp.c, container_node);
2580 node.op.ArrayAccess = try transExpr(rp, scope, ZigClangArraySubscriptExpr_getIdx(stmt), .used, .r_value);2580
2581 node.rtoken = try appendToken(rp.c, .RBrace, "]");2581 // cast if the index is long long or signed
2582 const subscr_expr = ZigClangArraySubscriptExpr_getIdx(stmt);
2583 const qt = getExprQualType(rp.c, subscr_expr);
2584 const is_longlong = cIsLongLongInteger(qt);
2585 const is_signed = cIsSignedInteger(qt);
2586
2587 if (is_longlong or is_signed) {
2588 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");
2589 // check if long long first so that signed long long doesn't just become unsigned long long
2590 var typeid_node = if (is_longlong) try transCreateNodeIdentifier(rp.c, "usize") else try transQualTypeIntWidthOf(rp.c, qt, false);
2591 try cast_node.params.push(typeid_node);
2592 _ = try appendToken(rp.c, .Comma, ",");
2593 try cast_node.params.push(try transExpr(rp, scope, subscr_expr, .used, .r_value));
2594 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2595 node.rtoken = try appendToken(rp.c, .RBrace, "]");
2596 node.op.ArrayAccess = &cast_node.base;
2597 } else {
2598 node.op.ArrayAccess = try transExpr(rp, scope, subscr_expr, .used, .r_value);
2599 node.rtoken = try appendToken(rp.c, .RBrace, "]");
2600 }
2582 return maybeSuppressResult(rp, scope, result_used, &node.base);2601 return maybeSuppressResult(rp, scope, result_used, &node.base);
2583}2602}
25842603
...@@ -3528,6 +3547,15 @@ fn cIsFloating(qt: ZigClangQualType) bool {...@@ -3528,6 +3547,15 @@ fn cIsFloating(qt: ZigClangQualType) bool {
3528 };3547 };
3529}3548}
35303549
3550fn cIsLongLongInteger(qt: ZigClangQualType) bool {
3551 const c_type = qualTypeCanon(qt);
3552 if (ZigClangType_getTypeClass(c_type) != .Builtin) return false;
3553 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, c_type);
3554 return switch (ZigClangBuiltinType_getKind(builtin_ty)) {
3555 .LongLong, .ULongLong, .Int128, .UInt128 => true,
3556 else => false,
3557 };
3558}
3531fn transCreateNodeAssign(3559fn transCreateNodeAssign(
3532 rp: RestorePoint,3560 rp: RestorePoint,
3533 scope: *Scope,3561 scope: *Scope,
test/run_translated_c.zig+20
...@@ -149,4 +149,24 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {...@@ -149,4 +149,24 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
149 \\ return 0;149 \\ return 0;
150 \\}150 \\}
151 , "");151 , "");
152
153 cases.add("cast signed array index to unsigned",
154 \\#include <stdlib.h>
155 \\int main(int argc, char **argv) {
156 \\ int a[10], i = 0;
157 \\ a[i] = 0;
158 \\ if (a[i] != 0) abort();
159 \\ return 0;
160 \\}
161 , "");
162
163 cases.add("cast long long array index to unsigned",
164 \\#include <stdlib.h>
165 \\int main(int argc, char **argv) {
166 \\ long long a[10], i = 0;
167 \\ a[i] = 0;
168 \\ if (a[i] != 0) abort();
169 \\ return 0;
170 \\}
171 , "");
152}172}
test/translate_c.zig+40-1
...@@ -1843,12 +1843,51 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1843,12 +1843,51 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1843 \\pub export var array: [100]c_int = .{0} ** 100;1843 \\pub export var array: [100]c_int = .{0} ** 100;
1844 \\pub export fn foo(arg_index: c_int) c_int {1844 \\pub export fn foo(arg_index: c_int) c_int {
1845 \\ var index = arg_index;1845 \\ var index = arg_index;
1846 \\ return array[index];1846 \\ return array[@intCast(c_uint, index)];
1847 \\}1847 \\}
1848 ,1848 ,
1849 \\pub const ACCESS = array[2];1849 \\pub const ACCESS = array[2];
1850 });1850 });
18511851
1852 cases.add("cast signed array index to unsigned",
1853 \\void foo() {
1854 \\ int a[10], i = 0;
1855 \\ a[i] = 0;
1856 \\}
1857 , &[_][]const u8{
1858 \\pub export fn foo() void {
1859 \\ var a: [10]c_int = undefined;
1860 \\ var i: c_int = 0;
1861 \\ a[@intCast(c_uint, i)] = 0;
1862 \\}
1863 });
1864
1865 cases.add("long long array index cast to usize",
1866 \\void foo() {
1867 \\ long long a[10], i = 0;
1868 \\ a[i] = 0;
1869 \\}
1870 , &[_][]const u8{
1871 \\pub export fn foo() void {
1872 \\ var a: [10]c_longlong = undefined;
1873 \\ var i: c_longlong = @bitCast(c_longlong, @as(c_longlong, @as(c_int, 0)));
1874 \\ a[@intCast(usize, i)] = @bitCast(c_longlong, @as(c_longlong, @as(c_int, 0)));
1875 \\}
1876 });
1877
1878 cases.add("unsigned array index skips cast",
1879 \\void foo() {
1880 \\ unsigned int a[10], i = 0;
1881 \\ a[i] = 0;
1882 \\}
1883 , &[_][]const u8{
1884 \\pub export fn foo() void {
1885 \\ var a: [10]c_uint = undefined;
1886 \\ var i: c_uint = @bitCast(c_uint, @as(c_int, 0));
1887 \\ a[i] = @bitCast(c_uint, @as(c_int, 0));
1888 \\}
1889 });
1890
1852 cases.add("macro call",1891 cases.add("macro call",
1853 \\#define CALL(arg) bar(arg)1892 \\#define CALL(arg) bar(arg)
1854 , &[_][]const u8{1893 , &[_][]const u8{