From 773b1c4c5cdf9fde19cbf09d0f81f1bfe27ed7ca Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Mon, 20 Mar 2023 18:05:52 +0200 Subject: llvm: fix lowering packed union initiated to zero-bit value Closes #14980 --- test/behavior/union.zig | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'test') diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 9b49f8bf47..ff3f0b7e54 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1493,3 +1493,23 @@ test "union reassignment can use previous value" { a = U{ .b = a.a }; try expect(a.b == 32); } + +test "packed union with zero-bit field" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + + const S = packed struct { + nested: packed union { + zero: void, + sized: u32, + }, + bar: u32, + + fn doTest(self: @This()) !void { + try expect(self.bar == 42); + } + }; + try S.doTest(.{ .nested = .{ .zero = {} }, .bar = 42 }); +} -- cgit v1.2.3 From 9d9815fb9c21c91df41422ff582402fb56029328 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Mon, 20 Mar 2023 18:30:33 +0200 Subject: Value: handle comparisons of runtime_values Closes #15004 --- src/value.zig | 10 ++++++++++ test/behavior/src.zig | 11 +++++++++++ 2 files changed, 21 insertions(+) (limited to 'test') diff --git a/src/value.zig b/src/value.zig index e5283d1270..1b6d2adc1e 100644 --- a/src/value.zig +++ b/src/value.zig @@ -1113,6 +1113,10 @@ pub const Value = extern union { .bool_true, => return BigIntMutable.init(&space.limbs, 1).toConst(), + .runtime_value => { + const sub_val = val.castTag(.runtime_value).?.data; + return sub_val.toBigIntAdvanced(space, target, opt_sema); + }, .int_u64 => return BigIntMutable.init(&space.limbs, val.castTag(.int_u64).?.data).toConst(), .int_i64 => return BigIntMutable.init(&space.limbs, val.castTag(.int_i64).?.data).toConst(), .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt(), @@ -1979,6 +1983,12 @@ pub const Value = extern union { .variable, => .gt, + .runtime_value => { + // This is needed to correctly handle hashing the value. + // Checks in Sema should prevent direct comparisons from reaching here. + const val = lhs.castTag(.runtime_value).?.data; + return val.orderAgainstZeroAdvanced(opt_sema); + }, .int_u64 => std.math.order(lhs.castTag(.int_u64).?.data, 0), .int_i64 => std.math.order(lhs.castTag(.int_i64).?.data, 0), .int_big_positive => lhs.castTag(.int_big_positive).?.asBigInt().orderAgainstScalar(0), diff --git a/test/behavior/src.zig b/test/behavior/src.zig index 77e420afcf..e6b84e5d56 100644 --- a/test/behavior/src.zig +++ b/test/behavior/src.zig @@ -32,3 +32,14 @@ test "@src used as a comptime parameter" { const T2 = S.Foo(@src()); try expect(T1 != T2); } + +test "@src in tuple passed to anytype function" { + const S = struct { + fn Foo(a: anytype) u32 { + return a[0].line; + } + }; + const l1 = S.Foo(.{@src()}); + const l2 = S.Foo(.{@src()}); + try expect(l1 != l2); +} -- cgit v1.2.3 From 82133cd992575ab567091eaf2f12fbe5e326b5df Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Tue, 21 Mar 2023 00:09:00 +0200 Subject: Sema: improve error message of field access of wrapped type Closes #15027 --- src/Sema.zig | 48 +++++++++++++++++++++- .../field_access_of_wrapped_type.zig | 20 +++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 test/cases/compile_errors/field_access_of_wrapped_type.zig (limited to 'test') diff --git a/src/Sema.zig b/src/Sema.zig index 0afce47e76..6d6a9a13e8 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2127,6 +2127,50 @@ fn failWithUseOfAsync(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError return sema.failWithOwnedErrorMsg(msg); } +fn failWithInvalidFieldAccess(sema: *Sema, block: *Block, src: LazySrcLoc, object_ty: Type, field_name: []const u8) CompileError { + const inner_ty = if (object_ty.isSinglePointer()) object_ty.childType() else object_ty; + + if (inner_ty.zigTypeTag() == .Optional) opt: { + var buf: Type.Payload.ElemType = undefined; + const child_ty = inner_ty.optionalChild(&buf); + if (!typeSupportsFieldAccess(child_ty, field_name)) break :opt; + const msg = msg: { + const msg = try sema.errMsg(block, src, "optional type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); + errdefer msg.destroy(sema.gpa); + try sema.errNote(block, src, msg, "consider using '.?', 'orelse', or 'if'", .{}); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(msg); + } else if (inner_ty.zigTypeTag() == .ErrorUnion) err: { + const child_ty = inner_ty.errorUnionPayload(); + if (!typeSupportsFieldAccess(child_ty, field_name)) break :err; + const msg = msg: { + const msg = try sema.errMsg(block, src, "error union type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); + errdefer msg.destroy(sema.gpa); + try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{}); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(msg); + } + return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); +} + +fn typeSupportsFieldAccess(ty: Type, field_name: []const u8) bool { + switch (ty.zigTypeTag()) { + .Array => return mem.eql(u8, field_name, "len"), + .Pointer => { + const ptr_info = ty.ptrInfo().data; + if (ptr_info.size == .Slice) { + return mem.eql(u8, field_name, "ptr") or mem.eql(u8, field_name, "len"); + } else if (ptr_info.pointee_type.zigTypeTag() == .Array) { + return mem.eql(u8, field_name, "len"); + } else return false; + }, + .Type, .Struct, .Union => return true, + else => return false, + } +} + /// We don't return a pointer to the new error note because the pointer /// becomes invalid when you add another one. fn errNote( @@ -23321,7 +23365,7 @@ fn fieldVal( }, else => {}, } - return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); + return sema.failWithInvalidFieldAccess(block, src, object_ty, field_name); } fn fieldPtr( @@ -23535,7 +23579,7 @@ fn fieldPtr( }, else => {}, } - return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); + return sema.failWithInvalidFieldAccess(block, src, object_ty, field_name); } fn fieldCallBind( diff --git a/test/cases/compile_errors/field_access_of_wrapped_type.zig b/test/cases/compile_errors/field_access_of_wrapped_type.zig new file mode 100644 index 0000000000..9d8a7ef17c --- /dev/null +++ b/test/cases/compile_errors/field_access_of_wrapped_type.zig @@ -0,0 +1,20 @@ +const Foo = struct { + a: i32, +}; +export fn f1() void { + var foo: ?Foo = undefined; + foo.a += 1; +} +export fn f2() void { + var foo: anyerror!Foo = undefined; + foo.a += 1; +} + +// error +// backend=stage2 +// target=native +// +// :6:8: error: optional type '?tmp.Foo' does not support field access +// :6:8: note: consider using '.?', 'orelse', or 'if' +// :10:8: error: error union type 'anyerror!tmp.Foo' does not support field access +// :10:8: note: consider using 'try', 'catch', or 'if' -- cgit v1.2.3 From e70a0b2a6b329a76e9edc4d22c7b923841703a24 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Tue, 21 Mar 2023 00:27:33 +0200 Subject: Value: implement reinterpreting enum field index as integer Closes #15019 --- src/value.zig | 5 +++++ test/behavior/union.zig | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'test') diff --git a/src/value.zig b/src/value.zig index 1b6d2adc1e..e677414c0f 100644 --- a/src/value.zig +++ b/src/value.zig @@ -1113,6 +1113,10 @@ pub const Value = extern union { .bool_true, => return BigIntMutable.init(&space.limbs, 1).toConst(), + .enum_field_index => { + const index = val.castTag(.enum_field_index).?.data; + return BigIntMutable.init(&space.limbs, index).toConst(); + }, .runtime_value => { const sub_val = val.castTag(.runtime_value).?.data; return sub_val.toBigIntAdvanced(space, target, opt_sema); @@ -1983,6 +1987,7 @@ pub const Value = extern union { .variable, => .gt, + .enum_field_index => return std.math.order(lhs.castTag(.enum_field_index).?.data, 0), .runtime_value => { // This is needed to correctly handle hashing the value. // Checks in Sema should prevent direct comparisons from reaching here. diff --git a/test/behavior/union.zig b/test/behavior/union.zig index ff3f0b7e54..010b4a1ffa 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1513,3 +1513,23 @@ test "packed union with zero-bit field" { }; try S.doTest(.{ .nested = .{ .zero = {} }, .bar = 42 }); } + +test "reinterpreting enum value inside packed union" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + + const U = packed union { + tag: enum { a, b }, + val: u8, + + fn doTest() !void { + var u: @This() = .{ .tag = .a }; + u.val += 1; + try expect(u.tag == .b); + } + }; + try U.doTest(); + comptime try U.doTest(); +} -- cgit v1.2.3