Commit 0e38cc16d5

Veikka Tuominen <git@vexu.eu>
2022-12-02 18:56:43
Sema: fix comparisons between lazy and runtime values
Closes #12498
1 parent 7f9e841
Changed files (14)
lib/std/fs.zig
@@ -809,8 +809,6 @@ pub const IterableDir = struct {
                 // and we avoid the code complexity here.
                 const w = os.wasi;
                 start_over: while (true) {
-                    // TODO https://github.com/ziglang/zig/issues/12498
-                    _ = @sizeOf(w.dirent_t) + 1;
                     // According to the WASI spec, the last entry might be truncated,
                     // so we need to check if the left buffer contains the whole dirent.
                     if (self.end_index - self.index < @sizeOf(w.dirent_t)) {
src/arch/aarch64/CodeGen.zig
@@ -6247,7 +6247,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
             if (info.bits <= 64) {
                 const unsigned = switch (info.signedness) {
                     .signed => blk: {
-                        const signed = typed_value.val.toSignedInt();
+                        const signed = typed_value.val.toSignedInt(target);
                         break :blk @bitCast(u64, signed);
                     },
                     .unsigned => typed_value.val.toUnsignedInt(target),
src/arch/arm/CodeGen.zig
@@ -6121,7 +6121,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
             if (info.bits <= ptr_bits) {
                 const unsigned = switch (info.signedness) {
                     .signed => blk: {
-                        const signed = @intCast(i32, typed_value.val.toSignedInt());
+                        const signed = @intCast(i32, typed_value.val.toSignedInt(target));
                         break :blk @bitCast(u32, signed);
                     },
                     .unsigned => @intCast(u32, typed_value.val.toUnsignedInt(target)),
src/arch/sparc64/CodeGen.zig
@@ -3786,7 +3786,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
             if (info.bits <= 64) {
                 const unsigned = switch (info.signedness) {
                     .signed => blk: {
-                        const signed = typed_value.val.toSignedInt();
+                        const signed = typed_value.val.toSignedInt(target);
                         break :blk @bitCast(u64, signed);
                     },
                     .unsigned => typed_value.val.toUnsignedInt(target),
src/arch/wasm/CodeGen.zig
@@ -2702,11 +2702,11 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
             switch (int_info.signedness) {
                 .signed => switch (int_info.bits) {
                     0...32 => return WValue{ .imm32 = @intCast(u32, toTwosComplement(
-                        val.toSignedInt(),
+                        val.toSignedInt(target),
                         @intCast(u6, int_info.bits),
                     )) },
                     33...64 => return WValue{ .imm64 = toTwosComplement(
-                        val.toSignedInt(),
+                        val.toSignedInt(target),
                         @intCast(u7, int_info.bits),
                     ) },
                     else => unreachable,
@@ -2873,15 +2873,15 @@ fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) i32 {
             }
         },
         .Int => switch (ty.intInfo(func.target).signedness) {
-            .signed => return @truncate(i32, val.toSignedInt()),
+            .signed => return @truncate(i32, val.toSignedInt(target)),
             .unsigned => return @bitCast(i32, @truncate(u32, val.toUnsignedInt(target))),
         },
         .ErrorSet => {
             const kv = func.bin_file.base.options.module.?.getErrorValue(val.getError().?) catch unreachable; // passed invalid `Value` to function
             return @bitCast(i32, kv.value);
         },
-        .Bool => return @intCast(i32, val.toSignedInt()),
-        .Pointer => return @intCast(i32, val.toSignedInt()),
+        .Bool => return @intCast(i32, val.toSignedInt(target)),
+        .Pointer => return @intCast(i32, val.toSignedInt(target)),
         else => unreachable, // Programmer called this function for an illegal type
     }
 }
src/arch/x86_64/CodeGen.zig
@@ -7007,7 +7007,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
         .Int => {
             const info = typed_value.ty.intInfo(self.target.*);
             if (info.bits <= ptr_bits and info.signedness == .signed) {
-                return MCValue{ .immediate = @bitCast(u64, typed_value.val.toSignedInt()) };
+                return MCValue{ .immediate = @bitCast(u64, typed_value.val.toSignedInt(target)) };
             }
             if (!(info.bits > ptr_bits or info.signedness == .signed)) {
                 return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) };
src/codegen/llvm.zig
@@ -8932,7 +8932,7 @@ pub const FuncGen = struct {
             if (elem.isUndef()) {
                 val.* = llvm_i32.getUndef();
             } else {
-                const int = elem.toSignedInt();
+                const int = elem.toSignedInt(self.dg.module.getTarget());
                 const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len);
                 val.* = llvm_i32.constInt(unsigned, .False);
             }
src/codegen/spirv.zig
@@ -360,7 +360,7 @@ pub const DeclGen = struct {
 
                 // Note, value is required to be sign-extended, so we don't need to mask off the upper bits.
                 // See https://www.khronos.org/registry/SPIR-V/specs/unified1/SPIRV.html#Literal
-                var int_bits = if (ty.isSignedInt()) @bitCast(u64, val.toSignedInt()) else val.toUnsignedInt(target);
+                var int_bits = if (ty.isSignedInt()) @bitCast(u64, val.toSignedInt(target)) else val.toUnsignedInt(target);
 
                 const value: spec.LiteralContextDependentNumber = switch (backing_bits) {
                     1...32 => .{ .uint32 = @truncate(u32, int_bits) },
@@ -763,7 +763,7 @@ pub const DeclGen = struct {
             if (elem.isUndef()) {
                 self.func.body.writeOperand(spec.LiteralInteger, 0xFFFF_FFFF);
             } else {
-                const int = elem.toSignedInt();
+                const int = elem.toSignedInt(self.getTarget());
                 const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len);
                 self.func.body.writeOperand(spec.LiteralInteger, unsigned);
             }
src/link/Dwarf.zig
@@ -409,7 +409,7 @@ pub const DeclState = struct {
                         // See https://github.com/ziglang/zig/issues/645
                         var int_buffer: Value.Payload.U64 = undefined;
                         const field_int_val = value.enumToInt(ty, &int_buffer);
-                        break :value @bitCast(u64, field_int_val.toSignedInt());
+                        break :value @bitCast(u64, field_int_val.toSignedInt(target));
                     } else @intCast(u64, field_i);
                     mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian);
                 }
src/codegen.zig
@@ -459,7 +459,7 @@ pub fn generateSymbol(
             if (info.bits <= 8) {
                 const x: u8 = switch (info.signedness) {
                     .unsigned => @intCast(u8, typed_value.val.toUnsignedInt(target)),
-                    .signed => @bitCast(u8, @intCast(i8, typed_value.val.toSignedInt())),
+                    .signed => @bitCast(u8, @intCast(i8, typed_value.val.toSignedInt(target))),
                 };
                 try code.append(x);
                 return Result{ .appended = {} };
@@ -488,13 +488,13 @@ pub fn generateSymbol(
                 },
                 .signed => {
                     if (info.bits <= 16) {
-                        const x = @intCast(i16, typed_value.val.toSignedInt());
+                        const x = @intCast(i16, typed_value.val.toSignedInt(target));
                         mem.writeInt(i16, try code.addManyAsArray(2), x, endian);
                     } else if (info.bits <= 32) {
-                        const x = @intCast(i32, typed_value.val.toSignedInt());
+                        const x = @intCast(i32, typed_value.val.toSignedInt(target));
                         mem.writeInt(i32, try code.addManyAsArray(4), x, endian);
                     } else {
-                        const x = typed_value.val.toSignedInt();
+                        const x = typed_value.val.toSignedInt(target);
                         mem.writeInt(i64, try code.addManyAsArray(8), x, endian);
                     }
                 },
@@ -536,13 +536,13 @@ pub fn generateSymbol(
                 },
                 .signed => {
                     if (info.bits <= 16) {
-                        const x = @intCast(i16, int_val.toSignedInt());
+                        const x = @intCast(i16, int_val.toSignedInt(target));
                         mem.writeInt(i16, try code.addManyAsArray(2), x, endian);
                     } else if (info.bits <= 32) {
-                        const x = @intCast(i32, int_val.toSignedInt());
+                        const x = @intCast(i32, int_val.toSignedInt(target));
                         mem.writeInt(i32, try code.addManyAsArray(4), x, endian);
                     } else {
-                        const x = int_val.toSignedInt();
+                        const x = int_val.toSignedInt(target);
                         mem.writeInt(i64, try code.addManyAsArray(8), x, endian);
                     }
                 },
src/Sema.zig
@@ -20262,7 +20262,7 @@ fn analyzeShuffle(
         var buf: Value.ElemValueBuffer = undefined;
         const elem = mask.elemValueBuffer(sema.mod, i, &buf);
         if (elem.isUndef()) continue;
-        const int = elem.toSignedInt();
+        const int = elem.toSignedInt(sema.mod.getTarget());
         var unsigned: u32 = undefined;
         var chosen: u32 = undefined;
         if (int >= 0) {
@@ -20304,7 +20304,7 @@ fn analyzeShuffle(
                     values[i] = Value.undef;
                     continue;
                 }
-                const int = mask_elem_val.toSignedInt();
+                const int = mask_elem_val.toSignedInt(sema.mod.getTarget());
                 const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int);
                 if (int >= 0) {
                     values[i] = try a_val.elemValue(sema.mod, sema.arena, unsigned);
@@ -28299,6 +28299,7 @@ fn cmpNumeric(
 
     var lhs_bits: usize = undefined;
     if (try sema.resolveMaybeUndefVal(lhs)) |lhs_val| {
+        try sema.resolveLazyValue(lhs_val);
         if (lhs_val.isUndef())
             return sema.addConstUndef(Type.bool);
         if (lhs_val.isNan()) switch (op) {
@@ -28357,6 +28358,7 @@ fn cmpNumeric(
 
     var rhs_bits: usize = undefined;
     if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| {
+        try sema.resolveLazyValue(rhs_val);
         if (rhs_val.isUndef())
             return sema.addConstUndef(Type.bool);
         if (rhs_val.isNan()) switch (op) {
src/value.zig
@@ -1201,8 +1201,8 @@ pub const Value = extern union {
     }
 
     /// Asserts the value is an integer and it fits in a i64
-    pub fn toSignedInt(self: Value) i64 {
-        switch (self.tag()) {
+    pub fn toSignedInt(val: Value, target: Target) i64 {
+        switch (val.tag()) {
             .zero,
             .bool_false,
             .the_only_possible_value, // i0, u0
@@ -1212,10 +1212,19 @@ pub const Value = extern union {
             .bool_true,
             => return 1,
 
-            .int_u64 => return @intCast(i64, self.castTag(.int_u64).?.data),
-            .int_i64 => return self.castTag(.int_i64).?.data,
-            .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable,
-            .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable,
+            .int_u64 => return @intCast(i64, val.castTag(.int_u64).?.data),
+            .int_i64 => return val.castTag(.int_i64).?.data,
+            .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable,
+            .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable,
+
+            .lazy_align => {
+                const ty = val.castTag(.lazy_align).?.data;
+                return @intCast(i64, ty.abiAlignment(target));
+            },
+            .lazy_size => {
+                const ty = val.castTag(.lazy_size).?.data;
+                return @intCast(i64, ty.abiSize(target));
+            },
 
             .undef => unreachable,
             else => unreachable,
test/behavior/bugs/12498.zig
@@ -0,0 +1,8 @@
+const std = @import("std");
+const expect = std.testing.expect;
+
+const S = struct { a: usize };
+test "lazy abi size used in comparison" {
+    var rhs: i32 = 100;
+    try expect(@sizeOf(S) < rhs);
+}
test/behavior.zig
@@ -90,6 +90,7 @@ test {
     _ = @import("behavior/bugs/12430.zig");
     _ = @import("behavior/bugs/12486.zig");
     _ = @import("behavior/bugs/12488.zig");
+    _ = @import("behavior/bugs/12498.zig");
     _ = @import("behavior/bugs/12551.zig");
     _ = @import("behavior/bugs/12644.zig");
     _ = @import("behavior/bugs/12680.zig");