mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 04:04:44 +01:00
Sema: fix single-range switch prong capture
This kind of capture cannot always be comptime-known, assuming so caused access of undefined memory during payload capture analysis!
This commit is contained in:
parent
76dd39d531
commit
e2338edb47
2 changed files with 32 additions and 20 deletions
37
src/Sema.zig
37
src/Sema.zig
|
|
@ -10970,8 +10970,7 @@ fn analyzeSwitchBlock(
|
||||||
.case_idx = index,
|
.case_idx = index,
|
||||||
} }),
|
} }),
|
||||||
capture == .by_ref,
|
capture == .by_ref,
|
||||||
is_special,
|
if (is_special) .special else .{ .item_refs = &.{.fromValue(item_opv)} },
|
||||||
if (!is_special) case_vals else undefined,
|
|
||||||
if (is_inline) .fromValue(item_opv) else .none,
|
if (is_inline) .fromValue(item_opv) else .none,
|
||||||
validated_switch.else_err_ty,
|
validated_switch.else_err_ty,
|
||||||
);
|
);
|
||||||
|
|
@ -12569,11 +12568,7 @@ fn resolveSwitchProng(
|
||||||
operand_src,
|
operand_src,
|
||||||
capture_src,
|
capture_src,
|
||||||
capture == .by_ref,
|
capture == .by_ref,
|
||||||
kind == .special,
|
kind,
|
||||||
switch (kind) {
|
|
||||||
.item_refs => |item_refs| item_refs,
|
|
||||||
.has_ranges, .special => undefined,
|
|
||||||
},
|
|
||||||
inline_case_capture,
|
inline_case_capture,
|
||||||
else_err_ty,
|
else_err_ty,
|
||||||
);
|
);
|
||||||
|
|
@ -12702,11 +12697,7 @@ fn analyzeSwitchProng(
|
||||||
operand_src,
|
operand_src,
|
||||||
capture_src,
|
capture_src,
|
||||||
capture == .by_ref,
|
capture == .by_ref,
|
||||||
kind == .special,
|
kind,
|
||||||
switch (kind) {
|
|
||||||
.item_refs => |item_refs| item_refs,
|
|
||||||
.has_ranges, .special => undefined,
|
|
||||||
},
|
|
||||||
inline_case_capture,
|
inline_case_capture,
|
||||||
else_err_ty,
|
else_err_ty,
|
||||||
);
|
);
|
||||||
|
|
@ -12783,9 +12774,7 @@ fn analyzeSwitchPayloadCapture(
|
||||||
operand_src: LazySrcLoc,
|
operand_src: LazySrcLoc,
|
||||||
capture_src: LazySrcLoc,
|
capture_src: LazySrcLoc,
|
||||||
capture_by_ref: bool,
|
capture_by_ref: bool,
|
||||||
is_special_prong: bool,
|
kind: SwitchProngKind,
|
||||||
/// May be `undefined` if `is_special_prong` is `true`.
|
|
||||||
case_vals: []const Air.Inst.Ref,
|
|
||||||
/// If this is not `.none`, this is an inline capture.
|
/// If this is not `.none`, this is an inline capture.
|
||||||
inline_case_capture: Air.Inst.Ref,
|
inline_case_capture: Air.Inst.Ref,
|
||||||
else_err_ty: ?Type,
|
else_err_ty: ?Type,
|
||||||
|
|
@ -12829,7 +12818,7 @@ fn analyzeSwitchPayloadCapture(
|
||||||
|
|
||||||
const operand_ptr_ty = if (capture_by_ref) sema.typeOf(operand_ptr) else undefined;
|
const operand_ptr_ty = if (capture_by_ref) sema.typeOf(operand_ptr) else undefined;
|
||||||
|
|
||||||
if (is_special_prong) {
|
if (kind == .special) {
|
||||||
if (capture_by_ref) return operand_ptr;
|
if (capture_by_ref) return operand_ptr;
|
||||||
return switch (operand_ty.zigTypeTag(zcu)) {
|
return switch (operand_ty.zigTypeTag(zcu)) {
|
||||||
.error_set => e: {
|
.error_set => e: {
|
||||||
|
|
@ -12846,6 +12835,8 @@ fn analyzeSwitchPayloadCapture(
|
||||||
|
|
||||||
switch (operand_ty.zigTypeTag(zcu)) {
|
switch (operand_ty.zigTypeTag(zcu)) {
|
||||||
.@"union" => {
|
.@"union" => {
|
||||||
|
const case_vals = kind.item_refs;
|
||||||
|
|
||||||
const union_obj = zcu.typeToUnion(operand_ty).?;
|
const union_obj = zcu.typeToUnion(operand_ty).?;
|
||||||
const first_item_val = sema.resolveConstDefinedValue(case_block, .unneeded, case_vals[0], undefined) catch unreachable;
|
const first_item_val = sema.resolveConstDefinedValue(case_block, .unneeded, case_vals[0], undefined) catch unreachable;
|
||||||
|
|
||||||
|
|
@ -13141,6 +13132,7 @@ fn analyzeSwitchPayloadCapture(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const case_vals = kind.item_refs;
|
||||||
if (case_vals.len == 1) {
|
if (case_vals.len == 1) {
|
||||||
const item_val = sema.resolveConstDefinedValue(case_block, .unneeded, case_vals[0], undefined) catch unreachable;
|
const item_val = sema.resolveConstDefinedValue(case_block, .unneeded, case_vals[0], undefined) catch unreachable;
|
||||||
const item_ty = try pt.singleErrorSetType(item_val.getErrorName(zcu).unwrap().?);
|
const item_ty = try pt.singleErrorSetType(item_val.getErrorName(zcu).unwrap().?);
|
||||||
|
|
@ -13161,11 +13153,16 @@ fn analyzeSwitchPayloadCapture(
|
||||||
// switch condition. It is comptime-known if there is only one item.
|
// switch condition. It is comptime-known if there is only one item.
|
||||||
if (capture_by_ref) {
|
if (capture_by_ref) {
|
||||||
return operand_ptr;
|
return operand_ptr;
|
||||||
} else if (case_vals.len == 1) {
|
|
||||||
return case_vals[0];
|
|
||||||
} else {
|
|
||||||
return operand_val;
|
|
||||||
}
|
}
|
||||||
|
switch (kind) {
|
||||||
|
.special => unreachable,
|
||||||
|
.item_refs => |case_vals| {
|
||||||
|
// If there's only a single item, the capture is comptime-known!
|
||||||
|
if (case_vals.len == 1) return case_vals[0];
|
||||||
|
},
|
||||||
|
.has_ranges => {},
|
||||||
|
}
|
||||||
|
return operand_val;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1307,3 +1307,18 @@ test "single-item prong in switch on enum has comptime-known capture" {
|
||||||
try E.doTheTest(.a);
|
try E.doTheTest(.a);
|
||||||
try comptime E.doTheTest(.a);
|
try comptime E.doTheTest(.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "single-range switch prong capture" {
|
||||||
|
const S = struct {
|
||||||
|
fn doTheTest(x: u8) !void {
|
||||||
|
switch (x) {
|
||||||
|
1...5 => |val| {
|
||||||
|
try expect(val == 2);
|
||||||
|
},
|
||||||
|
else => return error.TestFailed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try S.doTheTest(2);
|
||||||
|
try comptime S.doTheTest(2);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue