Commit c6b3d06535

Andrew Kelley <andrew@ziglang.org>
2021-10-26 22:46:27
Sema: improved C pointers and casting
* C pointer types always have allowzero set to true but they omit the word allowzero when printed. * Implement coercion from C pointers to other pointers. * Implement in-memory coercion for slices and pointer-like optionals. * Make slicing a C pointer drop the allowzero bit. * Value representation for pointer-like optionals is now allowed to use pointer tag values in addition to the `opt_payload` tag.
1 parent 6df26a3
Changed files (6)
src/codegen/llvm.zig
@@ -1184,6 +1184,8 @@ pub const DeclGen = struct {
                 if (tv.ty.isPtrLikeOptional()) {
                     if (tv.val.castTag(.opt_payload)) |payload| {
                         return self.genTypedValue(.{ .ty = payload_ty, .val = payload.data });
+                    } else if (is_pl) {
+                        return self.genTypedValue(.{ .ty = payload_ty, .val = tv.val });
                     } else {
                         const llvm_ty = try self.llvmType(tv.ty);
                         return llvm_ty.constNull();
src/Sema.zig
@@ -9125,7 +9125,7 @@ fn zirPtrTypeSimple(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
         .pointee_type = elem_type,
         .@"addrspace" = .generic,
         .mutable = inst_data.is_mutable,
-        .@"allowzero" = inst_data.is_allowzero,
+        .@"allowzero" = inst_data.is_allowzero or inst_data.size == .C,
         .@"volatile" = inst_data.is_volatile,
         .size = inst_data.size,
     });
@@ -9185,7 +9185,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
         .bit_offset = bit_start,
         .host_size = bit_end,
         .mutable = inst_data.flags.is_mutable,
-        .@"allowzero" = inst_data.flags.is_allowzero,
+        .@"allowzero" = inst_data.flags.is_allowzero or inst_data.size == .C,
         .@"volatile" = inst_data.flags.is_volatile,
         .size = inst_data.size,
     });
@@ -12102,6 +12102,21 @@ fn coerce(
                 }
             }
 
