| author | |
| committer | |
| log | 7ba1f9bfb52a1f6fa776eeafb45790331be4388f |
| tree | e893b174fc9b7e88ea15190f75e05753b315e940 |
| parent | c8c798685f3a7d6454bc06d5f47531ad6f615eb5 |
Fixes #121947 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 { | ... | @@ -36,6 +36,9 @@ pub fn cast(comptime DestType: type, target: anytype) DestType { |
| 36 | .Int => { | 36 | .Int => { |
| 37 | return castInt(DestType, target); | 37 | return castInt(DestType, target); |
| 38 | }, | 38 | }, |
| 39 | .Fn => { | ||
| 40 | return castInt(DestType, @ptrToInt(&target)); | ||
| 41 | }, | ||
| 39 | else => {}, | 42 | else => {}, |
| 40 | } | 43 | } |
| 41 | }, | 44 | }, |
| ... | @@ -45,6 +48,7 @@ pub fn cast(comptime DestType: type, target: anytype) DestType { | ... | @@ -45,6 +48,7 @@ pub fn cast(comptime DestType: type, target: anytype) DestType { |
| 45 | } | 48 | } |
| 46 | @compileError("cast to union type '" ++ @typeName(DestType) ++ "' from type '" ++ @typeName(SourceType) ++ "' which is not present in union"); | 49 | @compileError("cast to union type '" ++ @typeName(DestType) ++ "' from type '" ++ @typeName(SourceType) ++ "' which is not present in union"); |
| 47 | }, | 50 | }, |
| 51 | .Bool => return cast(usize, target) != 0, | ||
| 48 | else => {}, | 52 | else => {}, |
| 49 | } | 53 | } |
| 50 | return @as(DestType, target); | 54 | return @as(DestType, target); |
src/translate_c.zig+14-4| ... | @@ -1950,7 +1950,10 @@ fn transDeclRefExpr( | ... | @@ -1950,7 +1950,10 @@ fn transDeclRefExpr( |
| 1950 | const value_decl = expr.getDecl(); | 1950 | const value_decl = expr.getDecl(); |
| 1951 | const name = try c.str(@ptrCast(*const clang.NamedDecl, value_decl).getName_bytes_begin()); | 1951 | const name = try c.str(@ptrCast(*const clang.NamedDecl, value_decl).getName_bytes_begin()); |
| 1952 | const mangled_name = scope.getAlias(name); | 1952 | 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); | ||
| 1954 | 1957 | ||
| 1955 | if (@ptrCast(*const clang.Decl, value_decl).getKind() == .Var) { | 1958 | if (@ptrCast(*const clang.Decl, value_decl).getKind() == .Var) { |
| 1956 | const var_decl = @ptrCast(*const clang.VarDecl, value_decl); | 1959 | const var_decl = @ptrCast(*const clang.VarDecl, value_decl); |
| ... | @@ -1999,7 +2002,11 @@ fn transImplicitCastExpr( | ... | @@ -1999,7 +2002,11 @@ fn transImplicitCastExpr( |
| 1999 | }, | 2002 | }, |
| 2000 | .PointerToBoolean => { | 2003 | .PointerToBoolean => { |
| 2001 | // @ptrToInt(val) != 0 | 2004 | // @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); | ||
| 2003 | 2010 | ||
| 2004 | const ne = try Tag.not_equal.create(c.arena, .{ .lhs = ptr_to_int, .rhs = Tag.zero_literal.init() }); | 2011 | const ne = try Tag.not_equal.create(c.arena, .{ .lhs = ptr_to_int, .rhs = Tag.zero_literal.init() }); |
| 2005 | return maybeSuppressResult(c, scope, result_used, ne); | 2012 | return maybeSuppressResult(c, scope, result_used, ne); |
| ... | @@ -2042,7 +2049,7 @@ fn isBuiltinDefined(name: []const u8) bool { | ... | @@ -2042,7 +2049,7 @@ fn isBuiltinDefined(name: []const u8) bool { |
| 2042 | 2049 | ||
| 2043 | fn transBuiltinFnExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!Node { | 2050 | fn transBuiltinFnExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!Node { |
| 2044 | const node = try transExpr(c, scope, expr, used); | 2051 | const node = try transExpr(c, scope, expr, used); |
| 2045 | if (node.castTag(.identifier)) |ident| { | 2052 | if (node.castTag(.fn_identifier)) |ident| { |
| 2046 | const name = ident.data; | 2053 | const name = ident.data; |
| 2047 | if (!isBuiltinDefined(name)) return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO implement function '{s}' in std.zig.c_builtins", .{name}); | 2054 | if (!isBuiltinDefined(name)) return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO implement function '{s}' in std.zig.c_builtins", .{name}); |
| 2048 | } | 2055 | } |
| ... | @@ -2447,7 +2454,10 @@ fn transCCast( | ... | @@ -2447,7 +2454,10 @@ fn transCCast( |
| 2447 | } | 2454 | } |
| 2448 | if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) { | 2455 | if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) { |
| 2449 | // @intCast(dest_type, @ptrToInt(val)) | 2456 | // @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); | ||
| 2451 | return Tag.int_cast.create(c.arena, .{ .lhs = dst_node, .rhs = ptr_to_int }); | 2461 | return Tag.int_cast.create(c.arena, .{ .lhs = dst_node, .rhs = ptr_to_int }); |
| 2452 | } | 2462 | } |
| 2453 | if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) { | 2463 | if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) { |
src/translate_c/ast.zig+11| ... | @@ -36,6 +36,7 @@ pub const Node = extern union { | ... | @@ -36,6 +36,7 @@ pub const Node = extern union { |
| 36 | /// "string"[0..end] | 36 | /// "string"[0..end] |
| 37 | string_slice, | 37 | string_slice, |
| 38 | identifier, | 38 | identifier, |
| 39 | fn_identifier, | ||
| 39 | @"if", | 40 | @"if", |
| 40 | /// if (!operand) break; | 41 | /// if (!operand) break; |
| 41 | if_not_break, | 42 | if_not_break, |
| ... | @@ -335,6 +336,7 @@ pub const Node = extern union { | ... | @@ -335,6 +336,7 @@ pub const Node = extern union { |
| 335 | .char_literal, | 336 | .char_literal, |
| 336 | .enum_literal, | 337 | .enum_literal, |
| 337 | .identifier, | 338 | .identifier, |
| 339 | .fn_identifier, | ||
| 338 | .warning, | 340 | .warning, |
| 339 | .type, | 341 | .type, |
| 340 | .helpers_macro, | 342 | .helpers_macro, |
| ... | @@ -1058,6 +1060,14 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { | ... | @@ -1058,6 +1060,14 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 1058 | .data = undefined, | 1060 | .data = undefined, |
| 1059 | }); | 1061 | }); |
| 1060 | }, | 1062 | }, |
| 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 | }, | ||
| 1061 | .float_literal => { | 1071 | .float_literal => { |
| 1062 | const payload = node.castTag(.float_literal).?.data; | 1072 | const payload = node.castTag(.float_literal).?.data; |
| 1063 | return c.addNode(.{ | 1073 | return c.addNode(.{ |
| ... | @@ -2234,6 +2244,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { | ... | @@ -2234,6 +2244,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { |
| 2234 | .char_literal, | 2244 | .char_literal, |
| 2235 | .enum_literal, | 2245 | .enum_literal, |
| 2236 | .identifier, | 2246 | .identifier, |
| 2247 | .fn_identifier, | ||
| 2237 | .field_access, | 2248 | .field_access, |
| 2238 | .ptr_cast, | 2249 | .ptr_cast, |
| 2239 | .type, | 2250 | .type, |
test/behavior/translate_c_macros.h+8| ... | @@ -40,3 +40,11 @@ union U { | ... | @@ -40,3 +40,11 @@ union U { |
| 40 | #define CAST_OR_CALL_WITH_PARENS(type_or_fn, val) ((type_or_fn)(val)) | 40 | #define CAST_OR_CALL_WITH_PARENS(type_or_fn, val) ((type_or_fn)(val)) |
| 41 | 41 | ||
| 42 | #define NESTED_COMMA_OPERATOR (1, (2, 3)) | 42 | #define NESTED_COMMA_OPERATOR (1, (2, 3)) |
| 43 | |||
| 44 | #include <stdint.h> | ||
| 45 | #if !defined(__UINTPTR_MAX__) | ||
| 46 | typedef _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" { | ... | @@ -99,3 +99,17 @@ test "nested comma operator" { |
| 99 | 99 | ||
| 100 | try expectEqual(@as(c_int, 3), h.NESTED_COMMA_OPERATOR); | 100 | try expectEqual(@as(c_int, 3), h.NESTED_COMMA_OPERATOR); |
| 101 | } | 101 | } |
| 102 | |||
| 103 | test "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 { | ... | @@ -1861,4 +1861,18 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { |
| 1861 | \\ return 0; | 1861 | \\ return 0; |
| 1862 | \\} | 1862 | \\} |
| 1863 | , ""); | 1863 | , ""); |
| 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 | , ""); | ||
| 1864 | } | 1878 | } |
test/translate_c.zig+1-1| ... | @@ -3435,7 +3435,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -3435,7 +3435,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 3435 | \\ var x = arg_x; | 3435 | \\ var x = arg_x; |
| 3436 | \\ var a: bool = @as(c_int, @boolToInt(x)) != @as(c_int, 1); | 3436 | \\ var a: bool = @as(c_int, @boolToInt(x)) != @as(c_int, 1); |
| 3437 | \\ var b: bool = @as(c_int, @boolToInt(a)) != @as(c_int, 0); | 3437 | \\ 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; |
| 3439 | \\ return foo(@as(c_int, @boolToInt(c)) != @as(c_int, @boolToInt(b))); | 3439 | \\ return foo(@as(c_int, @boolToInt(c)) != @as(c_int, @boolToInt(b))); |
| 3440 | \\} | 3440 | \\} |
| 3441 | }); | 3441 | }); |