mirror of
https://github.com/ziglang/zig.git
synced 2024-11-15 00:26:57 +00:00
translate-c: take address of functions before passing them to @ptrToInt
Fixes #12194
This commit is contained in:
parent
c8c798685f
commit
7ba1f9bfb5
@ -36,6 +36,9 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
|
||||
.Int => {
|
||||
return castInt(DestType, target);
|
||||
},
|
||||
.Fn => {
|
||||
return castInt(DestType, @ptrToInt(&target));
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
},
|
||||
@ -45,6 +48,7 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
|
||||
}
|
||||
@compileError("cast to union type '" ++ @typeName(DestType) ++ "' from type '" ++ @typeName(SourceType) ++ "' which is not present in union");
|
||||
},
|
||||
.Bool => return cast(usize, target) != 0,
|
||||
else => {},
|
||||
}
|
||||
return @as(DestType, target);
|
||||
|
@ -1950,7 +1950,10 @@ fn transDeclRefExpr(
|
||||
const value_decl = expr.getDecl();
|
||||
const name = try c.str(@ptrCast(*const clang.NamedDecl, value_decl).getName_bytes_begin());
|
||||
const mangled_name = scope.getAlias(name);
|
||||
var ref_expr = try Tag.identifier.create(c.arena, mangled_name);
|
||||
var ref_expr = if (cIsFunctionDeclRef(@ptrCast(*const clang.Expr, expr)))
|
||||
try Tag.fn_identifier.create(c.arena, mangled_name)
|
||||
else
|
||||
try Tag.identifier.create(c.arena, mangled_name);
|
||||
|
||||
if (@ptrCast(*const clang.Decl, value_decl).getKind() == .Var) {
|
||||
const var_decl = @ptrCast(*const clang.VarDecl, value_decl);
|
||||
@ -1999,7 +2002,11 @@ fn transImplicitCastExpr(
|
||||
},
|
||||
.PointerToBoolean => {
|
||||
// @ptrToInt(val) != 0
|
||||
const ptr_to_int = try Tag.ptr_to_int.create(c.arena, try transExpr(c, scope, sub_expr, .used));
|
||||
var ptr_node = try transExpr(c, scope, sub_expr, .used);
|
||||
if (ptr_node.tag() == .fn_identifier) {
|
||||
ptr_node = try Tag.address_of.create(c.arena, ptr_node);
|
||||
}
|
||||
const ptr_to_int = try Tag.ptr_to_int.create(c.arena, ptr_node);
|
||||
|
||||
const ne = try Tag.not_equal.create(c.arena, .{ .lhs = ptr_to_int, .rhs = Tag.zero_literal.init() });
|
||||
return maybeSuppressResult(c, scope, result_used, ne);
|
||||
@ -2042,7 +2049,7 @@ fn isBuiltinDefined(name: []const u8) bool {
|
||||
|
||||
fn transBuiltinFnExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!Node {
|
||||
const node = try transExpr(c, scope, expr, used);
|
||||
if (node.castTag(.identifier)) |ident| {
|
||||
if (node.castTag(.fn_identifier)) |ident| {
|
||||
const name = ident.data;
|
||||
if (!isBuiltinDefined(name)) return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO implement function '{s}' in std.zig.c_builtins", .{name});
|
||||
}
|
||||
@ -2447,7 +2454,10 @@ fn transCCast(
|
||||
}
|
||||
if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) {
|
||||
// @intCast(dest_type, @ptrToInt(val))
|
||||
const ptr_to_int = try Tag.ptr_to_int.create(c.arena, expr);
|
||||
const ptr_to_int = if (expr.tag() == .fn_identifier)
|
||||
try Tag.ptr_to_int.create(c.arena, try Tag.address_of.create(c.arena, expr))
|
||||
else
|
||||
try Tag.ptr_to_int.create(c.arena, expr);
|
||||
return Tag.int_cast.create(c.arena, .{ .lhs = dst_node, .rhs = ptr_to_int });
|
||||
}
|
||||
if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) {
|
||||
|
@ -36,6 +36,7 @@ pub const Node = extern union {
|
||||
/// "string"[0..end]
|
||||
string_slice,
|
||||
identifier,
|
||||
fn_identifier,
|
||||
@"if",
|
||||
/// if (!operand) break;
|
||||
if_not_break,
|
||||
@ -335,6 +336,7 @@ pub const Node = extern union {
|
||||
.char_literal,
|
||||
.enum_literal,
|
||||
.identifier,
|
||||
.fn_identifier,
|
||||
.warning,
|
||||
.type,
|
||||
.helpers_macro,
|
||||
@ -1058,6 +1060,14 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
|
||||
.data = undefined,
|
||||
});
|
||||
},
|
||||
.fn_identifier => {
|
||||
const payload = node.castTag(.fn_identifier).?.data;
|
||||
return c.addNode(.{
|
||||
.tag = .identifier,
|
||||
.main_token = try c.addIdentifier(payload),
|
||||
.data = undefined,
|
||||
});
|
||||
},
|
||||
.float_literal => {
|
||||
const payload = node.castTag(.float_literal).?.data;
|
||||
return c.addNode(.{
|
||||
@ -2234,6 +2244,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
|
||||
.char_literal,
|
||||
.enum_literal,
|
||||
.identifier,
|
||||
.fn_identifier,
|
||||
.field_access,
|
||||
.ptr_cast,
|
||||
.type,
|
||||
|
@ -40,3 +40,11 @@ union U {
|
||||
#define CAST_OR_CALL_WITH_PARENS(type_or_fn, val) ((type_or_fn)(val))
|
||||
|
||||
#define NESTED_COMMA_OPERATOR (1, (2, 3))
|
||||
|
||||
#include <stdint.h>
|
||||
#if !defined(__UINTPTR_MAX__)
|
||||
typedef _Bool uintptr_t;
|
||||
#endif
|
||||
|
||||
#define CAST_TO_BOOL(X) (_Bool)(X)
|
||||
#define CAST_TO_UINTPTR(X) (uintptr_t)(X)
|
||||
|
@ -99,3 +99,17 @@ test "nested comma operator" {
|
||||
|
||||
try expectEqual(@as(c_int, 3), h.NESTED_COMMA_OPERATOR);
|
||||
}
|
||||
|
||||
test "cast functions" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
|
||||
const S = struct {
|
||||
fn foo() void {}
|
||||
};
|
||||
try expectEqual(true, h.CAST_TO_BOOL(S.foo));
|
||||
try expect(h.CAST_TO_UINTPTR(S.foo) != 0);
|
||||
}
|
||||
|
@ -1861,4 +1861,18 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
|
||||
// The C standard does not require function pointers to be convertible to any integer type.
|
||||
// However, POSIX requires that function pointers have the same representation as `void *`
|
||||
// so that dlsym() can work
|
||||
cases.add("Function to integral",
|
||||
\\#include <stdint.h>
|
||||
\\int main(void) {
|
||||
\\#if defined(__UINTPTR_MAX__) && __has_include(<unistd.h>)
|
||||
\\ uintptr_t x = main;
|
||||
\\ x = (uintptr_t)main;
|
||||
\\#endif
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
}
|
||||
|
@ -3435,7 +3435,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ var x = arg_x;
|
||||
\\ var a: bool = @as(c_int, @boolToInt(x)) != @as(c_int, 1);
|
||||
\\ var b: bool = @as(c_int, @boolToInt(a)) != @as(c_int, 0);
|
||||
\\ var c: bool = @ptrToInt(foo) != 0;
|
||||
\\ var c: bool = @ptrToInt(&foo) != 0;
|
||||
\\ return foo(@as(c_int, @boolToInt(c)) != @as(c_int, @boolToInt(b)));
|
||||
\\}
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user