Commit a3c9bfef30

Robin Voetter <robin@voetter.nl>
2021-10-22 01:24:38
stage2: truncation
* Also fixes a related case where big int truncate would assume that the input fits in the output limbs buffer
1 parent d49c601
Changed files (4)
lib
std
src
test
lib/std/math/big/int.zig
@@ -1405,13 +1405,16 @@ pub const Mutable = struct {
                 r.normalize(r.len);
             }
         } else {
-            r.copy(a);
-            if (r.len < req_limbs) {
+            if (a.limbs.len < req_limbs) {
                 // Integer fits within target bits, no wrapping required.
+                r.copy(a);
                 return;
             }
 
-            r.len = req_limbs;
+            r.copy(.{
+                .positive = a.positive,
+                .limbs = a.limbs[0..req_limbs],
+            });
             r.limbs[r.len - 1] &= mask;
             r.normalize(r.len);
 
lib/std/math/big/int_test.zig
@@ -1654,6 +1654,18 @@ test "big.int truncate negative multi to single" {
     try testing.expect((try a.to(i17)) == 0);
 }
 
+test "big.int truncate multi unsigned many" {
+    var a = try Managed.initSet(testing.allocator, 1);
+    defer a.deinit();
+    try a.shiftLeft(a, 1023);
+
+    var b = try Managed.init(testing.allocator);
+    defer b.deinit();
+    try b.truncate(a.toConst(), .signed, @bitSizeOf(i1));
+
+    try testing.expect((try b.to(i1)) == 0);
+}
+
 test "big.int saturate single signed positive" {
     var a = try Managed.initSet(testing.allocator, 0xBBBB_BBBB);
     defer a.deinit();
src/Sema.zig
@@ -9477,14 +9477,18 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
     }
 
     const target = sema.mod.getTarget();
-    const src_info = operand_ty.intInfo(target);
     const dest_info = dest_ty.intInfo(target);
 
-    if (src_info.bits == 0 or dest_info.bits == 0) {
+    if (dest_info.bits == 0) {
         return sema.addConstant(dest_ty, Value.zero);
     }
 
     if (!src_is_comptime_int) {
+        const src_info = operand_ty.intInfo(target);
+        if (src_info.bits == 0) {
+            return sema.addConstant(dest_ty, Value.zero);
+        }
+
         if (src_info.signedness != dest_info.signedness) {
             return sema.fail(block, operand_src, "expected {s} integer type, found '{}'", .{
                 @tagName(dest_info.signedness), operand_ty,
test/behavior.zig
@@ -51,6 +51,7 @@ test {
     _ = @import("behavior/switch.zig");
     _ = @import("behavior/this.zig");
     _ = @import("behavior/translate_c_macros.zig");
+    _ = @import("behavior/truncate.zig");
     _ = @import("behavior/underscore.zig");
     _ = @import("behavior/union.zig");
     _ = @import("behavior/usingnamespace.zig");
@@ -163,7 +164,6 @@ test {
         _ = @import("behavior/switch_prong_err_enum.zig");
         _ = @import("behavior/switch_prong_implicit_cast.zig");
         _ = @import("behavior/switch_stage1.zig");
-        _ = @import("behavior/truncate.zig");
         _ = @import("behavior/try.zig");
         _ = @import("behavior/tuple.zig");
         _ = @import("behavior/type.zig");