authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-03-27 11:31:30+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-27 11:31:30+03:00
logf9a2c0fc6c51be929640fbff39809bd1371eedc2
treeb197d1128ac7fe830c7ee65715a830c200cef23b
parent3beef3945c87c589feebf50ed985bb6e65887110
parent607300a59bfa24fae19b85029065c4a3cc136692
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10871 from schmee/stage2-bitcast-safety

stage2: add type checking for @bitCast

2 files changed, 69 insertions(+), 2 deletions(-)

src/Sema.zig+56-1
...@@ -6800,8 +6800,51 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -6800,8 +6800,51 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
6800 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };6800 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
6801 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };6801 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
6802 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;6802 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
6803 const target = sema.mod.getTarget();
68036804
6804 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);6805 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
6806 switch (dest_ty.zigTypeTag()) {
6807 .AnyFrame,
6808 .ComptimeFloat,
6809 .ComptimeInt,
6810 .Enum,
6811 .EnumLiteral,
6812 .ErrorSet,
6813 .ErrorUnion,
6814 .Fn,
6815 .Frame,
6816 .NoReturn,
6817 .Null,
6818 .Opaque,
6819 .Optional,
6820 .Type,
6821 .Undefined,
6822 .Void,
6823 => return sema.fail(block, dest_ty_src, "invalid type '{}' for @bitCast", .{dest_ty.fmt(target)}),
6824
6825 .Pointer => return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}', use @ptrCast to cast to a pointer", .{
6826 dest_ty.fmt(target),
6827 }),
6828 .Struct, .Union => if (dest_ty.containerLayout() == .Auto) {
6829 const container = switch (dest_ty.zigTypeTag()) {
6830 .Struct => "struct",
6831 .Union => "union",
6832 else => unreachable,
6833 };
6834 return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}', {s} does not have a guaranteed in-memory layout", .{
6835 dest_ty.fmt(target), container,
6836 });
6837 },
6838 .BoundFn => @panic("TODO remove this type from the language and compiler"),
6839
6840 .Array,
6841 .Bool,
6842 .Float,
6843 .Int,
6844 .Vector,
6845 => {},
6846 }
6847
6805 const operand = sema.resolveInst(extra.rhs);6848 const operand = sema.resolveInst(extra.rhs);
6806 return sema.bitCast(block, dest_ty, operand, operand_src);6849 return sema.bitCast(block, dest_ty, operand, operand_src);
6807}6850}
...@@ -19137,7 +19180,19 @@ fn bitCast(...@@ -19137,7 +19180,19 @@ fn bitCast(
19137 const old_ty = try sema.resolveTypeFields(block, inst_src, sema.typeOf(inst));19180 const old_ty = try sema.resolveTypeFields(block, inst_src, sema.typeOf(inst));
19138 try sema.resolveTypeLayout(block, inst_src, old_ty);19181 try sema.resolveTypeLayout(block, inst_src, old_ty);
1913919182
19140 // TODO validate the type size and other compile errors19183 const target = sema.mod.getTarget();
19184 var dest_bits = dest_ty.bitSize(target);
19185 var old_bits = old_ty.bitSize(target);
19186
19187 if (old_bits != dest_bits) {
19188 return sema.fail(block, inst_src, "@bitCast size mismatch: destination type '{}' has {d} bits but source type '{}' has {d} bits", .{
19189 dest_ty.fmt(target),
19190 dest_bits,
19191 old_ty.fmt(target),
19192 old_bits,
19193 });
19194 }
19195
19141 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {19196 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
19142 const result_val = try sema.bitCastVal(block, inst_src, val, old_ty, dest_ty, 0);19197 const result_val = try sema.bitCastVal(block, inst_src, val, old_ty, dest_ty, 0);
19143 return sema.addConstant(dest_ty, result_val);19198 return sema.addConstant(dest_ty, result_val);
src/type.zig+13-1
...@@ -3274,8 +3274,20 @@ pub const Type = extern union {...@@ -3274,8 +3274,20 @@ pub const Type = extern union {
3274 const int_tag_ty = ty.intTagType(&buffer);3274 const int_tag_ty = ty.intTagType(&buffer);
3275 return int_tag_ty.bitSize(target);3275 return int_tag_ty.bitSize(target);
3276 },3276 },
3277
3277 .@"union", .union_tagged => {3278 .@"union", .union_tagged => {
3278 @panic("TODO bitSize unions");3279 const union_obj = ty.cast(Payload.Union).?.data;
3280
3281 const fields = union_obj.fields;
3282 if (fields.count() == 0) return 0;
3283
3284 assert(union_obj.haveFieldTypes());
3285
3286 var size: u64 = 0;
3287 for (fields.values()) |field| {
3288 size = @maximum(size, field.ty.bitSize(target));
3289 }
3290 return size;
3279 },3291 },
32803292
3281 .vector => {3293 .vector => {