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...@@ -8288,6 +8288,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
82888288
8289 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);8289 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
8290 const operand = try sema.resolveInst(extra.rhs);8290 const operand = try sema.resolveInst(extra.rhs);
8291 const operand_ty = sema.typeOf(operand);
8291 switch (dest_ty.zigTypeTag()) {8292 switch (dest_ty.zigTypeTag()) {
8292 .AnyFrame,8293 .AnyFrame,
8293 .ComptimeFloat,8294 .ComptimeFloat,
...@@ -8310,8 +8311,8 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -8310,8 +8311,8 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
8310 const msg = msg: {8311 const msg = msg: {
8311 const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)});8312 const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)});
8312 errdefer msg.destroy(sema.gpa);8313 errdefer msg.destroy(sema.gpa);
8313 switch (sema.typeOf(operand).zigTypeTag()) {8314 switch (operand_ty.zigTypeTag()) {
8314 .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToEnum for type coercion", .{}),8315 .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToEnum to cast from '{}'", .{operand_ty.fmt(sema.mod)}),
8315 else => {},8316 else => {},
8316 }8317 }
83178318
...@@ -8320,9 +8321,20 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -8320,9 +8321,20 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
8320 return sema.failWithOwnedErrorMsg(block, msg);8321 return sema.failWithOwnedErrorMsg(block, msg);
8321 },8322 },
83228323
8323 .Pointer => return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}', use @ptrCast to cast to a pointer", .{8324 .Pointer => {
8324 dest_ty.fmt(sema.mod),8325 const msg = msg: {
8325 }),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 },
8326 .Struct, .Union => if (dest_ty.containerLayout() == .Auto) {8338 .Struct, .Union => if (dest_ty.containerLayout() == .Auto) {
8327 const container = switch (dest_ty.zigTypeTag()) {8339 const container = switch (dest_ty.zigTypeTag()) {
8328 .Struct => "struct",8340 .Struct => "struct",
...@@ -8342,6 +8354,70 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -8342,6 +8354,70 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
8342 .Vector,8354 .Vector,
8343 => {},8355 => {},
8344 }8356 }
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 }
8345 return sema.bitCast(block, dest_ty, operand, operand_src);8421 return sema.bitCast(block, dest_ty, operand, operand_src);
8346}8422}
83478423
test/behavior/bitcast.zig-16
...@@ -90,22 +90,6 @@ test "nested bitcast" {...@@ -90,22 +90,6 @@ test "nested bitcast" {
90 comptime try S.foo(42);90 comptime try S.foo(42);
91}91}
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
109// issue #3010: compiler segfault93// issue #3010: compiler segfault
110test "bitcast literal [4]u8 param to u32" {94test "bitcast literal [4]u8 param to u32" {
111 const ip = @bitCast(u32, [_]u8{ 255, 255, 255, 255 });95 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 {...@@ -9,4 +9,4 @@ export fn entry() void {
9// target=native9// target=native
10//10//
11// :3:24: error: cannot @bitCast to 'tmp.entry.E'11// :3:24: error: cannot @bitCast to 'tmp.entry.E'
12// :3:24: note: use @intToEnum for type coercion12// :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