Skip to content

translate-c: use @intToPtr to cast away qualifiers #4052

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 1 commit into from
Jan 7, 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
70 changes: 46 additions & 24 deletions src-self-hosted/translate_c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2880,35 +2880,57 @@ fn transCPtrCast(
) !*ast.Node {
const ty = ZigClangQualType_getTypePtr(dst_type);
const child_type = ZigClangType_getPointeeType(ty);
const src_ty = ZigClangQualType_getTypePtr(src_type);
const src_child_type = ZigClangType_getPointeeType(src_ty);

// Implicit downcasting from higher to lower alignment values is forbidden,
// use @alignCast to side-step this problem
const ptrcast_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrCast");
const dst_type_node = try transType(rp, ty, loc);
try ptrcast_node.params.push(dst_type_node);
_ = try appendToken(rp.c, .Comma, ",");
if ((ZigClangQualType_isConstQualified(src_child_type) and
!ZigClangQualType_isConstQualified(child_type)) or
(ZigClangQualType_isVolatileQualified(src_child_type) and
!ZigClangQualType_isVolatileQualified(child_type)))
{
// Casting away const or volatile requires us to use @intToPtr
const inttoptr_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToPtr");
const dst_type_node = try transType(rp, ty, loc);
try inttoptr_node.params.push(dst_type_node);
_ = try appendToken(rp.c, .Comma, ",");

if (ZigClangType_isVoidType(qualTypeCanon(child_type))) {
// void has 1-byte alignment, so @alignCast is not needed
try ptrcast_node.params.push(expr);
} else if (typeIsOpaque(rp.c, qualTypeCanon(child_type), loc)) {
// For opaque types a ptrCast is enough
try ptrcast_node.params.push(expr);
const ptrtoint_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt");
try ptrtoint_node.params.push(expr);
ptrtoint_node.rparen_token = try appendToken(rp.c, .RParen, ")");

try inttoptr_node.params.push(&ptrtoint_node.base);
inttoptr_node.rparen_token = try appendToken(rp.c, .RParen, ")");
return &inttoptr_node.base;
} else {
const aligncast_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignCast");
const alignof_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignOf");
const child_type_node = try transQualType(rp, child_type, loc);
try alignof_node.params.push(child_type_node);
alignof_node.rparen_token = try appendToken(rp.c, .RParen, ")");
try aligncast_node.params.push(&alignof_node.base);
// Implicit downcasting from higher to lower alignment values is forbidden,
// use @alignCast to side-step this problem
const ptrcast_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrCast");
const dst_type_node = try transType(rp, ty, loc);
try ptrcast_node.params.push(dst_type_node);
_ = try appendToken(rp.c, .Comma, ",");
try aligncast_node.params.push(expr);
aligncast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
try ptrcast_node.params.push(&aligncast_node.base);
}
ptrcast_node.rparen_token = try appendToken(rp.c, .RParen, ")");

return &ptrcast_node.base;
if (ZigClangType_isVoidType(qualTypeCanon(child_type))) {
// void has 1-byte alignment, so @alignCast is not needed
try ptrcast_node.params.push(expr);
} else if (typeIsOpaque(rp.c, qualTypeCanon(child_type), loc)) {
// For opaque types a ptrCast is enough
try ptrcast_node.params.push(expr);
} else {
const aligncast_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignCast");
const alignof_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignOf");
const child_type_node = try transQualType(rp, child_type, loc);
try alignof_node.params.push(child_type_node);
alignof_node.rparen_token = try appendToken(rp.c, .RParen, ")");
try aligncast_node.params.push(&alignof_node.base);
_ = try appendToken(rp.c, .Comma, ",");
try aligncast_node.params.push(expr);
aligncast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
try ptrcast_node.params.push(&aligncast_node.base);
}
ptrcast_node.rparen_token = try appendToken(rp.c, .RParen, ")");

return &ptrcast_node.base;
}
}

fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node {
Expand Down
16 changes: 16 additions & 0 deletions test/run_translated_c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,20 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
\\ return 0;
\\}
, "");

cases.add("casting away const and volatile",
\\void foo(int *a) {}
\\void bar(const int *a) {
\\ foo((int *)a);
\\}
\\void baz(volatile int *a) {
\\ foo((int *)a);
\\}
\\int main(int argc, char **argv) {
\\ int a = 0;
\\ bar((const int *)&a);
\\ baz((volatile int *)&a);
\\ return 0;
\\}
, "");
}
22 changes: 22 additions & 0 deletions test/translate_c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2418,4 +2418,26 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub export fn c() void {}
\\pub fn foo() void {}
});

cases.add("casting away const and volatile",
\\void foo(int *a) {}
\\void bar(const int *a) {
\\ foo((int *)a);
\\}
\\void baz(volatile int *a) {
\\ foo((int *)a);
\\}
, &[_][]const u8{
\\pub export fn foo(arg_a: [*c]c_int) void {
\\ var a = arg_a;
\\}
\\pub export fn bar(arg_a: [*c]const c_int) void {
\\ var a = arg_a;
\\ foo(@intToPtr([*c]c_int, @ptrToInt(a)));
\\}
\\pub export fn baz(arg_a: [*c]volatile c_int) void {
\\ var a = arg_a;
\\ foo(@intToPtr([*c]c_int, @ptrToInt(a)));
\\}
});
}