authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-28 15:00:40+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-01 23:37:01+03:00
log57f9405a8fcaec6043d680fa47ae0e98709160c2
tree40614ac1850186954c45c91f169d60a4df2bdb2b
parente7b6a1833106a5d808e4e82a2d61abf417aff407

Sema: validate bitcast operand type


7 files changed, 111 insertions(+), 49 deletions(-)

src/Sema.zig+81-5
......@@ -8288,6 +8288,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
82888288
82898289 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
82908290 const operand = try sema.resolveInst(extra.rhs);
8291 const operand_ty = sema.typeOf(operand);
82918292 switch (dest_ty.zigTypeTag()) {
82928293 .AnyFrame,
82938294 .ComptimeFloat,
......@@ -8310,8 +8311,8 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
83108311 const msg = msg: {
83118312 const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)});
83128313 errdefer msg.destroy(sema.gpa);
8313 switch (sema.typeOf(operand).zigTypeTag()) {
8314 .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToEnum for type coercion", .{}),
8314 switch (operand_ty.zigTypeTag()) {
8315 .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToEnum to cast from '{}'", .{operand_ty.fmt(sema.mod)}),
83158316 else => {},
83168317 }
83178318
......@@ -8320,9 +8321,20 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
83208321 return sema.failWithOwnedErrorMsg(block, msg);
83218322 },
83228323
8323 .Pointer => return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}', use @ptrCast to cast to a pointer", .{
8324 dest_ty.fmt(sema.mod),
8325 }),
8324 .Pointer => {
8325 const msg = msg: {
8326 const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)});
8327 errdefer msg.destroy(sema.gpa);
8328 switch (operand_ty.zigTypeTag()) {
8329 .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToPtr to cast from '{}'", .{operand_ty.fmt(sema.mod)}),
8330 .Pointer => try sema.errNote(block, dest_ty_src, msg, "use @ptrCast to cast from '{}'", .{operand_ty.fmt(sema.mod)}),
8331 else => {},
8332 }
8333
8334 break :msg msg;
8335 };
8336 return sema.failWithOwnedErrorMsg(block, msg);
8337 },
83268338 .Struct, .Union => if (dest_ty.containerLayout() == .Auto) {
83278339 const container = switch (dest_ty.zigTypeTag()) {
83288340 .Struct => "struct",
......@@ -8342,6 +8354,70 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
83428354 .Vector,
83438355 => {},
83448356 }
8357 switch (operand_ty.zigTypeTag()) {
8358 .AnyFrame,
8359 .ComptimeFloat,
8360 .ComptimeInt,
8361 .EnumLiteral,
8362 .ErrorSet,
8363 .ErrorUnion,
8364 .Fn,
8365 .Frame,
8366 .NoReturn,
8367 .Null,
8368 .Opaque,
8369 .Optional,
8370 .Type,
8371 .Undefined,
8372 .Void,
8373 => return sema.fail(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)}),
8374
8375 .Enum => {
8376 const msg = msg: {
8377 const msg = try sema.errMsg(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)});
8378 errdefer msg.destroy(sema.gpa);
8379 switch (dest_ty.zigTypeTag()) {
8380 .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @enumToInt to cast to '{}'", .{dest_ty.fmt(sema.mod)}),
8381 else => {},
8382 }
8383
8384 break :msg msg;
8385 };
8386 return sema.failWithOwnedErrorMsg(block, msg);
8387 },
8388 .Pointer => {
8389 const msg = msg: {
8390 const msg = try sema.errMsg(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)});
8391 errdefer msg.destroy(sema.gpa);
8392 switch (dest_ty.zigTypeTag()) {
8393 .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @ptrToInt to cast to '{}'", .{dest_ty.fmt(sema.mod)}),
8394 .Pointer => try sema.errNote(block, operand_src, msg, "use @ptrCast to cast to '{}'", .{dest_ty.fmt(sema.mod)}),
8395 else => {},
8396 }
8397
8398 break :msg msg;
8399 };
8400 return sema.failWithOwnedErrorMsg(block, msg);
8401 },
8402 .Struct, .Union => if (operand_ty.containerLayout() == .Auto) {
8403 const container = switch (operand_ty.zigTypeTag()) {
8404 .Struct => "struct",
8405 .Union => "union",
8406 else => unreachable,
8407 };
8408 return sema.fail(block, operand_src, "cannot @bitCast from '{}', {s} does not have a guaranteed in-memory layout", .{
8409 operand_ty.fmt(sema.mod), container,
8410 });
8411 },
8412 .BoundFn => @panic("TODO remove this type from the language and compiler"),
8413
8414 .Array,
8415 .Bool,
8416 .Float,
8417 .Int,
8418 .Vector,
8419 => {},
8420 }
83458421 return sema.bitCast(block, dest_ty, operand, operand_src);
83468422}
83478423
test/behavior/bitcast.zig-16
......@@ -90,22 +90,6 @@ test "nested bitcast" {
9090 comptime try S.foo(42);
9191}
9292
93test "@bitCast enum to its integer type" {
94 const SOCK = enum(c_int) {
95 A,
96 B,
97
98 fn testBitCastExternEnum() !void {
99 var SOCK_DGRAM = @This().B;
100 var sock_dgram = @bitCast(c_int, SOCK_DGRAM);
101 try expect(sock_dgram == 1);
102 }
103 };
104
105 try SOCK.testBitCastExternEnum();
106 comptime try SOCK.testBitCastExternEnum();
107}
108
10993// issue #3010: compiler segfault
11094test "bitcast literal [4]u8 param to u32" {
11195 const ip = @bitCast(u32, [_]u8{ 255, 255, 255, 255 });
test/cases/compile_errors/bitCast_to_enum_type.zig+1-1
......@@ -9,4 +9,4 @@ export fn entry() void {
99// target=native
1010//
1111// :3:24: error: cannot @bitCast to 'tmp.entry.E'
12// :3:24: note: use @intToEnum for type coercion
12// :3:24: note: use @intToEnum to cast from 'u32'
test/cases/compile_errors/intToPtr_with_misaligned_address.zig created+10
......@@ -0,0 +1,10 @@
1pub export fn entry() void {
2 var y = @intToPtr([*]align(4) u8, 5);
3 _ = y;
4}
5
6// error
7// backend=stage2
8// target=native
9//
10// :2:39: error: pointer type '[*]align(4) u8' requires aligned address
test/cases/compile_errors/issue_3818_bitcast_from_parray-slice_to_u16.zig created+19
......@@ -0,0 +1,19 @@
1export fn foo1() void {
2 var bytes = [_]u8{1, 2};
3 const word: u16 = @bitCast(u16, bytes[0..]);
4 _ = word;
5}
6export fn foo2() void {
7 var bytes: []const u8 = &[_]u8{1, 2};
8 const word: u16 = @bitCast(u16, bytes);
9 _ = word;
10}
11
12// error
13// backend=stage2
14// target=native
15//
16// :3:42: error: cannot @bitCast from '*[2]u8'
17// :3:42: note: use @ptrToInt to cast to 'u16'
18// :8:37: error: cannot @bitCast from '[]const u8'
19// :8:37: note: use @ptrToInt to cast to 'u16'
test/cases/compile_errors/stage1/obj/intToPtr_with_misaligned_address.zig deleted-10
......@@ -1,10 +0,0 @@
1pub fn main() void {
2 var y = @intToPtr([*]align(4) u8, 5);
3 _ = y;
4}
5
6// error
7// backend=stage1
8// target=native
9//
10// tmp.zig:2:13: error: pointer type '[*]align(4) u8' requires aligned address
test/cases/compile_errors/stage1/obj/issue_3818_bitcast_from_parray-slice_to_u16.zig deleted-17
......@@ -1,17 +0,0 @@
1export fn foo1() void {
2 var bytes = [_]u8{1, 2};
3 const word: u16 = @bitCast(u16, bytes[0..]);
4 _ = word;
5}
6export fn foo2() void {
7 var bytes: []const u8 = &[_]u8{1, 2};
8 const word: u16 = @bitCast(u16, bytes);
9 _ = word;
10}
11
12// error
13// backend=stage1
14// target=native
15//
16// tmp.zig:3:42: error: unable to @bitCast from pointer type '*[2]u8'
17// tmp.zig:8:32: error: destination type 'u16' has size 2 but source type '[]const u8' has size 16