diff --git a/src/Sema.zig b/src/Sema.zig index dfe42e38ea0a361054cc3580f741c8a8658a828b..d61aa52be48a4de52acc6c387f07803a5b52bf33 100644 --- a/src/Sema.zig +++ b/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,86 +12277,109 @@ 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; - } - - if (dest_info.@"addrspace" != src_info.@"addrspace") { - 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; - } - - 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; - } - - const ok_cv_qualifiers = - (src_info.mutable or !dest_info.mutable) and - (!src_info.@"volatile" or dest_info.@"volatile"); - - if (!ok_cv_qualifiers) { - return .no_match; - } - - 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_ty.hasCodeGenBits() != src_type.hasCodeGenBits()) { - return .no_match; - } - - if (src_info.host_size != dest_info.host_size or - src_info.bit_offset != dest_info.bit_offset) - { - 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); - - if (dest_align > src_align) { - return .no_match; - } + // 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); } + } - return .ok; + // Slices + if (dest_ty.isSlice() and src_ty.isSlice()) { + return coerceInMemoryAllowedPtrs(dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target); } - // TODO: implement more of this function + // TODO: arrays + // TODO: non-pointer-like optionals + // TODO: error unions + // TODO: error sets + // TODO: functions + // TODO: vectors return .no_match; } +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; + + const child = coerceInMemoryAllowed(dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target); + if (child == .no_match) { + return child; + } + + if (dest_info.@"addrspace" != src_info.@"addrspace") { + 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; + } + + 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; + } + + const ok_cv_qualifiers = + (src_info.mutable or !dest_info.mutable) and + (!src_info.@"volatile" or dest_info.@"volatile"); + + if (!ok_cv_qualifiers) { + return .no_match; + } + + 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; + } + + if (src_info.host_size != dest_info.host_size or + src_info.bit_offset != dest_info.bit_offset) + { + 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( sema: *Sema, block: *Block, @@ -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, }); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index ca9e973354640ea6155ab34aaf02cc2c0e3ccbb1..fd92dec413a6ec52cec259c0eaa4f363e969d300 100644 --- a/src/codegen/llvm.zig +++ b/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(); diff --git a/src/type.zig b/src/type.zig index 589639ab7fd3fb689a9da6a5e0574e9c1160cf71..e1a407011b4e8add6beba8b25c611edce35eb2a4 100644 --- a/src/type.zig +++ b/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); } diff --git a/src/value.zig b/src/value.zig index 19c2a736667cfc6d7e5c2fb8722d81b447c1920d..382aeeedf7582065aa423a115acfc7e6ab24b427 100644 --- a/src/value.zig +++ b/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, }; } diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 42e6016061334261353150e1a1d1afd0e139adc2..040ddafd784246b023886b410b4bbf34982c996a 100644 --- a/test/behavior/cast.zig +++ b/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'); +} diff --git a/test/behavior/cast_stage1.zig b/test/behavior/cast_stage1.zig index 8eb6302e6077e8f7517a5ce0a07051d16dea331d..1a5679bc0c285a205bdd5f26584550610d57df7f 100644 --- a/test/behavior/cast_stage1.zig +++ b/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 {