From 62065a9aea1c3c93cfea617403b7d5dc8344e36a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 9 May 2019 12:17:23 -0400 Subject: [PATCH] translate-c: handle int to ptr and ptr to int casting See #2451 --- src/translate_c.cpp | 38 ++++++++++++++++++++++++++++++++++++++ test/translate_c.zig | 14 ++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 706d296fc0..0935d229c1 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -581,6 +581,33 @@ static bool qual_type_is_ptr(ZigClangQualType qt) { return ZigClangType_getTypeClass(ty) == ZigClangType_Pointer; } +static bool qual_type_is_int(ZigClangQualType qt) { + const ZigClangType *ty = qual_type_canon(qt); + if (ZigClangType_getTypeClass(ty) != ZigClangType_Builtin) + return false; + const clang::BuiltinType *builtin_ty = reinterpret_cast(ty); + switch (builtin_ty->getKind()) { + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::Char_S: + case clang::BuiltinType::Char8: + case clang::BuiltinType::SChar: + case clang::BuiltinType::UShort: + case clang::BuiltinType::UInt: + case clang::BuiltinType::ULong: + case clang::BuiltinType::ULongLong: + case clang::BuiltinType::Short: + case clang::BuiltinType::Int: + case clang::BuiltinType::Long: + case clang::BuiltinType::LongLong: + case clang::BuiltinType::UInt128: + case clang::BuiltinType::Int128: + return true; + default: + return false; + } +} + static const clang::FunctionProtoType *qual_type_get_fn_proto(ZigClangQualType qt, bool *is_ptr) { const ZigClangType *ty = qual_type_canon(qt); *is_ptr = false; @@ -744,6 +771,17 @@ static AstNode* trans_c_cast(Context *c, ZigClangSourceLocation source_location, if (qual_type_is_ptr(dest_type) && qual_type_is_ptr(src_type)) { return trans_c_ptr_cast(c, source_location, dest_type, src_type, expr); } + if (qual_type_is_int(dest_type) && qual_type_is_ptr(src_type)) { + AstNode *addr_node = trans_create_node_builtin_fn_call_str(c, "ptrToInt"); + addr_node->data.fn_call_expr.params.append(expr); + return trans_create_node_fn_call_1(c, trans_qual_type(c, dest_type, source_location), addr_node); + } + if (qual_type_is_int(src_type) && qual_type_is_ptr(dest_type)) { + AstNode *ptr_node = trans_create_node_builtin_fn_call_str(c, "intToPtr"); + ptr_node->data.fn_call_expr.params.append(trans_qual_type(c, dest_type, source_location)); + ptr_node->data.fn_call_expr.params.append(expr); + return ptr_node; + } // TODO: maybe widen to increase size // TODO: maybe bitcast to change sign // TODO: maybe truncate to reduce size diff --git a/test/translate_c.zig b/test/translate_c.zig index 21b33e69df..28a58fa386 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -2,6 +2,20 @@ const tests = @import("tests.zig"); const builtin = @import("builtin"); pub fn addCases(cases: *tests.TranslateCContext) void { + cases.add("casting pointers to ints and ints to pointers", + \\void foo(void); + \\void bar(void) { + \\ void *func_ptr = foo; + \\ void (*typed_func_ptr)(void) = (void (*)(void)) (unsigned long) func_ptr; + \\} + , + \\pub extern fn foo() void; + \\pub fn bar() void { + \\ var func_ptr: ?*c_void = @ptrCast(?*c_void, foo); + \\ var typed_func_ptr: ?extern fn() void = @intToPtr(?extern fn() void, c_ulong(@ptrToInt(func_ptr))); + \\} + ); + if (builtin.os != builtin.Os.windows) { // Windows treats this as an enum with type c_int cases.add("big negative enum init values when C ABI supports long long enums",