commit f9a2c0fc6c51be929640fbff39809bd1371eedc2 (tree)
parent 3beef3945c87c589feebf50ed985bb6e65887110
Author: Veikka Tuominen <git@vexu.eu>
Date: Sun, 27 Mar 2022 11:31:30 +0300
Merge pull request #10871 from schmee/stage2-bitcast-safety
stage2: add type checking for @bitCast
Diffstat:
2 files changed, 69 insertions(+), 2 deletions(-)
diff --git a/src/Sema.zig b/src/Sema.zig
@@ -6800,8 +6800,51 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
+ const target = sema.mod.getTarget();
const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
+ switch (dest_ty.zigTypeTag()) {
+ .AnyFrame,
+ .ComptimeFloat,
+ .ComptimeInt,
+ .Enum,
+ .EnumLiteral,
+ .ErrorSet,
+ .ErrorUnion,
+ .Fn,
+ .Frame,
+ .NoReturn,
+ .Null,
+ .Opaque,
+ .Optional,
+ .Type,
+ .Undefined,
+ .Void,
+ => return sema.fail(block, dest_ty_src, "invalid type '{}' for @bitCast", .{dest_ty.fmt(target)}),
+
+ .Pointer => return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}', use @ptrCast to cast to a pointer", .{
+ dest_ty.fmt(target),
+ }),
+ .Struct, .Union => if (dest_ty.containerLayout() == .Auto) {
+ const container = switch (dest_ty.zigTypeTag()) {
+ .Struct => "struct",
+ .Union => "union",
+ else => unreachable,
+ };
+ return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}', {s} does not have a guaranteed in-memory layout", .{
+ dest_ty.fmt(target), container,
+ });
+ },
+ .BoundFn => @panic("TODO remove this type from the language and compiler"),
+
+ .Array,
+ .Bool,
+ .Float,
+ .Int,
+ .Vector,
+ => {},
+ }
+
const operand = sema.resolveInst(extra.rhs);
return sema.bitCast(block, dest_ty, operand, operand_src);
}
@@ -19137,7 +19180,19 @@ fn bitCast(
const old_ty = try sema.resolveTypeFields(block, inst_src, sema.typeOf(inst));
try sema.resolveTypeLayout(block, inst_src, old_ty);
- // TODO validate the type size and other compile errors
+ const target = sema.mod.getTarget();
+ var dest_bits = dest_ty.bitSize(target);
+ var old_bits = old_ty.bitSize(target);
+
+ if (old_bits != dest_bits) {
+ return sema.fail(block, inst_src, "@bitCast size mismatch: destination type '{}' has {d} bits but source type '{}' has {d} bits", .{
+ dest_ty.fmt(target),
+ dest_bits,
+ old_ty.fmt(target),
+ old_bits,
+ });
+ }
+
if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
const result_val = try sema.bitCastVal(block, inst_src, val, old_ty, dest_ty, 0);
return sema.addConstant(dest_ty, result_val);
diff --git a/src/type.zig b/src/type.zig
@@ -3274,8 +3274,20 @@ pub const Type = extern union {
const int_tag_ty = ty.intTagType(&buffer);
return int_tag_ty.bitSize(target);
},
+
.@"union", .union_tagged => {
- @panic("TODO bitSize unions");
+ const union_obj = ty.cast(Payload.Union).?.data;
+
+ const fields = union_obj.fields;
+ if (fields.count() == 0) return 0;
+
+ assert(union_obj.haveFieldTypes());
+
+ var size: u64 = 0;
+ for (fields.values()) |field| {
+ size = @maximum(size, field.ty.bitSize(target));
+ }
+ return size;
},
.vector => {