Commit 62065a9aea

Andrew Kelley <andrew@ziglang.org>
2019-05-09 18:17:23
translate-c: handle int to ptr and ptr to int casting
See #2451
1 parent a7346ea
Changed files (2)
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<const clang::BuiltinType*>(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
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",