Skip to content

Fix translation of signed array indices #4113

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jan 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 32 additions & 4 deletions src-self-hosted/translate_c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ fn prepopulateGlobalNameTable(ast_unit: *ZigClangASTUnit, c: *Context) !void {
}
}

extern fn declVisitorNamesOnlyC(context: ?*c_void, decl: *const ZigClangDecl) bool {
fn declVisitorNamesOnlyC(context: ?*c_void, decl: *const ZigClangDecl) callconv(.C) bool {
const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context));
declVisitorNamesOnly(c, decl) catch |err| {
c.err = err;
Expand All @@ -372,7 +372,7 @@ extern fn declVisitorNamesOnlyC(context: ?*c_void, decl: *const ZigClangDecl) bo
return true;
}

extern fn declVisitorC(context: ?*c_void, decl: *const ZigClangDecl) bool {
fn declVisitorC(context: ?*c_void, decl: *const ZigClangDecl) callconv(.C) bool {
const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context));
declVisitor(c, decl) catch |err| {
c.err = err;
Expand Down Expand Up @@ -2499,8 +2499,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);
}

Expand Down Expand Up @@ -3399,6 +3418,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,
Expand Down
20 changes: 20 additions & 0 deletions test/run_translated_c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,24 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
\\ 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;
\\}
, "");
}
41 changes: 40 additions & 1 deletion test/translate_c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down