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
master
travisstaloch 2020-01-09 21:08:24 -08:00 committed by Andrew Kelley
parent ae324985a6
commit 3f98756f85
3 changed files with 90 additions and 3 deletions

View File

@ -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 container_node = try transExpr(rp, scope, base_stmt, .used, .r_value);
const node = try transCreateNodeArrayAccess(rp.c, container_node); 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); 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( fn transCreateNodeAssign(
rp: RestorePoint, rp: RestorePoint,
scope: *Scope, scope: *Scope,

View File

@ -149,4 +149,24 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
\\ return 0; \\ return 0;
\\} \\}
, ""); , "");
cases.add("cast signed array index to unsigned",
\\#include <stdlib.h>
\\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 <stdlib.h>
\\int main(int argc, char **argv) {
\\ long long a[10], i = 0;
\\ a[i] = 0;
\\ if (a[i] != 0) abort();
\\ return 0;
\\}
, "");
} }

View File

@ -1843,12 +1843,51 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub export var array: [100]c_int = .{0} ** 100; \\pub export var array: [100]c_int = .{0} ** 100;
\\pub export fn foo(arg_index: c_int) c_int { \\pub export fn foo(arg_index: c_int) c_int {
\\ var index = arg_index; \\ var index = arg_index;
\\ return array[index]; \\ return array[@intCast(c_uint, index)];
\\} \\}
, ,
\\pub const ACCESS = array[2]; \\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", cases.add("macro call",
\\#define CALL(arg) bar(arg) \\#define CALL(arg) bar(arg)
, &[_][]const u8{ , &[_][]const u8{