diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 730c93e037e1..a48aceae0e5c 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -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 { diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig index 42dd97873c05..b7cc0cb7dcbd 100644 --- a/test/run_translated_c.zig +++ b/test/run_translated_c.zig @@ -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; + \\} + , ""); } diff --git a/test/translate_c.zig b/test/translate_c.zig index 7049173d80c6..3b8396163b7c 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -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))); + \\} + }); }