authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-06-26 23:35:11+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-06-26 23:35:11+02:00
log05cb944709d2a05a944e60f032638cae5ee01fb0
tree6951331c63eec3a29f0961ee8d5e528a43b2328c
parentb636906fb640a12107cd21637c2af67b8e9d6ebd
parentf2d13f6d074139c01184e170fe24127a2d9db944

Merge pull request 'Sema: more fixes' (#35707) from sinon/zig:more-fixes into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/35707 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

6 files changed, 90 insertions(+), 54 deletions(-)

src/Sema.zig+15-32
...@@ -9314,7 +9314,7 @@ fn intCast(...@@ -9314,7 +9314,7 @@ fn intCast(
9314 break :ok all_in_range;9314 break :ok all_in_range;
9315 } else ok: {9315 } else ok: {
9316 const zero_inst = Air.internedToRef((try pt.intValue(operand_ty, 0)).toIntern());9316 const zero_inst = Air.internedToRef((try pt.intValue(operand_ty, 0)).toIntern());
9317 const is_in_range = try block.addBinOp(.cmp_lte, operand, zero_inst);9317 const is_in_range = try block.addBinOp(.cmp_eq, operand, zero_inst);
9318 break :ok is_in_range;9318 break :ok is_in_range;
9319 };9319 };
9320 try sema.addSafetyCheck(block, src, ok, .integer_out_of_bounds);9320 try sema.addSafetyCheck(block, src, ok, .integer_out_of_bounds);
...@@ -12012,15 +12012,12 @@ fn resolveSwitchPayloadCaptureTaggedUnion(...@@ -12012,15 +12012,12 @@ fn resolveSwitchPayloadCaptureTaggedUnion(
12012 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);12012 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
12013 const payload_ref: Air.Inst.Ref = payload_ref: {12013 const payload_ref: Air.Inst.Ref = payload_ref: {
12014 if (capture_by_ref) {12014 if (capture_by_ref) {
12015 const operand_ptr_info = sema.typeOf(loaded_operand).ptrInfo(zcu);12015 const ptr_field_ty = try sema.typeOf(loaded_operand).fieldPtrType(field_index, pt);
12016 const ptr_field_ty = try pt.ptrType(.{12016 if (try sema.resolveDefinedValue(case_block, operand_src, loaded_operand)) |op_ptr_val| {
12017 .child = field_ty.toIntern(),12017 if (op_ptr_val.isUndef(zcu)) break :payload_ref try pt.undefRef(ptr_field_ty);
12018 .flags = .{12018 const field_ptr_val = try op_ptr_val.ptrField(field_index, pt);
12019 .is_const = operand_ptr_info.flags.is_const,12019 break :payload_ref .fromValue(try pt.getCoerced(field_ptr_val, ptr_field_ty));
12020 .is_volatile = operand_ptr_info.flags.is_volatile,12020 }
12021 .address_space = operand_ptr_info.flags.address_space,
12022 },
12023 });
12024 break :payload_ref try case_block.addStructFieldPtr(loaded_operand, field_index, ptr_field_ty);12021 break :payload_ref try case_block.addStructFieldPtr(loaded_operand, field_index, ptr_field_ty);
12025 }12022 }
12026 if (try sema.resolveDefinedValue(case_block, operand_src, loaded_operand)) |union_val| {12023 if (try sema.resolveDefinedValue(case_block, operand_src, loaded_operand)) |union_val| {
...@@ -17548,15 +17545,10 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr...@@ -17548,15 +17545,10 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr
17548 const is_cold = sema.branch_hint == .cold;17545 const is_cold = sema.branch_hint == .cold;
1754917546
17550 const operand_ty = sema.typeOf(operand);17547 const operand_ty = sema.typeOf(operand);
17551 const ptr_info = operand_ty.ptrInfo(zcu);17548 const res_ty = try pt.ptrType(info: {
17552 const res_ty = try pt.ptrType(.{17549 var new = operand_ty.ptrInfo(zcu);
17553 .child = err_union_ty.errorUnionPayload(zcu).toIntern(),17550 new.child = err_union_ty.errorUnionPayload(zcu).toIntern();
17554 .flags = .{17551 break :info new;
17555 .is_const = ptr_info.flags.is_const,
17556 .is_volatile = ptr_info.flags.is_volatile,
17557 .is_allowzero = ptr_info.flags.is_allowzero,
17558 .address_space = ptr_info.flags.address_space,
17559 },
17560 });17552 });
17561 const res_ty_ref = Air.internedToRef(res_ty.toIntern());17553 const res_ty_ref = Air.internedToRef(res_ty.toIntern());
17562 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.TryPtr).@"struct".field_names.len +17554 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.TryPtr).@"struct".field_names.len +
...@@ -26404,23 +26396,21 @@ fn fieldCallBind(...@@ -26404,23 +26396,21 @@ fn fieldCallBind(
26404 .@"struct" => {26396 .@"struct" => {
26405 if (zcu.typeToStruct(concrete_ty)) |struct_type| {26397 if (zcu.typeToStruct(concrete_ty)) |struct_type| {
26406 const field_index = struct_type.nameIndex(ip, field_name) orelse break :find_field;26398 const field_index = struct_type.nameIndex(ip, field_name) orelse break :find_field;
26407 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);26399 return sema.finishFieldCallBind(block, src, ptr_ty, field_index, object_ptr);
26408
26409 return sema.finishFieldCallBind(block, src, ptr_ty, field_ty, field_index, object_ptr);
26410 } else if (concrete_ty.isTuple(zcu)) {26400 } else if (concrete_ty.isTuple(zcu)) {
26411 if (field_name.eqlSlice("len", ip)) {26401 if (field_name.eqlSlice("len", ip)) {
26412 return .{ .direct = try pt.intRef(.usize, concrete_ty.structFieldCount(zcu)) };26402 return .{ .direct = try pt.intRef(.usize, concrete_ty.structFieldCount(zcu)) };
26413 }26403 }
26414 if (field_name.toUnsigned(ip)) |field_index| {26404 if (field_name.toUnsigned(ip)) |field_index| {
26415 if (field_index >= concrete_ty.structFieldCount(zcu)) break :find_field;26405 if (field_index >= concrete_ty.structFieldCount(zcu)) break :find_field;
26416 return sema.finishFieldCallBind(block, src, ptr_ty, concrete_ty.fieldType(field_index, zcu), field_index, object_ptr);26406 return sema.finishFieldCallBind(block, src, ptr_ty, field_index, object_ptr);
26417 }26407 }
26418 } else {26408 } else {
26419 const max = concrete_ty.structFieldCount(zcu);26409 const max = concrete_ty.structFieldCount(zcu);
26420 for (0..max) |i_usize| {26410 for (0..max) |i_usize| {
26421 const i: u32 = @intCast(i_usize);26411 const i: u32 = @intCast(i_usize);
26422 if (field_name == concrete_ty.structFieldName(i, zcu).unwrap().?) {26412 if (field_name == concrete_ty.structFieldName(i, zcu).unwrap().?) {
26423 return sema.finishFieldCallBind(block, src, ptr_ty, concrete_ty.fieldType(i, zcu), i, object_ptr);26413 return sema.finishFieldCallBind(block, src, ptr_ty, i, object_ptr);
26424 }26414 }
26425 }26415 }
26426 }26416 }
...@@ -26536,19 +26526,12 @@ fn finishFieldCallBind(...@@ -26536,19 +26526,12 @@ fn finishFieldCallBind(
26536 block: *Block,26526 block: *Block,
26537 src: LazySrcLoc,26527 src: LazySrcLoc,
26538 ptr_ty: Type,26528 ptr_ty: Type,
26539 field_ty: Type,
26540 field_index: u32,26529 field_index: u32,
26541 object_ptr: Air.Inst.Ref,26530 object_ptr: Air.Inst.Ref,
26542) CompileError!ResolvedFieldCallee {26531) CompileError!ResolvedFieldCallee {
26543 const pt = sema.pt;26532 const pt = sema.pt;
26544 const zcu = pt.zcu;26533 const zcu = pt.zcu;
26545 const ptr_field_ty = try pt.ptrType(.{26534 const ptr_field_ty = try ptr_ty.fieldPtrType(field_index, pt);
26546 .child = field_ty.toIntern(),
26547 .flags = .{
26548 .is_const = !ptr_ty.ptrIsMutable(zcu),
26549 .address_space = ptr_ty.ptrAddressSpace(zcu),
26550 },
26551 });
2655226535
26553 const container_ty = ptr_ty.childType(zcu);26536 const container_ty = ptr_ty.childType(zcu);
26554 if (container_ty.zigTypeTag(zcu) == .@"struct") {26537 if (container_ty.zigTypeTag(zcu) == .@"struct") {
test/behavior/switch.zig+19
...@@ -1574,3 +1574,22 @@ test "repeated switch analysis overrides previous analysis results" {...@@ -1574,3 +1574,22 @@ test "repeated switch analysis overrides previous analysis results" {
1574 };1574 };
1575 }1575 }
1576}1576}
1577
1578test "union field pointer capture preserves alignment in inline prong" {
1579 const U = union(enum) {
1580 a: u32,
1581 b: u32,
1582 fn doTheTest(u: *align(1) const @This()) !void {
1583 switch (u.*) {
1584 inline .a, .b => |*a_ptr| {
1585 comptime assert(@TypeOf(a_ptr) == *align(1) const u32);
1586 try expect(a_ptr.* == 123);
1587 },
1588 }
1589 }
1590 };
1591 try U.doTheTest(&.{ .a = 123 });
1592 try U.doTheTest(&.{ .b = 123 });
1593 try comptime U.doTheTest(&.{ .a = 123 });
1594 try comptime U.doTheTest(&.{ .b = 123 });
1595}
test/behavior/try.zig+12
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const assert = std.debug.assert;
3const expect = std.testing.expect;4const expect = std.testing.expect;
45
5test "try on error union" {6test "try on error union" {
...@@ -197,3 +198,14 @@ test "try ptr propagation mutate" {...@@ -197,3 +198,14 @@ test "try ptr propagation mutate" {
197 try S.doTheTest();198 try S.doTheTest();
198 try comptime S.doTheTest();199 try comptime S.doTheTest();
199}200}
201
202test "try pointer expression alignment" {
203 const S = struct {
204 fn doTheTest(p: *align(1) (anyerror!u32)) !void {
205 comptime assert(@TypeOf(&(try p.*)) == *align(1) u32);
206 try expect((try p.*) == 10);
207 }
208 };
209 var x: anyerror!u32 = 10;
210 try S.doTheTest(&x);
211}
test/cases/safety/@intCast negative to u0.zig created+22
...@@ -0,0 +1,22 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "integer does not fit in destination type")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11pub fn main() !void {
12 bar(1, -1);
13 return error.TestFailed;
14}
15
16fn bar(one: u1, not_zero: i32) void {
17 const x = one << @intCast(not_zero);
18 _ = x;
19}
20// run
21// backend=selfhosted,llvm
22// target=x86_64-linux,aarch64-linux
test/cases/safety/@intCast positive to u0.zig created+22
...@@ -0,0 +1,22 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "integer does not fit in destination type")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11pub fn main() !void {
12 bar(1, 1);
13 return error.TestFailed;
14}
15
16fn bar(one: u1, not_zero: i32) void {
17 const x = one << @intCast(not_zero);
18 _ = x;
19}
20// run
21// backend=selfhosted,llvm
22// target=x86_64-linux,aarch64-linux
test/cases/safety/@intCast to u0.zig deleted-22
...@@ -1,22 +0,0 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "integer does not fit in destination type")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11pub fn main() !void {
12 bar(1, 1);
13 return error.TestFailed;
14}
15
16fn bar(one: u1, not_zero: i32) void {
17 const x = one << @intCast(not_zero);
18 _ = x;
19}
20// run
21// backend=selfhosted,llvm
22// target=x86_64-linux,aarch64-linux