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
signature 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
68006800 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
68016801 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
68026802 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
6803 const target = sema.mod.getTarget();
68036804
68046805 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
68056848 const operand = sema.resolveInst(extra.rhs);
68066849 return sema.bitCast(block, dest_ty, operand, operand_src);
68076850}
......@@ -19137,7 +19180,19 @@ fn bitCast(
1913719180 const old_ty = try sema.resolveTypeFields(block, inst_src, sema.typeOf(inst));
1913819181 try sema.resolveTypeLayout(block, inst_src, old_ty);
1913919182
19140 // TODO validate the type size and other compile errors
19183 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
1914119196 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
1914219197 const result_val = try sema.bitCastVal(block, inst_src, val, old_ty, dest_ty, 0);
1914319198 return sema.addConstant(dest_ty, result_val);
src/type.zig+13-1
......@@ -3274,8 +3274,20 @@ pub const Type = extern union {
32743274 const int_tag_ty = ty.intTagType(&buffer);
32753275 return int_tag_ty.bitSize(target);
32763276 },
3277
32773278 .@"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;
32793291 },
32803292
32813293 .vector => {