translate-c: use @intToPtr to cast away qualifiers

This commit is contained in:
Tadeo Kondrak 2020-01-02 19:36:36 -07:00 committed by Andrew Kelley
parent e3a63b4e5a
commit f83b02a581
3 changed files with 86 additions and 26 deletions

View File

@ -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 (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);
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, ",");
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;
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 {
// 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 (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 {

View File

@ -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;
\\}
, "");
}

View File

@ -2452,4 +2452,26 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub export fn c() void {}
\\pub fn foo() callconv(.C) 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)));
\\}
});
}