authorgravatar for evan@lagerdata.comEvan Haas <evan@lagerdata.com> 2022-07-25 09:53:40-07:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-27 14:03:08+03:00
log7ba1f9bfb52a1f6fa776eeafb45790331be4388f
treee893b174fc9b7e88ea15190f75e05753b315e940
parentc8c798685f3a7d6454bc06d5f47531ad6f615eb5

translate-c: take address of functions before passing them to @ptrToInt

Fixes #12194

7 files changed, 66 insertions(+), 5 deletions(-)

lib/std/zig/c_translation.zig+4
......@@ -36,6 +36,9 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
3636 .Int => {
3737 return castInt(DestType, target);
3838 },
39 .Fn => {
40 return castInt(DestType, @ptrToInt(&target));
41 },
3942 else => {},
4043 }
4144 },
......@@ -45,6 +48,7 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
4548 }
4649 @compileError("cast to union type '" ++ @typeName(DestType) ++ "' from type '" ++ @typeName(SourceType) ++ "' which is not present in union");
4750 },
51 .Bool => return cast(usize, target) != 0,
4852 else => {},
4953 }
5054 return @as(DestType, target);
src/translate_c.zig+14-4
......@@ -1950,7 +1950,10 @@ fn transDeclRefExpr(
19501950 const value_decl = expr.getDecl();
19511951 const name = try c.str(@ptrCast(*const clang.NamedDecl, value_decl).getName_bytes_begin());
19521952 const mangled_name = scope.getAlias(name);
1953 var ref_expr = try Tag.identifier.create(c.arena, mangled_name);
1953 var ref_expr = if (cIsFunctionDeclRef(@ptrCast(*const clang.Expr, expr)))
1954 try Tag.fn_identifier.create(c.arena, mangled_name)
1955 else
1956 try Tag.identifier.create(c.arena, mangled_name);
19541957
19551958 if (@ptrCast(*const clang.Decl, value_decl).getKind() == .Var) {
19561959 const var_decl = @ptrCast(*const clang.VarDecl, value_decl);
......@@ -1999,7 +2002,11 @@ fn transImplicitCastExpr(
19992002 },
20002003 .PointerToBoolean => {
20012004 // @ptrToInt(val) != 0
2002 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, try transExpr(c, scope, sub_expr, .used));
2005 var ptr_node = try transExpr(c, scope, sub_expr, .used);
2006 if (ptr_node.tag() == .fn_identifier) {
2007 ptr_node = try Tag.address_of.create(c.arena, ptr_node);
2008 }
2009 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, ptr_node);
20032010
20042011 const ne = try Tag.not_equal.create(c.arena, .{ .lhs = ptr_to_int, .rhs = Tag.zero_literal.init() });
20052012 return maybeSuppressResult(c, scope, result_used, ne);
......@@ -2042,7 +2049,7 @@ fn isBuiltinDefined(name: []const u8) bool {
20422049
20432050fn transBuiltinFnExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!Node {
20442051 const node = try transExpr(c, scope, expr, used);
2045 if (node.castTag(.identifier)) |ident| {
2052 if (node.castTag(.fn_identifier)) |ident| {
20462053 const name = ident.data;
20472054 if (!isBuiltinDefined(name)) return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO implement function '{s}' in std.zig.c_builtins", .{name});
20482055 }
......@@ -2447,7 +2454,10 @@ fn transCCast(
24472454 }
24482455 if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) {
24492456 // @intCast(dest_type, @ptrToInt(val))
2450 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, expr);
2457 const ptr_to_int = if (expr.tag() == .fn_identifier)
2458 try Tag.ptr_to_int.create(c.arena, try Tag.address_of.create(c.arena, expr))
2459 else
2460 try Tag.ptr_to_int.create(c.arena, expr);
24512461 return Tag.int_cast.create(c.arena, .{ .lhs = dst_node, .rhs = ptr_to_int });
24522462 }
24532463 if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) {
src/translate_c/ast.zig+11
......@@ -36,6 +36,7 @@ pub const Node = extern union {
3636 /// "string"[0..end]
3737 string_slice,
3838 identifier,
39 fn_identifier,
3940 @"if",
4041 /// if (!operand) break;
4142 if_not_break,
......@@ -335,6 +336,7 @@ pub const Node = extern union {
335336 .char_literal,
336337 .enum_literal,
337338 .identifier,
339 .fn_identifier,
338340 .warning,
339341 .type,
340342 .helpers_macro,
......@@ -1058,6 +1060,14 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
10581060 .data = undefined,
10591061 });
10601062 },
1063 .fn_identifier => {
1064 const payload = node.castTag(.fn_identifier).?.data;
1065 return c.addNode(.{
1066 .tag = .identifier,
1067 .main_token = try c.addIdentifier(payload),
1068 .data = undefined,
1069 });
1070 },
10611071 .float_literal => {
10621072 const payload = node.castTag(.float_literal).?.data;
10631073 return c.addNode(.{
......@@ -2234,6 +2244,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
22342244 .char_literal,
22352245 .enum_literal,
22362246 .identifier,
2247 .fn_identifier,
22372248 .field_access,
22382249 .ptr_cast,
22392250 .type,
test/behavior/translate_c_macros.h+8
......@@ -40,3 +40,11 @@ union U {
4040#define CAST_OR_CALL_WITH_PARENS(type_or_fn, val) ((type_or_fn)(val))
4141
4242#define NESTED_COMMA_OPERATOR (1, (2, 3))
43
44#include <stdint.h>
45#if !defined(__UINTPTR_MAX__)
46typedef _Bool uintptr_t;
47#endif
48
49#define CAST_TO_BOOL(X) (_Bool)(X)
50#define CAST_TO_UINTPTR(X) (uintptr_t)(X)
test/behavior/translate_c_macros.zig+14
......@@ -99,3 +99,17 @@ test "nested comma operator" {
9999
100100 try expectEqual(@as(c_int, 3), h.NESTED_COMMA_OPERATOR);
101101}
102
103test "cast functions" {
104 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
105 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
106 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
107 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
108 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
109
110 const S = struct {
111 fn foo() void {}
112 };
113 try expectEqual(true, h.CAST_TO_BOOL(S.foo));
114 try expect(h.CAST_TO_UINTPTR(S.foo) != 0);
115}
test/run_translated_c.zig+14
......@@ -1861,4 +1861,18 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
18611861 \\ return 0;
18621862 \\}
18631863 , "");
1864
1865 // The C standard does not require function pointers to be convertible to any integer type.
1866 // However, POSIX requires that function pointers have the same representation as `void *`
1867 // so that dlsym() can work
1868 cases.add("Function to integral",
1869 \\#include <stdint.h>
1870 \\int main(void) {
1871 \\#if defined(__UINTPTR_MAX__) && __has_include(<unistd.h>)
1872 \\ uintptr_t x = main;
1873 \\ x = (uintptr_t)main;
1874 \\#endif
1875 \\ return 0;
1876 \\}
1877 , "");
18641878}
test/translate_c.zig+1-1
......@@ -3435,7 +3435,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
34353435 \\ var x = arg_x;
34363436 \\ var a: bool = @as(c_int, @boolToInt(x)) != @as(c_int, 1);
34373437 \\ var b: bool = @as(c_int, @boolToInt(a)) != @as(c_int, 0);
3438 \\ var c: bool = @ptrToInt(foo) != 0;
3438 \\ var c: bool = @ptrToInt(&foo) != 0;
34393439 \\ return foo(@as(c_int, @boolToInt(c)) != @as(c_int, @boolToInt(b)));
34403440 \\}
34413441 });