From a7b3082ba0d07c66d2ec19304ffe993d77f714b7 Mon Sep 17 00:00:00 2001 From: John Schmidt Date: Sat, 12 Feb 2022 16:57:52 +0100 Subject: [PATCH 1/3] Implement `type.bitSize` for unions --- src/type.zig | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/type.zig b/src/type.zig index d5b8e6f5b3..6b7214888d 100644 --- a/src/type.zig +++ b/src/type.zig @@ -3251,8 +3251,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 => { From dc5dc3ac59bb0f013a867b278b994b76df655480 Mon Sep 17 00:00:00 2001 From: John Schmidt Date: Sat, 12 Feb 2022 16:57:58 +0100 Subject: [PATCH 2/3] stage2: add type checking for @bitCast --- src/Sema.zig | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/src/Sema.zig b/src/Sema.zig index a42a4caf38..63d7eca23b 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -6765,8 +6765,71 @@ 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()) { + .Type, + .Void, + .NoReturn, + .ComptimeFloat, + .ComptimeInt, + .Undefined, + .Null, + .Optional, + .ErrorUnion, + .ErrorSet, + .Opaque, + .Frame, + .AnyFrame, + .EnumLiteral, + .Union, + .Fn, + => return sema.fail(block, dest_ty_src, "invalid type '{}' for @bitCast", .{dest_ty.fmt(target)}), + + .Pointer => { + const msg = msg: { + const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to pointer type '{}'", .{dest_ty.fmt(target)}); + errdefer msg.destroy(sema.gpa); + + const pointee_ty = dest_ty.ptrInfo().data.pointee_type; + try sema.errNote(block, dest_ty_src, msg, "to cast to a pointer type, use @ptrCast({}, ...)", .{dest_ty.fmt(target)}); + try sema.errNote(block, dest_ty_src, msg, "to cast to a non-pointer type, use @bitCast({}, ...)", .{pointee_ty.fmt(target)}); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(block, msg); + }, + .Struct => { + if (dest_ty.containerLayout() == .Auto) { + const msg = msg: { + const msg = try sema.errMsg( + block, + dest_ty_src, + "cannot @bitCast to '{}', struct does not have a specified layout", + .{dest_ty.fmt(target)}, + ); + errdefer msg.destroy(sema.gpa); + + const ty_decl_src = dest_ty.declSrcLoc(); + try sema.mod.errNoteNonLazy( + ty_decl_src, + msg, + "consider using 'packed struct' or 'extern struct' for a specified layout.", + .{}, + ); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(block, msg); + } + }, + .BoundFn => @panic("TODO remove this type from the language and compiler"), + else => {}, + } + + // When bitcasting we compare the bit size of the types, so we need to + // fully resolve all composite types to finalize the layout. + try sema.resolveTypeFully(block, dest_ty_src, dest_ty); + const operand = sema.resolveInst(extra.rhs); return sema.bitCast(block, dest_ty, operand, operand_src); } @@ -18995,7 +19058,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); From 607300a59bfa24fae19b85029065c4a3cc136692 Mon Sep 17 00:00:00 2001 From: John Schmidt Date: Sat, 26 Mar 2022 00:57:17 +0100 Subject: [PATCH 3/3] sema: simplify @bitCast error messages --- src/Sema.zig | 80 ++++++++++++++++++++-------------------------------- 1 file changed, 30 insertions(+), 50 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 63d7eca23b..a566a2b56c 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -6769,66 +6769,46 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); switch (dest_ty.zigTypeTag()) { - .Type, - .Void, - .NoReturn, + .AnyFrame, .ComptimeFloat, .ComptimeInt, - .Undefined, - .Null, - .Optional, - .ErrorUnion, - .ErrorSet, - .Opaque, - .Frame, - .AnyFrame, + .Enum, .EnumLiteral, - .Union, + .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 => { - const msg = msg: { - const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to pointer type '{}'", .{dest_ty.fmt(target)}); - errdefer msg.destroy(sema.gpa); - - const pointee_ty = dest_ty.ptrInfo().data.pointee_type; - try sema.errNote(block, dest_ty_src, msg, "to cast to a pointer type, use @ptrCast({}, ...)", .{dest_ty.fmt(target)}); - try sema.errNote(block, dest_ty_src, msg, "to cast to a non-pointer type, use @bitCast({}, ...)", .{pointee_ty.fmt(target)}); - break :msg msg; + .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.failWithOwnedErrorMsg(block, msg); - }, - .Struct => { - if (dest_ty.containerLayout() == .Auto) { - const msg = msg: { - const msg = try sema.errMsg( - block, - dest_ty_src, - "cannot @bitCast to '{}', struct does not have a specified layout", - .{dest_ty.fmt(target)}, - ); - errdefer msg.destroy(sema.gpa); - - const ty_decl_src = dest_ty.declSrcLoc(); - try sema.mod.errNoteNonLazy( - ty_decl_src, - msg, - "consider using 'packed struct' or 'extern struct' for a specified layout.", - .{}, - ); - break :msg msg; - }; - return sema.failWithOwnedErrorMsg(block, msg); - } + 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"), - else => {}, - } - // When bitcasting we compare the bit size of the types, so we need to - // fully resolve all composite types to finalize the layout. - try sema.resolveTypeFully(block, dest_ty_src, dest_ty); + .Array, + .Bool, + .Float, + .Int, + .Vector, + => {}, + } const operand = sema.resolveInst(extra.rhs); return sema.bitCast(block, dest_ty, operand, operand_src);