authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-01 14:06:51-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-01 14:06:51-05:00
logae1ebe09b7c1258bfa8de37244fd9b510b1447a4
treeaa02aa86d4d916f55b7666f379df78c72fb13cea
parentbbe857be96084bae6ca1e5f10e35f3631df50edc
signaturelock-open Commit is signed but in an unrecognized format.

add compile errror for @bitCast when bit counts mismatch

fixes invalid LLVM IR from previous commit

3 files changed, 46 insertions(+), 23 deletions(-)

src/ir.cpp+12-2
...@@ -20580,10 +20580,10 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct...@@ -20580,10 +20580,10 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct
20580 if (type_is_invalid(src_type))20580 if (type_is_invalid(src_type))
20581 return ira->codegen->invalid_instruction;20581 return ira->codegen->invalid_instruction;
2058220582
20583 if ((err = ensure_complete_type(ira->codegen, dest_type)))20583 if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusSizeKnown)))
20584 return ira->codegen->invalid_instruction;20584 return ira->codegen->invalid_instruction;
2058520585
20586 if ((err = ensure_complete_type(ira->codegen, src_type)))20586 if ((err = type_resolve(ira->codegen, src_type, ResolveStatusSizeKnown)))
20587 return ira->codegen->invalid_instruction;20587 return ira->codegen->invalid_instruction;
2058820588
20589 if (get_codegen_ptr_type(src_type) != nullptr) {20589 if (get_codegen_ptr_type(src_type) != nullptr) {
...@@ -20646,6 +20646,16 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct...@@ -20646,6 +20646,16 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct
20646 return ira->codegen->invalid_instruction;20646 return ira->codegen->invalid_instruction;
20647 }20647 }
2064820648
20649 uint64_t dest_size_bits = type_size_bits(ira->codegen, dest_type);
20650 uint64_t src_size_bits = type_size_bits(ira->codegen, src_type);
20651 if (dest_size_bits != src_size_bits) {
20652 ir_add_error(ira, &instruction->base,
20653 buf_sprintf("destination type '%s' has %" ZIG_PRI_u64 " bits but source type '%s' has %" ZIG_PRI_u64 " bits",
20654 buf_ptr(&dest_type->name), dest_size_bits,
20655 buf_ptr(&src_type->name), src_size_bits));
20656 return ira->codegen->invalid_instruction;
20657 }
20658
20649 if (instr_is_comptime(value)) {20659 if (instr_is_comptime(value)) {
20650 ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);20660 ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
20651 if (!val)20661 if (!val)
std/io.zig+25-21
...@@ -503,13 +503,13 @@ pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type {...@@ -503,13 +503,13 @@ pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type {
503 /// containing them in the least significant end. The number of bits successfully503 /// containing them in the least significant end. The number of bits successfully
504 /// read is placed in `out_bits`, as reaching the end of the stream is not an error.504 /// read is placed in `out_bits`, as reaching the end of the stream is not an error.
505 pub fn readBits(self: *Self, comptime U: type, bits: usize, out_bits: *usize) Error!U {505 pub fn readBits(self: *Self, comptime U: type, bits: usize, out_bits: *usize) Error!U {
506 debug.assert(trait.isUnsignedInt(U));506 comptime assert(trait.isUnsignedInt(U));
507507
508 //by extending the buffer to a minimum of u8 we can cover a number of edge cases508 //by extending the buffer to a minimum of u8 we can cover a number of edge cases
509 // related to shifting and casting.509 // related to shifting and casting.
510 const u_bit_count = comptime meta.bitCount(U);510 const u_bit_count = comptime meta.bitCount(U);
511 const buf_bit_count = bc: {511 const buf_bit_count = bc: {
512 debug.assert(u_bit_count >= bits);512 assert(u_bit_count >= bits);
513 break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count;513 break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count;
514 };514 };
515 const Buf = @IntType(false, buf_bit_count);515 const Buf = @IntType(false, buf_bit_count);
...@@ -664,7 +664,7 @@ test "io.SliceOutStream" {...@@ -664,7 +664,7 @@ test "io.SliceOutStream" {
664 const stream = &slice_stream.stream;664 const stream = &slice_stream.stream;
665665
666 try stream.print("{}{}!", "Hello", "World");666 try stream.print("{}{}!", "Hello", "World");
667 debug.assert(mem.eql(u8, "HelloWorld!", slice_stream.getWritten()));667 debug.assertOrPanic(mem.eql(u8, "HelloWorld!", slice_stream.getWritten()));
668}668}
669669
670var null_out_stream_state = NullOutStream.init();670var null_out_stream_state = NullOutStream.init();
...@@ -726,7 +726,7 @@ test "io.CountingOutStream" {...@@ -726,7 +726,7 @@ test "io.CountingOutStream" {
726726
727 const bytes = "yay" ** 10000;727 const bytes = "yay" ** 10000;
728 stream.write(bytes) catch unreachable;728 stream.write(bytes) catch unreachable;
729 debug.assert(counting_stream.bytes_written == bytes.len);729 debug.assertOrPanic(counting_stream.bytes_written == bytes.len);
730}730}
731731
732pub fn BufferedOutStream(comptime Error: type) type {732pub fn BufferedOutStream(comptime Error: type) type {
...@@ -835,13 +835,13 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {...@@ -835,13 +835,13 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
835 if (bits == 0) return;835 if (bits == 0) return;
836836
837 const U = @typeOf(value);837 const U = @typeOf(value);
838 debug.assert(trait.isUnsignedInt(U));838 comptime assert(trait.isUnsignedInt(U));
839839
840 //by extending the buffer to a minimum of u8 we can cover a number of edge cases840 //by extending the buffer to a minimum of u8 we can cover a number of edge cases
841 // related to shifting and casting.841 // related to shifting and casting.
842 const u_bit_count = comptime meta.bitCount(U);842 const u_bit_count = comptime meta.bitCount(U);
843 const buf_bit_count = bc: {843 const buf_bit_count = bc: {
844 debug.assert(u_bit_count >= bits);844 assert(u_bit_count >= bits);
845 break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count;845 break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count;
846 };846 };
847 const Buf = @IntType(false, buf_bit_count);847 const Buf = @IntType(false, buf_bit_count);
...@@ -1013,10 +1013,10 @@ test "io.readLineFrom" {...@@ -1013,10 +1013,10 @@ test "io.readLineFrom" {
1013 );1013 );
1014 const stream = &mem_stream.stream;1014 const stream = &mem_stream.stream;
10151015
1016 debug.assert(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf)));1016 debug.assertOrPanic(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf)));
1017 debug.assert(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf)));1017 debug.assertOrPanic(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf)));
1018 debug.assertError(readLineFrom(stream, &buf), error.EndOfStream);1018 debug.assertError(readLineFrom(stream, &buf), error.EndOfStream);
1019 debug.assert(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333"));1019 debug.assertOrPanic(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333"));
1020}1020}
10211021
1022pub fn readLineSlice(slice: []u8) ![]u8 {1022pub fn readLineSlice(slice: []u8) ![]u8 {
...@@ -1044,7 +1044,7 @@ test "io.readLineSliceFrom" {...@@ -1044,7 +1044,7 @@ test "io.readLineSliceFrom" {
1044 );1044 );
1045 const stream = &mem_stream.stream;1045 const stream = &mem_stream.stream;
10461046
1047 debug.assert(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..])));1047 debug.assertOrPanic(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..])));
1048 debug.assertError(readLineSliceFrom(stream, buf[0..]), error.OutOfMemory);1048 debug.assertError(readLineSliceFrom(stream, buf[0..]), error.OutOfMemory);
1049}1049}
10501050
...@@ -1057,7 +1057,7 @@ test "io.readLineSliceFrom" {...@@ -1057,7 +1057,7 @@ test "io.readLineSliceFrom" {
1057/// which will be called when the deserializer is used to deserialize1057/// which will be called when the deserializer is used to deserialize
1058/// that type. It will pass a pointer to the type instance to deserialize1058/// that type. It will pass a pointer to the type instance to deserialize
1059/// into and a pointer to the deserializer struct.1059/// into and a pointer to the deserializer struct.
1060pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: type) type {1060pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime Error: type) type {
1061 return struct {1061 return struct {
1062 const Self = @This();1062 const Self = @This();
10631063
...@@ -1079,9 +1079,9 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ...@@ -1079,9 +1079,9 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ
10791079
1080 //@BUG: inferred error issue. See: #1386 1080 //@BUG: inferred error issue. See: #1386
1081 fn deserializeInt(self: *Self, comptime T: type) (Stream.Error || error{EndOfStream})!T {1081 fn deserializeInt(self: *Self, comptime T: type) (Stream.Error || error{EndOfStream})!T {
1082 debug.assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T));1082 comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T));
10831083
1084 const u8_bit_count = comptime meta.bitCount(u8);1084 const u8_bit_count = 8;
1085 const t_bit_count = comptime meta.bitCount(T);1085 const t_bit_count = comptime meta.bitCount(T);
10861086
1087 const U = @IntType(false, t_bit_count);1087 const U = @IntType(false, t_bit_count);
...@@ -1097,13 +1097,17 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ...@@ -1097,13 +1097,17 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ
1097 const read_size = try self.in_stream.read(buffer[0..]);1097 const read_size = try self.in_stream.read(buffer[0..]);
1098 if (read_size < int_size) return error.EndOfStream;1098 if (read_size < int_size) return error.EndOfStream;
10991099
1100 if (int_size == 1) return @bitCast(T, buffer[0]);1100 if (int_size == 1) {
1101 if (t_bit_count == 8) return @bitCast(T, buffer[0]);
1102 const PossiblySignedByte = @IntType(T.is_signed, 8);
1103 return @truncate(T, @bitCast(PossiblySignedByte, buffer[0]));
1104 }
11011105
1102 var result = U(0);1106 var result = U(0);
1103 for (buffer) |byte, i| {1107 for (buffer) |byte, i| {
1104 switch (endian) {1108 switch (endian) {
1105 builtin.Endian.Big => {1109 builtin.Endian.Big => {
1106 result = (result << @intCast(u4, u8_bit_count)) | byte;1110 result = (result << u8_bit_count) | byte;
1107 },1111 },
1108 builtin.Endian.Little => {1112 builtin.Endian.Little => {
1109 result |= U(byte) << @intCast(Log2U, u8_bit_count * i);1113 result |= U(byte) << @intCast(Log2U, u8_bit_count * i);
...@@ -1118,12 +1122,12 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ...@@ -1118,12 +1122,12 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ
1118 // see: #13151122 // see: #1315
1119 fn setTag(ptr: var, tag: var) void {1123 fn setTag(ptr: var, tag: var) void {
1120 const T = @typeOf(ptr);1124 const T = @typeOf(ptr);
1121 comptime debug.assert(trait.isPtrTo(builtin.TypeId.Union)(T));1125 comptime assert(trait.isPtrTo(builtin.TypeId.Union)(T));
1122 const U = meta.Child(T);1126 const U = meta.Child(T);
11231127
1124 const info = @typeInfo(U).Union;1128 const info = @typeInfo(U).Union;
1125 if (info.tag_type) |TagType| {1129 if (info.tag_type) |TagType| {
1126 debug.assert(TagType == @typeOf(tag));1130 comptime assert(TagType == @typeOf(tag));
11271131
1128 var ptr_tag = ptr: {1132 var ptr_tag = ptr: {
1129 if (@alignOf(TagType) >= @alignOf(U)) break :ptr @ptrCast(*TagType, ptr);1133 if (@alignOf(TagType) >= @alignOf(U)) break :ptr @ptrCast(*TagType, ptr);
...@@ -1151,7 +1155,7 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ...@@ -1151,7 +1155,7 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ
1151 /// Deserializes data into the type pointed to by `ptr`1155 /// Deserializes data into the type pointed to by `ptr`
1152 pub fn deserializeInto(self: *Self, ptr: var) !void {1156 pub fn deserializeInto(self: *Self, ptr: var) !void {
1153 const T = @typeOf(ptr);1157 const T = @typeOf(ptr);
1154 debug.assert(trait.is(builtin.TypeId.Pointer)(T));1158 comptime assert(trait.is(builtin.TypeId.Pointer)(T));
11551159
1156 if (comptime trait.isSlice(T) or comptime trait.isPtrTo(builtin.TypeId.Array)(T)) {1160 if (comptime trait.isSlice(T) or comptime trait.isPtrTo(builtin.TypeId.Array)(T)) {
1157 for (ptr) |*v|1161 for (ptr) |*v|
...@@ -1159,7 +1163,7 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ...@@ -1159,7 +1163,7 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ
1159 return;1163 return;
1160 }1164 }
11611165
1162 comptime debug.assert(trait.isSingleItemPtr(T));1166 comptime assert(trait.isSingleItemPtr(T));
11631167
1164 const C = comptime meta.Child(T);1168 const C = comptime meta.Child(T);
1165 const child_type_id = @typeId(C);1169 const child_type_id = @typeId(C);
...@@ -1266,7 +1270,7 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ...@@ -1266,7 +1270,7 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ
1266/// which will be called when the serializer is used to serialize that type. It will1270/// which will be called when the serializer is used to serialize that type. It will
1267/// pass a const pointer to the type instance to be serialized and a pointer1271/// pass a const pointer to the type instance to be serialized and a pointer
1268/// to the serializer struct.1272/// to the serializer struct.
1269pub fn Serializer(endian: builtin.Endian, is_packed: bool, comptime Error: type) type {1273pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, comptime Error: type) type {
1270 return struct {1274 return struct {
1271 const Self = @This();1275 const Self = @This();
12721276
...@@ -1288,7 +1292,7 @@ pub fn Serializer(endian: builtin.Endian, is_packed: bool, comptime Error: type)...@@ -1288,7 +1292,7 @@ pub fn Serializer(endian: builtin.Endian, is_packed: bool, comptime Error: type)
12881292
1289 fn serializeInt(self: *Self, value: var) !void {1293 fn serializeInt(self: *Self, value: var) !void {
1290 const T = @typeOf(value);1294 const T = @typeOf(value);
1291 debug.assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T));1295 comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T));
12921296
1293 const t_bit_count = comptime meta.bitCount(T);1297 const t_bit_count = comptime meta.bitCount(T);
1294 const u8_bit_count = comptime meta.bitCount(u8);1298 const u8_bit_count = comptime meta.bitCount(u8);
test/compile_errors.zig+9
...@@ -1,6 +1,15 @@...@@ -1,6 +1,15 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: *tests.CompileErrorContext) void {3pub fn addCases(cases: *tests.CompileErrorContext) void {
4 cases.add(
5 "@bitCast same size but bit count mismatch",
6 \\export fn entry(byte: u8) void {
7 \\ var oops = @bitCast(u7, byte);
8 \\}
9 ,
10 ".tmp_source.zig:2:16: error: destination type 'u7' has 7 bits but source type 'u8' has 8 bits",
11 );
12
4 cases.add(13 cases.add(
5 "attempted `&&`",14 "attempted `&&`",
6 \\export fn entry(a: bool, b: bool) i32 {15 \\export fn entry(a: bool, b: bool) i32 {