From 3f98756f8542e5ca6b45322f17eb59b74706fb62 Mon Sep 17 00:00:00 2001 From: travisstaloch Date: Thu, 9 Jan 2020 21:08:24 -0800 Subject: [PATCH] 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 --- src-self-hosted/translate_c.zig | 32 +++++++++++++++++++++++-- test/run_translated_c.zig | 20 ++++++++++++++++ test/translate_c.zig | 41 ++++++++++++++++++++++++++++++++- 3 files changed, 90 insertions(+), 3 deletions(-) diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 519cb4f1da..b3064869fc 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -2577,8 +2577,27 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangArrayS const container_node = try transExpr(rp, scope, base_stmt, .used, .r_value); const node = try transCreateNodeArrayAccess(rp.c, container_node); - node.op.ArrayAccess = try transExpr(rp, scope, ZigClangArraySubscriptExpr_getIdx(stmt), .used, .r_value); - node.rtoken = try appendToken(rp.c, .RBrace, "]"); + + // cast if the index is long long or signed + const subscr_expr = ZigClangArraySubscriptExpr_getIdx(stmt); + const qt = getExprQualType(rp.c, subscr_expr); + const is_longlong = cIsLongLongInteger(qt); + const is_signed = cIsSignedInteger(qt); + + if (is_longlong or is_signed) { + const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); + // check if long long first so that signed long long doesn't just become unsigned long long + var typeid_node = if (is_longlong) try transCreateNodeIdentifier(rp.c, "usize") else try transQualTypeIntWidthOf(rp.c, qt, false); + try cast_node.params.push(typeid_node); + _ = try appendToken(rp.c, .Comma, ","); + try cast_node.params.push(try transExpr(rp, scope, subscr_expr, .used, .r_value)); + cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); + node.rtoken = try appendToken(rp.c, .RBrace, "]"); + node.op.ArrayAccess = &cast_node.base; + } else { + node.op.ArrayAccess = try transExpr(rp, scope, subscr_expr, .used, .r_value); + node.rtoken = try appendToken(rp.c, .RBrace, "]"); + } return maybeSuppressResult(rp, scope, result_used, &node.base); } @@ -3528,6 +3547,15 @@ fn cIsFloating(qt: ZigClangQualType) bool { }; } +fn cIsLongLongInteger(qt: ZigClangQualType) bool { + const c_type = qualTypeCanon(qt); + if (ZigClangType_getTypeClass(c_type) != .Builtin) return false; + const builtin_ty = @ptrCast(*const ZigClangBuiltinType, c_type); + return switch (ZigClangBuiltinType_getKind(builtin_ty)) { + .LongLong, .ULongLong, .Int128, .UInt128 => true, + else => false, + }; +} fn transCreateNodeAssign( rp: RestorePoint, scope: *Scope, diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig index 5d8233ec96..dd34713ee3 100644 --- a/test/run_translated_c.zig +++ b/test/run_translated_c.zig @@ -149,4 +149,24 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { \\ return 0; \\} , ""); + + cases.add("cast signed array index to unsigned", + \\#include + \\int main(int argc, char **argv) { + \\ int a[10], i = 0; + \\ a[i] = 0; + \\ if (a[i] != 0) abort(); + \\ return 0; + \\} + , ""); + + cases.add("cast long long array index to unsigned", + \\#include + \\int main(int argc, char **argv) { + \\ long long a[10], i = 0; + \\ a[i] = 0; + \\ if (a[i] != 0) abort(); + \\ return 0; + \\} + , ""); } diff --git a/test/translate_c.zig b/test/translate_c.zig index 2ad4a1564c..f8b6c33dcd 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -1843,12 +1843,51 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub export var array: [100]c_int = .{0} ** 100; \\pub export fn foo(arg_index: c_int) c_int { \\ var index = arg_index; - \\ return array[index]; + \\ return array[@intCast(c_uint, index)]; \\} , \\pub const ACCESS = array[2]; }); + cases.add("cast signed array index to unsigned", + \\void foo() { + \\ int a[10], i = 0; + \\ a[i] = 0; + \\} + , &[_][]const u8{ + \\pub export fn foo() void { + \\ var a: [10]c_int = undefined; + \\ var i: c_int = 0; + \\ a[@intCast(c_uint, i)] = 0; + \\} + }); + + cases.add("long long array index cast to usize", + \\void foo() { + \\ long long a[10], i = 0; + \\ a[i] = 0; + \\} + , &[_][]const u8{ + \\pub export fn foo() void { + \\ var a: [10]c_longlong = undefined; + \\ var i: c_longlong = @bitCast(c_longlong, @as(c_longlong, @as(c_int, 0))); + \\ a[@intCast(usize, i)] = @bitCast(c_longlong, @as(c_longlong, @as(c_int, 0))); + \\} + }); + + cases.add("unsigned array index skips cast", + \\void foo() { + \\ unsigned int a[10], i = 0; + \\ a[i] = 0; + \\} + , &[_][]const u8{ + \\pub export fn foo() void { + \\ var a: [10]c_uint = undefined; + \\ var i: c_uint = @bitCast(c_uint, @as(c_int, 0)); + \\ a[i] = @bitCast(c_uint, @as(c_int, 0)); + \\} + }); + cases.add("macro call", \\#define CALL(arg) bar(arg) , &[_][]const u8{