Skip to content

Commit c1a5caa

Browse files
committed
compiler: combine @intCast safety checks
`castTruncatedData` was a poorly worded error (all shrinking casts "truncate bits", it's just that we assume those bits to be zext/sext of the other bits!), and `negativeToUnsigned` was a pointless distinction which forced the compiler to emit worse code (since two separate safety checks were required for casting e.g. 'i32' to 'u16') and wasn't even implemented correctly. This commit combines those safety panics into one function, `integerOutOfBounds`. The name maybe isn't perfect, but that's not hugely important; what matters is the new default message, which is clearer than the old ones: "integer does not fit in destination type".
1 parent 6daa37d commit c1a5caa

20 files changed

+46
-74
lines changed

doc/langref/test_intCast_builtin.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ test "integer cast panic" {
55
_ = b;
66
}
77

8-
// test_error=cast truncated bits
8+
// test_error=integer does not fit in destination type

lib/std/debug.zig

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,9 @@ pub fn FullPanic(comptime panicFn: fn ([]const u8, ?usize) noreturn) type {
7878
@branchHint(.cold);
7979
call("invalid error code", @returnAddress());
8080
}
81-
pub fn castTruncatedData() noreturn {
81+
pub fn integerOutOfBounds() noreturn {
8282
@branchHint(.cold);
83-
call("integer cast truncated bits", @returnAddress());
84-
}
85-
pub fn negativeToUnsigned() noreturn {
86-
@branchHint(.cold);
87-
call("attempt to cast negative value to unsigned integer", @returnAddress());
83+
call("integer does not fit in destination type", @returnAddress());
8884
}
8985
pub fn integerOverflow() noreturn {
9086
@branchHint(.cold);
@@ -128,6 +124,10 @@ pub fn FullPanic(comptime panicFn: fn ([]const u8, ?usize) noreturn) type {
128124
}
129125
/// Delete after next zig1.wasm update
130126
pub const memcpyLenMismatch = copyLenMismatch;
127+
/// Delete after next zig1.wasm update
128+
pub const castTruncatedData = integerOutOfBounds;
129+
/// Delete after next zig1.wasm update
130+
pub const negativeToUnsigned = integerOutOfBounds;
131131
pub fn copyLenMismatch() noreturn {
132132
@branchHint(.cold);
133133
call("source and destination arguments have non-equal lengths", @returnAddress());

lib/std/debug/no_panic.zig

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,7 @@ pub fn invalidErrorCode() noreturn {
6565
@trap();
6666
}
6767

68-
pub fn castTruncatedData() noreturn {
69-
@branchHint(.cold);
70-
@trap();
71-
}
72-
73-
pub fn negativeToUnsigned() noreturn {
68+
pub fn integerOutOfBounds() noreturn {
7469
@branchHint(.cold);
7570
@trap();
7671
}
@@ -127,6 +122,10 @@ pub fn forLenMismatch() noreturn {
127122

128123
/// Delete after next zig1.wasm update
129124
pub const memcpyLenMismatch = copyLenMismatch;
125+
/// Delete after next zig1.wasm update
126+
pub const castTruncatedData = integerOutOfBounds;
127+
/// Delete after next zig1.wasm update
128+
pub const negativeToUnsigned = integerOutOfBounds;
130129

131130
pub fn copyLenMismatch() noreturn {
132131
@branchHint(.cold);

lib/std/debug/simple_panic.zig

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,8 @@ pub fn invalidErrorCode() noreturn {
7272
call("invalid error code", null);
7373
}
7474

75-
pub fn castTruncatedData() noreturn {
76-
call("integer cast truncated bits", null);
77-
}
78-
79-
pub fn negativeToUnsigned() noreturn {
80-
call("attempt to cast negative value to unsigned integer", null);
75+
pub fn integerOutOfBounds() noreturn {
76+
call("integer does not fit in destination type", null);
8177
}
8278

8379
pub fn integerOverflow() noreturn {
@@ -122,6 +118,10 @@ pub fn forLenMismatch() noreturn {
122118

123119
/// Delete after next zig1.wasm update
124120
pub const memcpyLenMismatch = copyLenMismatch;
121+
/// Delete after next zig1.wasm update
122+
pub const castTruncatedData = integerOutOfBounds;
123+
/// Delete after next zig1.wasm update
124+
pub const negativeToUnsigned = integerOutOfBounds;
125125

126126
pub fn copyLenMismatch() noreturn {
127127
call("source and destination have non-equal lengths", null);

src/Air/Legalize.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1307,7 +1307,7 @@ fn safeIntcastBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Error!Air.In
13071307
var main_block: Block = .init(&inst_buf);
13081308
var cur_block: *Block = &main_block;
13091309

1310-
const panic_id: Zcu.SimplePanicId = if (dest_is_enum) .invalid_enum_value else .cast_truncated_data;
1310+
const panic_id: Zcu.SimplePanicId = if (dest_is_enum) .invalid_enum_value else .integer_out_of_bounds;
13111311

13121312
if (have_min_check or have_max_check) {
13131313
const dest_int_ty = if (dest_is_enum) dest_ty.intTagType(zcu) else dest_ty;

src/Sema.zig

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10263,7 +10263,7 @@ fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1026310263
const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_eu_opt, "@intCast");
1026410264
const operand = try sema.resolveInst(extra.rhs);
1026510265

10266-
return sema.intCast(block, block.nodeOffset(inst_data.src_node), dest_ty, src, operand, operand_src, true, false);
10266+
return sema.intCast(block, block.nodeOffset(inst_data.src_node), dest_ty, src, operand, operand_src);
1026710267
}
1026810268

1026910269
fn intCast(
@@ -10274,8 +10274,6 @@ fn intCast(
1027410274
dest_ty_src: LazySrcLoc,
1027510275
operand: Air.Inst.Ref,
1027610276
operand_src: LazySrcLoc,
10277-
runtime_safety: bool,
10278-
safety_panics_are_enum: bool,
1027910277
) CompileError!Air.Inst.Ref {
1028010278
const pt = sema.pt;
1028110279
const zcu = pt.zcu;
@@ -10294,7 +10292,7 @@ fn intCast(
1029410292

1029510293
if ((try sema.typeHasOnePossibleValue(dest_ty))) |opv| {
1029610294
// requirement: intCast(u0, input) iff input == 0
10297-
if (runtime_safety and block.wantSafety()) {
10295+
if (block.wantSafety()) {
1029810296
try sema.requireRuntimeBlock(block, src, operand_src);
1029910297
const wanted_info = dest_scalar_ty.intInfo(zcu);
1030010298
const wanted_bits = wanted_info.bits;
@@ -10311,18 +10309,17 @@ fn intCast(
1031110309
const is_in_range = try block.addBinOp(.cmp_lte, operand, zero_inst);
1031210310
break :ok is_in_range;
1031310311
};
10314-
try sema.addSafetyCheck(block, src, ok, if (safety_panics_are_enum) .invalid_enum_value else .cast_truncated_data);
10312+
try sema.addSafetyCheck(block, src, ok, .integer_out_of_bounds);
1031510313
}
1031610314
}
1031710315

1031810316
return Air.internedToRef(opv.toIntern());
1031910317
}
1032010318

1032110319
try sema.requireRuntimeBlock(block, src, operand_src);
10322-
if (runtime_safety and block.wantSafety()) {
10320+
if (block.wantSafety()) {
1032310321
if (zcu.backendSupportsFeature(.panic_fn)) {
10324-
_ = try sema.preparePanicId(src, .negative_to_unsigned);
10325-
_ = try sema.preparePanicId(src, .cast_truncated_data);
10322+
_ = try sema.preparePanicId(src, .integer_out_of_bounds);
1032610323
}
1032710324
return block.addTyOp(.intcast_safe, dest_ty, operand);
1032810325
}
@@ -37984,8 +37981,7 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ
3798437981
.@"panic.castToNull",
3798537982
.@"panic.incorrectAlignment",
3798637983
.@"panic.invalidErrorCode",
37987-
.@"panic.castTruncatedData",
37988-
.@"panic.negativeToUnsigned",
37984+
.@"panic.integerOutOfBounds",
3798937985
.@"panic.integerOverflow",
3799037986
.@"panic.shlOverflow",
3799137987
.@"panic.shrOverflow",

src/Zcu.zig

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -441,8 +441,7 @@ pub const BuiltinDecl = enum {
441441
@"panic.castToNull",
442442
@"panic.incorrectAlignment",
443443
@"panic.invalidErrorCode",
444-
@"panic.castTruncatedData",
445-
@"panic.negativeToUnsigned",
444+
@"panic.integerOutOfBounds",
446445
@"panic.integerOverflow",
447446
@"panic.shlOverflow",
448447
@"panic.shrOverflow",
@@ -518,8 +517,7 @@ pub const BuiltinDecl = enum {
518517
.@"panic.castToNull",
519518
.@"panic.incorrectAlignment",
520519
.@"panic.invalidErrorCode",
521-
.@"panic.castTruncatedData",
522-
.@"panic.negativeToUnsigned",
520+
.@"panic.integerOutOfBounds",
523521
.@"panic.integerOverflow",
524522
.@"panic.shlOverflow",
525523
.@"panic.shrOverflow",
@@ -585,8 +583,7 @@ pub const SimplePanicId = enum {
585583
cast_to_null,
586584
incorrect_alignment,
587585
invalid_error_code,
588-
cast_truncated_data,
589-
negative_to_unsigned,
586+
integer_out_of_bounds,
590587
integer_overflow,
591588
shl_overflow,
592589
shr_overflow,
@@ -609,8 +606,7 @@ pub const SimplePanicId = enum {
609606
.cast_to_null => .@"panic.castToNull",
610607
.incorrect_alignment => .@"panic.incorrectAlignment",
611608
.invalid_error_code => .@"panic.invalidErrorCode",
612-
.cast_truncated_data => .@"panic.castTruncatedData",
613-
.negative_to_unsigned => .@"panic.negativeToUnsigned",
609+
.integer_out_of_bounds => .@"panic.integerOutOfBounds",
614610
.integer_overflow => .@"panic.integerOverflow",
615611
.shl_overflow => .@"panic.shlOverflow",
616612
.shr_overflow => .@"panic.shrOverflow",

src/codegen/llvm.zig

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9189,11 +9189,7 @@ pub const FuncGen = struct {
91899189
const is_vector = operand_ty.zigTypeTag(zcu) == .vector;
91909190
assert(is_vector == (dest_ty.zigTypeTag(zcu) == .vector));
91919191

9192-
const min_panic_id: Zcu.SimplePanicId, const max_panic_id: Zcu.SimplePanicId = id: {
9193-
if (dest_is_enum) break :id .{ .invalid_enum_value, .invalid_enum_value };
9194-
if (dest_info.signedness == .unsigned) break :id .{ .negative_to_unsigned, .cast_truncated_data };
9195-
break :id .{ .cast_truncated_data, .cast_truncated_data };
9196-
};
9192+
const panic_id: Zcu.SimplePanicId = if (dest_is_enum) .invalid_enum_value else .integer_out_of_bounds;
91979193

91989194
if (have_min_check) {
91999195
const min_const_scalar = try minIntConst(&o.builder, dest_scalar, operand_scalar_llvm_ty, zcu);
@@ -9207,7 +9203,7 @@ pub const FuncGen = struct {
92079203
const ok_block = try fg.wip.block(1, "IntMinOk");
92089204
_ = try fg.wip.brCond(ok, ok_block, fail_block, .none);
92099205
fg.wip.cursor = .{ .block = fail_block };
9210-
try fg.buildSimplePanic(min_panic_id);
9206+
try fg.buildSimplePanic(panic_id);
92119207
fg.wip.cursor = .{ .block = ok_block };
92129208
}
92139209

@@ -9223,7 +9219,7 @@ pub const FuncGen = struct {
92239219
const ok_block = try fg.wip.block(1, "IntMaxOk");
92249220
_ = try fg.wip.brCond(ok, ok_block, fail_block, .none);
92259221
fg.wip.cursor = .{ .block = fail_block };
9226-
try fg.buildSimplePanic(max_panic_id);
9222+
try fg.buildSimplePanic(panic_id);
92279223
fg.wip.cursor = .{ .block = ok_block };
92289224
}
92299225
}

test/cases/compile_errors/bad_panic_call_signature.zig

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ pub const panic = struct {
1515
pub const castToNull = simple_panic.castToNull;
1616
pub const incorrectAlignment = simple_panic.incorrectAlignment;
1717
pub const invalidErrorCode = simple_panic.invalidErrorCode;
18-
pub const castTruncatedData = simple_panic.castTruncatedData;
19-
pub const negativeToUnsigned = simple_panic.negativeToUnsigned;
18+
pub const integerOutOfBounds = simple_panic.integerOutOfBounds;
2019
pub const integerOverflow = simple_panic.integerOverflow;
2120
pub const shlOverflow = simple_panic.shlOverflow;
2221
pub const shrOverflow = simple_panic.shrOverflow;
@@ -27,8 +26,6 @@ pub const panic = struct {
2726
pub const shiftRhsTooBig = simple_panic.shiftRhsTooBig;
2827
pub const invalidEnumValue = simple_panic.invalidEnumValue;
2928
pub const forLenMismatch = simple_panic.forLenMismatch;
30-
/// Delete after next zig1.wasm update
31-
pub const memcpyLenMismatch = copyLenMismatch;
3229
pub const copyLenMismatch = simple_panic.copyLenMismatch;
3330
pub const memcpyAlias = simple_panic.memcpyAlias;
3431
pub const noreturnReturned = simple_panic.noreturnReturned;

test/cases/compile_errors/bad_panic_generic_signature.zig

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ pub const panic = struct {
1111
pub const castToNull = simple_panic.castToNull;
1212
pub const incorrectAlignment = simple_panic.incorrectAlignment;
1313
pub const invalidErrorCode = simple_panic.invalidErrorCode;
14-
pub const castTruncatedData = simple_panic.castTruncatedData;
15-
pub const negativeToUnsigned = simple_panic.negativeToUnsigned;
14+
pub const integerOutOfBounds = simple_panic.integerOutOfBounds;
1615
pub const integerOverflow = simple_panic.integerOverflow;
1716
pub const shlOverflow = simple_panic.shlOverflow;
1817
pub const shrOverflow = simple_panic.shrOverflow;
@@ -23,8 +22,6 @@ pub const panic = struct {
2322
pub const shiftRhsTooBig = simple_panic.shiftRhsTooBig;
2423
pub const invalidEnumValue = simple_panic.invalidEnumValue;
2524
pub const forLenMismatch = simple_panic.forLenMismatch;
26-
/// Delete after next zig1.wasm update
27-
pub const memcpyLenMismatch = copyLenMismatch;
2825
pub const copyLenMismatch = simple_panic.copyLenMismatch;
2926
pub const memcpyAlias = simple_panic.memcpyAlias;
3027
pub const noreturnReturned = simple_panic.noreturnReturned;

0 commit comments

Comments
 (0)