+            // coercion from C pointer
+            if (inst_ty.isCPtr()) src_c_ptr: {
+                // In this case we must add a safety check because the C pointer
+                // could be null.
+                const src_elem_ty = inst_ty.childType();
+                const dest_is_mut = dest_info.mutable;
+                const dst_elem_type = dest_info.pointee_type;
+                switch (coerceInMemoryAllowed(dst_elem_type, src_elem_ty, dest_is_mut, target)) {
+                    .ok => {},
+                    .no_match => break :src_c_ptr,
+                }
+                // TODO add safety check for null pointer
+                return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
+            }
+
             // coercion to C pointer
             if (dest_info.size == .C) {
                 switch (inst_ty.zigTypeTag()) {
@@ -12262,84 +12277,107 @@ const InMemoryCoercionResult = enum {
 /// * sentinel-terminated pointers can coerce into `[*]`
 /// TODO improve this function to report recursive compile errors like it does in stage1.
 /// look at the function types_match_const_cast_only
-fn coerceInMemoryAllowed(dest_ty: Type, src_type: Type, dest_is_mut: bool, target: std.Target) InMemoryCoercionResult {
-    if (dest_ty.eql(src_type))
+fn coerceInMemoryAllowed(dest_ty: Type, src_ty: Type, dest_is_mut: bool, target: std.Target) InMemoryCoercionResult {
+    if (dest_ty.eql(src_ty))
         return .ok;
 
-    if (dest_ty.zigTypeTag() == .Pointer and
-        src_type.zigTypeTag() == .Pointer)
-    {
-        const dest_info = dest_ty.ptrInfo().data;
-        const src_info = src_type.ptrInfo().data;
-
-        const child = coerceInMemoryAllowed(dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target);
-        if (child == .no_match) {
-            return child;
+    // Pointers / Pointer-like Optionals
+    var dest_buf: Type.Payload.ElemType = undefined;
+    var src_buf: Type.Payload.ElemType = undefined;
+    if (dest_ty.ptrOrOptionalPtrTy(&dest_buf)) |dest_ptr_ty| {
+        if (src_ty.ptrOrOptionalPtrTy(&src_buf)) |src_ptr_ty| {
+            return coerceInMemoryAllowedPtrs(dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target);
         }
+    }
 
-        if (dest_info.@"addrspace" != src_info.@"addrspace") {
-            return .no_match;
-        }
+    // Slices
+    if (dest_ty.isSlice() and src_ty.isSlice()) {
+        return coerceInMemoryAllowedPtrs(dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target);
+    }
 
-        const ok_sent = dest_info.sentinel == null or src_info.size == .C or
-            (src_info.sentinel != null and
-            dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type));
-        if (!ok_sent) {
-            return .no_match;
-        }
+    // TODO: arrays
+    // TODO: non-pointer-like optionals
+    // TODO: error unions
+    // TODO: error sets
+    // TODO: functions
+    // TODO: vectors
 
-        const ok_ptr_size = src_info.size == dest_info.size or
-            src_info.size == .C or dest_info.size == .C;
-        if (!ok_ptr_size) {
-            return .no_match;
-        }
+    return .no_match;
+}
 
-        const ok_cv_qualifiers =
-            (src_info.mutable or !dest_info.mutable) and
-            (!src_info.@"volatile" or dest_info.@"volatile");
+fn coerceInMemoryAllowedPtrs(
+    dest_ty: Type,
+    src_ty: Type,
+    dest_ptr_ty: Type,
+    src_ptr_ty: Type,
+    dest_is_mut: bool,
+    target: std.Target,
+) InMemoryCoercionResult {
+    const dest_info = dest_ptr_ty.ptrInfo().data;
+    const src_info = src_ptr_ty.ptrInfo().data;
 
-        if (!ok_cv_qualifiers) {
-            return .no_match;
-        }
+    const child = coerceInMemoryAllowed(dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target);
+    if (child == .no_match) {
+        return child;
+    }
 
-        const ok_allows_zero = (dest_info.@"allowzero" and
-            (src_info.@"allowzero" or !dest_is_mut)) or
-            (!dest_info.@"allowzero" and !src_info.@"allowzero");
-        if (!ok_allows_zero) {
-            return .no_match;
-        }
+    if (dest_info.@"addrspace" != src_info.@"addrspace") {
+        return .no_match;
+    }
 
-        if (dest_ty.hasCodeGenBits() != src_type.hasCodeGenBits()) {
-            return .no_match;
-        }
+    const ok_sent = dest_info.sentinel == null or src_info.size == .C or
+        (src_info.sentinel != null and
+        dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type));
+    if (!ok_sent) {
+        return .no_match;
+    }
 
-        if (src_info.host_size != dest_info.host_size or
-            src_info.bit_offset != dest_info.bit_offset)
-        {
-            return .no_match;
-        }
+    const ok_ptr_size = src_info.size == dest_info.size or
+        src_info.size == .C or dest_info.size == .C;
+    if (!ok_ptr_size) {
+        return .no_match;
+    }
 
-        // If both pointers have alignment 0, it means they both want ABI alignment.
-        // In this case, if they share the same child type, no need to resolve
-        // pointee type alignment. Otherwise both pointee types must have their alignment
-        // resolved and we compare the alignment numerically.
-        if (src_info.@"align" != 0 or dest_info.@"align" != 0 or
-            !dest_info.pointee_type.eql(src_info.pointee_type))
-        {
-            const src_align = src_type.ptrAlignment(target);
-            const dest_align = dest_ty.ptrAlignment(target);
+    const ok_cv_qualifiers =
+        (src_info.mutable or !dest_info.mutable) and
+        (!src_info.@"volatile" or dest_info.@"volatile");
 
-            if (dest_align > src_align) {
-                return .no_match;
-            }
-        }
+    if (!ok_cv_qualifiers) {
+        return .no_match;
+    }
 
-        return .ok;
+    const dest_allow_zero = dest_ty.ptrAllowsZero();
+    const src_allow_zero = src_ty.ptrAllowsZero();
+
+    const ok_allows_zero = (dest_allow_zero and
+        (src_allow_zero or !dest_is_mut)) or
+        (!dest_allow_zero and !src_allow_zero);
+    if (!ok_allows_zero) {
+        return .no_match;
     }
 
-    // TODO: implement more of this function
+    if (src_info.host_size != dest_info.host_size or
+        src_info.bit_offset != dest_info.bit_offset)
+    {
+        return .no_match;
+    }
 
-    return .no_match;
+    // If both pointers have alignment 0, it means they both want ABI alignment.
+    // In this case, if they share the same child type, no need to resolve
+    // pointee type alignment. Otherwise both pointee types must have their alignment
+    // resolved and we compare the alignment numerically.
+    if (src_info.@"align" != 0 or dest_info.@"align" != 0 or
+        !dest_info.pointee_type.eql(src_info.pointee_type))
+    {
+        const src_align = src_info.@"align";
+        const dest_align = dest_info.@"align";
+
+        if (dest_align > src_align) {
+            return .no_match;
+        }
+    }
+
+    return .ok;
 }
 
 fn coerceNum(
@@ -13297,6 +13335,7 @@ fn analyzeSlice(
     const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len);
 
     const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data;
+    const new_allowzero = new_ptr_ty_info.@"allowzero" and sema.typeOf(ptr).ptrSize() != .C;
 
     if (opt_new_len_val) |new_len_val| {
         const new_len_int = new_len_val.toUnsignedInt();
@@ -13312,7 +13351,7 @@ fn analyzeSlice(
             .@"align" = new_ptr_ty_info.@"align",
             .@"addrspace" = new_ptr_ty_info.@"addrspace",
             .mutable = new_ptr_ty_info.mutable,
-            .@"allowzero" = new_ptr_ty_info.@"allowzero",
+            .@"allowzero" = new_allowzero,
             .@"volatile" = new_ptr_ty_info.@"volatile",
             .size = .One,
         });
@@ -13340,7 +13379,7 @@ fn analyzeSlice(
         .@"align" = new_ptr_ty_info.@"align",
         .@"addrspace" = new_ptr_ty_info.@"addrspace",
         .mutable = new_ptr_ty_info.mutable,
-        .@"allowzero" = new_ptr_ty_info.@"allowzero",
+        .@"allowzero" = new_allowzero,
         .@"volatile" = new_ptr_ty_info.@"volatile",
         .size = .Slice,
     });
src/type.zig
@@ -390,7 +390,7 @@ pub const Type = extern union {
                 .@"addrspace" = .generic,
                 .bit_offset = 0,
                 .host_size = 0,
-                .@"allowzero" = false,
+                .@"allowzero" = true,
                 .mutable = false,
                 .@"volatile" = false,
                 .size = .C,
@@ -402,7 +402,7 @@ pub const Type = extern union {
                 .@"addrspace" = .generic,
                 .bit_offset = 0,
                 .host_size = 0,
-                .@"allowzero" = false,
+                .@"allowzero" = true,
                 .mutable = true,
                 .@"volatile" = false,
                 .size = .C,
@@ -1153,7 +1153,7 @@ pub const Type = extern union {
                     }
                     if (!payload.mutable) try writer.writeAll("const ");
                     if (payload.@"volatile") try writer.writeAll("volatile ");
-                    if (payload.@"allowzero") try writer.writeAll("allowzero ");
+                    if (payload.@"allowzero" and payload.size != .C) try writer.writeAll("allowzero ");
 
                     ty = payload.pointee_type;
                     continue;
@@ -2347,7 +2347,48 @@ pub const Type = extern union {
         }
     }
 
-    /// Asserts that the type is an optional or a pointer that can be null.
+    /// For pointer-like optionals, returns true, otherwise returns the allowzero property
+    /// of pointers.
+    pub fn ptrAllowsZero(ty: Type) bool {
+        if (ty.isPtrLikeOptional()) {
+            return true;
+        }
+        return ty.ptrInfo().data.@"allowzero";
+    }
+
+    /// For pointer-like optionals, it returns the pointer type. For pointers,
+    /// the type is returned unmodified.
+    pub fn ptrOrOptionalPtrTy(ty: Type, buf: *Payload.ElemType) ?Type {
+        if (isPtrLikeOptional(ty)) return ty.optionalChild(buf);
+        switch (ty.tag()) {
+            .c_const_pointer,
+            .c_mut_pointer,
+            .single_const_pointer_to_comptime_int,
+            .single_const_pointer,
+            .single_mut_pointer,
+            .many_const_pointer,
+            .many_mut_pointer,
+            .manyptr_u8,
+            .manyptr_const_u8,
+            => return ty,
+
+            .pointer => {
+                if (ty.ptrSize() == .Slice) {
+                    return null;
+                } else {
+                    return ty;
+                }
+            },
+
+            .inferred_alloc_const => unreachable,
+            .inferred_alloc_mut => unreachable,
+
+            else => return null,
+        }
+    }
+
+    /// Returns true if the type is optional and would be lowered to a single pointer
+    /// address value, using 0 for null. Note that this returns true for C pointers.
     pub fn isPtrLikeOptional(self: Type) bool {
         switch (self.tag()) {
             .optional_single_const_pointer,
@@ -2371,7 +2412,8 @@ pub const Type = extern union {
             },
 
             .pointer => return self.castTag(.pointer).?.data.size == .C,
-            else => unreachable,
+
+            else => return false,
         }
     }
 
@@ -2532,38 +2574,50 @@ pub const Type = extern union {
 
     /// Asserts that the type is an optional.
     /// Resulting `Type` will have inner memory referencing `buf`.
-    pub fn optionalChild(self: Type, buf: *Payload.ElemType) Type {
-        return switch (self.tag()) {
-            .optional => self.castTag(.optional).?.data,
+    /// Note that for C pointers this returns the type unmodified.
+    pub fn optionalChild(ty: Type, buf: *Payload.ElemType) Type {
+        return switch (ty.tag()) {
+            .optional => ty.castTag(.optional).?.data,
             .optional_single_mut_pointer => {
                 buf.* = .{
                     .base = .{ .tag = .single_mut_pointer },
-                    .data = self.castPointer().?.data,
+                    .data = ty.castPointer().?.data,
                 };
                 return Type.initPayload(&buf.base);
             },
             .optional_single_const_pointer => {
                 buf.* = .{
                     .base = .{ .tag = .single_const_pointer },
-                    .data = self.castPointer().?.data,
+                    .data = ty.castPointer().?.data,
                 };
                 return Type.initPayload(&buf.base);
             },
+
+            .pointer, // here we assume it is a C pointer
+            .c_const_pointer,
+            .c_mut_pointer,
+            => return ty,
+
             else => unreachable,
         };
     }
 
     /// Asserts that the type is an optional.
     /// Same as `optionalChild` but allocates the buffer if needed.
-    pub fn optionalChildAlloc(self: Type, allocator: *Allocator) !Type {
-        switch (self.tag()) {
-            .optional => return self.castTag(.optional).?.data,
+    pub fn optionalChildAlloc(ty: Type, allocator: *Allocator) !Type {
+        switch (ty.tag()) {
+            .optional => return ty.castTag(.optional).?.data,
             .optional_single_mut_pointer => {
-                return Tag.single_mut_pointer.create(allocator, self.castPointer().?.data);
+                return Tag.single_mut_pointer.create(allocator, ty.castPointer().?.data);
             },
             .optional_single_const_pointer => {
-                return Tag.single_const_pointer.create(allocator, self.castPointer().?.data);
+                return Tag.single_const_pointer.create(allocator, ty.castPointer().?.data);
             },
+            .pointer, // here we assume it is a C pointer
+            .c_const_pointer,
+            .c_mut_pointer,
+            => return ty,
+
             else => unreachable,
         }
     }
@@ -4050,6 +4104,9 @@ pub const Type = extern union {
         if (d.sentinel != null or d.@"align" != 0 or d.@"addrspace" != .generic or
             d.bit_offset != 0 or d.host_size != 0 or d.@"allowzero" or d.@"volatile")
         {
+            if (d.size == .C) {
+                assert(d.@"allowzero"); // All C pointers must set allowzero to true.
+            }
             return Type.Tag.pointer.create(arena, d);
         }
 
src/value.zig
@@ -1819,7 +1819,8 @@ pub const Value = extern union {
             .unreachable_value => unreachable,
             .inferred_alloc => unreachable,
             .inferred_alloc_comptime => unreachable,
-            else => unreachable,
+
+            else => false,
         };
     }
 
test/behavior/cast.zig
@@ -120,3 +120,160 @@ fn incrementVoidPtrArray(array: ?*c_void, len: usize) void {
         @ptrCast([*]u8, array.?)[n] += 1;
     }
 }
+
+test "implicitly cast indirect pointer to maybe-indirect pointer" {
+    const S = struct {
+        const Self = @This();
+        x: u8,
+        fn constConst(p: *const *const Self) u8 {
+            return p.*.x;
+        }
+        fn maybeConstConst(p: ?*const *const Self) u8 {
+            return p.?.*.x;
+        }
+        fn constConstConst(p: *const *const *const Self) u8 {
+            return p.*.*.x;
+        }
+        fn maybeConstConstConst(p: ?*const *const *const Self) u8 {
+            return p.?.*.*.x;
+        }
+    };
+    const s = S{ .x = 42 };
+    const p = &s;
+    const q = &p;
+    const r = &q;
+    try expect(42 == S.constConst(q));
+    try expect(42 == S.maybeConstConst(q));
+    try expect(42 == S.constConstConst(r));
+    try expect(42 == S.maybeConstConstConst(r));
+}
+
+test "@intCast comptime_int" {
+    const result = @intCast(i32, 1234);
+    try expect(@TypeOf(result) == i32);
+    try expect(result == 1234);
+}
+
+test "@floatCast comptime_int and comptime_float" {
+    {
+        const result = @floatCast(f16, 1234);
+        try expect(@TypeOf(result) == f16);
+        try expect(result == 1234.0);
+    }
+    {
+        const result = @floatCast(f16, 1234.0);
+        try expect(@TypeOf(result) == f16);
+        try expect(result == 1234.0);
+    }
+    {
+        const result = @floatCast(f32, 1234);
+        try expect(@TypeOf(result) == f32);
+        try expect(result == 1234.0);
+    }
+    {
+        const result = @floatCast(f32, 1234.0);
+        try expect(@TypeOf(result) == f32);
+        try expect(result == 1234.0);
+    }
+}
+
+test "coerce undefined to optional" {
+    try expect(MakeType(void).getNull() == null);
+    try expect(MakeType(void).getNonNull() != null);
+}
+
+fn MakeType(comptime T: type) type {
+    return struct {
+        fn getNull() ?T {
+            return null;
+        }
+
+        fn getNonNull() ?T {
+            return @as(T, undefined);
+        }
+    };
+}
+
+test "implicit cast from *[N]T to [*c]T" {
+    var x: [4]u16 = [4]u16{ 0, 1, 2, 3 };
+    var y: [*c]u16 = &x;
+
+    try expect(std.mem.eql(u16, x[0..4], y[0..4]));
+    x[0] = 8;
+    y[3] = 6;
+    try expect(std.mem.eql(u16, x[0..4], y[0..4]));
+}
+
+test "*usize to *void" {
+    var i = @as(usize, 0);
+    var v = @ptrCast(*void, &i);
+    v.* = {};
+}
+
+test "compile time int to ptr of function" {
+    try foobar(FUNCTION_CONSTANT);
+}
+
+pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize));
+pub const PFN_void = fn (*c_void) callconv(.C) void;
+
+fn foobar(func: PFN_void) !void {
+    try std.testing.expect(@ptrToInt(func) == maxInt(usize));
+}
+
+test "implicit ptr to *c_void" {
+    var a: u32 = 1;
+    var ptr: *align(@alignOf(u32)) c_void = &a;
+    var b: *u32 = @ptrCast(*u32, ptr);
+    try expect(b.* == 1);
+    var ptr2: ?*align(@alignOf(u32)) c_void = &a;
+    var c: *u32 = @ptrCast(*u32, ptr2.?);
+    try expect(c.* == 1);
+}
+
+test "@intToEnum passed a comptime_int to an enum with one item" {
+    const E = enum { A };
+    const x = @intToEnum(E, 0);
+    try expect(x == E.A);
+}
+
+test "@intCast to u0 and use the result" {
+    const S = struct {
+        fn doTheTest(zero: u1, one: u1, bigzero: i32) !void {
+            try expect((one << @intCast(u0, bigzero)) == 1);
+            try expect((zero << @intCast(u0, bigzero)) == 0);
+        }
+    };
+    try S.doTheTest(0, 1, 0);
+    comptime try S.doTheTest(0, 1, 0);
+}
+
+test "peer result null and comptime_int" {
+    const S = struct {
+        fn blah(n: i32) ?i32 {
+            if (n == 0) {
+                return null;
+            } else if (n < 0) {
+                return -1;
+            } else {
+                return 1;
+            }
+        }
+    };
+
+    try expect(S.blah(0) == null);
+    comptime try expect(S.blah(0) == null);
+    try expect(S.blah(10).? == 1);
+    comptime try expect(S.blah(10).? == 1);
+    try expect(S.blah(-10).? == -1);
+    comptime try expect(S.blah(-10).? == -1);
+}
+
+test "*const ?[*]const T to [*c]const [*c]const T" {
+    var array = [_]u8{ 'o', 'k' };
+    const opt_array_ptr: ?[*]const u8 = &array;
+    const a: *const ?[*]const u8 = &opt_array_ptr;
+    const b: [*c]const [*c]const u8 = a;
+    try expect(b.*[0] == 'o');
+    try expect(b[0][1] == 'k');
+}
test/behavior/cast_stage1.zig
@@ -5,33 +5,6 @@ const maxInt = std.math.maxInt;
 const Vector = std.meta.Vector;
 const native_endian = @import("builtin").target.cpu.arch.endian();
 
-test "implicitly cast indirect pointer to maybe-indirect pointer" {
-    const S = struct {
-        const Self = @This();
-        x: u8,
-        fn constConst(p: *const *const Self) u8 {
-            return p.*.x;
-        }
-        fn maybeConstConst(p: ?*const *const Self) u8 {
-            return p.?.*.x;
-        }
-        fn constConstConst(p: *const *const *const Self) u8 {
-            return p.*.*.x;
-        }
-        fn maybeConstConstConst(p: ?*const *const *const Self) u8 {
-            return p.?.*.*.x;
-        }
-    };
-    const s = S{ .x = 42 };
-    const p = &s;
-    const q = &p;
-    const r = &q;
-    try expect(42 == S.constConst(q));
-    try expect(42 == S.maybeConstConst(q));
-    try expect(42 == S.constConstConst(r));
-    try expect(42 == S.maybeConstConstConst(r));
-}
-
 test "explicit cast from integer to error type" {
     try testCastIntToErr(error.ItBroke);
     comptime try testCastIntToErr(error.ItBroke);
@@ -175,7 +148,7 @@ fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 {
     return slice[0..1];
 }
 
-test "implicit cast from &const [N]T to []const T" {
+test "implicit cast from *const [N]T to []const T" {
     try testCastConstArrayRefToConstSlice();
     comptime try testCastConstArrayRefToConstSlice();
 }
@@ -258,7 +231,7 @@ fn cast128Float(x: u128) f128 {
     return @bitCast(f128, x);
 }
 
-test "single-item pointer of array to slice and to unknown length pointer" {
+test "single-item pointer of array to slice to unknown length pointer" {
     try testCastPtrOfArrayToSliceAndPtr();
     comptime try testCastPtrOfArrayToSliceAndPtr();
 }
@@ -290,35 +263,6 @@ test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
     try expect(mem.eql(u8, std.mem.spanZ(@ptrCast([*:0]const u8, x[0].?)), "window name"));
 }
 
-test "@intCast comptime_int" {
-    const result = @intCast(i32, 1234);
-    try expect(@TypeOf(result) == i32);
-    try expect(result == 1234);
-}
-
-test "@floatCast comptime_int and comptime_float" {
-    {
-        const result = @floatCast(f16, 1234);
-        try expect(@TypeOf(result) == f16);
-        try expect(result == 1234.0);
-    }
-    {
-        const result = @floatCast(f16, 1234.0);
-        try expect(@TypeOf(result) == f16);
-        try expect(result == 1234.0);
-    }
-    {
-        const result = @floatCast(f32, 1234);
-        try expect(@TypeOf(result) == f32);
-        try expect(result == 1234.0);
-    }
-    {
-        const result = @floatCast(f32, 1234.0);
-        try expect(@TypeOf(result) == f32);
-        try expect(result == 1234.0);
-    }
-}
-
 test "vector casts" {
     const S = struct {
         fn doTheTest() !void {
@@ -369,23 +313,6 @@ test "@floatCast cast down" {
     }
 }
 
-test "implicit cast undefined to optional" {
-    try expect(MakeType(void).getNull() == null);
-    try expect(MakeType(void).getNonNull() != null);
-}
-
-fn MakeType(comptime T: type) type {
-    return struct {
-        fn getNull() ?T {
-            return null;
-        }
-
-        fn getNonNull() ?T {
-            return @as(T, undefined);
-        }
-    };
-}
-
 test "implicit cast from *[N]T to ?[*]T" {
     var x: ?[*]u16 = null;
     var y: [4]u16 = [4]u16{ 0, 1, 2, 3 };
@@ -397,16 +324,6 @@ test "implicit cast from *[N]T to ?[*]T" {
     try expect(std.mem.eql(u16, x.?[0..4], y[0..4]));
 }
 
-test "implicit cast from *[N]T to [*c]T" {
-    var x: [4]u16 = [4]u16{ 0, 1, 2, 3 };
-    var y: [*c]u16 = &x;
-
-    try expect(std.mem.eql(u16, x[0..4], y[0..4]));
-    x[0] = 8;
-    y[3] = 6;
-    try expect(std.mem.eql(u16, x[0..4], y[0..4]));
-}
-
 test "implicit cast from *T to ?*c_void" {
     var a: u8 = 1;
     incrementVoidPtrValue(&a);
@@ -417,50 +334,6 @@ fn incrementVoidPtrValue(value: ?*c_void) void {
     @ptrCast(*u8, value.?).* += 1;
 }
 
-test "*usize to *void" {
-    var i = @as(usize, 0);
-    var v = @ptrCast(*void, &i);
-    v.* = {};
-}
-
-test "compile time int to ptr of function" {
-    try foobar(FUNCTION_CONSTANT);
-}
-
-pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize));
-pub const PFN_void = fn (*c_void) callconv(.C) void;
-
-fn foobar(func: PFN_void) !void {
-    try std.testing.expect(@ptrToInt(func) == maxInt(usize));
-}
-
-test "implicit ptr to *c_void" {
-    var a: u32 = 1;
-    var ptr: *align(@alignOf(u32)) c_void = &a;
-    var b: *u32 = @ptrCast(*u32, ptr);
-    try expect(b.* == 1);
-    var ptr2: ?*align(@alignOf(u32)) c_void = &a;
-    var c: *u32 = @ptrCast(*u32, ptr2.?);
-    try expect(c.* == 1);
-}
-
-test "@intToEnum passed a comptime_int to an enum with one item" {
-    const E = enum { A };
-    const x = @intToEnum(E, 0);
-    try expect(x == E.A);
-}
-
-test "@intCast to u0 and use the result" {
-    const S = struct {
-        fn doTheTest(zero: u1, one: u1, bigzero: i32) !void {
-            try expect((one << @intCast(u0, bigzero)) == 1);
-            try expect((zero << @intCast(u0, bigzero)) == 0);
-        }
-    };
-    try S.doTheTest(0, 1, 0);
-    comptime try S.doTheTest(0, 1, 0);
-}
-
 test "peer type resolution: unreachable, null, slice" {
     const S = struct {
         fn doTheTest(num: usize, word: []const u8) !void {
@@ -639,27 +512,6 @@ test "return u8 coercing into ?u32 return type" {
     comptime try S.doTheTest();
 }
 
-test "peer result null and comptime_int" {
-    const S = struct {
-        fn blah(n: i32) ?i32 {
-            if (n == 0) {
-                return null;
-            } else if (n < 0) {
-                return -1;
-            } else {
-                return 1;
-            }
-        }
-    };
-
-    try expect(S.blah(0) == null);
-    comptime try expect(S.blah(0) == null);
-    try expect(S.blah(10).? == 1);
-    comptime try expect(S.blah(10).? == 1);
-    try expect(S.blah(-10).? == -1);
-    comptime try expect(S.blah(-10).? == -1);
-}
-
 test "peer type resolution implicit cast to return type" {
     const S = struct {
         fn doTheTest() !void {