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 #4075master
parent
ae324985a6
commit
3f98756f85
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
\\}
|
||||||
|
, "");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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{
|
||||||
|
|
Loading…
Reference in New Issue