Commit 04572f6e34

Andrew Kelley <andrew@ziglang.org>
2022-07-15 03:10:54
Sema: fix coerceResultPtr
It did not handle properly when the dummy operand was a comptime_int; it was crashing in coerce because comptime_int is supposed to be comptime-known. So when calling coerceResultPtr, we pass the actual operand, not a dummy operand, which means it will have the proper comptime value when necessary.
1 parent d7711ec
Changed files (3)
src
test
src/Sema.zig
@@ -2030,7 +2030,8 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
     defer trash_block.instructions.deinit(sema.gpa);
 
     const dummy_ptr = try trash_block.addTy(.alloc, sema.typeOf(ptr));
-    return coerceResultPtr(sema, block, src, ptr, dummy_ptr, pointee_ty, &trash_block);
+    const dummy_operand = try trash_block.addBitCast(pointee_ty, .void_value);
+    return coerceResultPtr(sema, block, src, ptr, dummy_ptr, dummy_operand, &trash_block);
 }
 
 fn coerceResultPtr(
@@ -2039,13 +2040,14 @@ fn coerceResultPtr(
     src: LazySrcLoc,
     ptr: Air.Inst.Ref,
     dummy_ptr: Air.Inst.Ref,
-    pointee_ty: Type,
+    dummy_operand: Air.Inst.Ref,
     trash_block: *Block,
 ) CompileError!Air.Inst.Ref {
     const target = sema.mod.getTarget();
     const addr_space = target_util.defaultAddressSpace(target, .local);
+    const pointee_ty = sema.typeOf(dummy_operand);
+    const prev_trash_len = trash_block.instructions.items.len;
 
-    const dummy_operand = try trash_block.addBitCast(pointee_ty, .void_value);
     try sema.storePtr2(trash_block, src, dummy_ptr, src, dummy_operand, src, .bitcast);
 
     {
@@ -2078,21 +2080,24 @@ fn coerceResultPtr(
     while (true) {
         const air_tags = sema.air_instructions.items(.tag);
         const air_datas = sema.air_instructions.items(.data);
+
+        if (trash_block.instructions.items.len == prev_trash_len) {
+            if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| {
+                return sema.addConstant(ptr_ty, ptr_val);
+            }
+            if (pointee_ty.eql(Type.@"null", sema.mod)) {
+                const opt_ty = sema.typeOf(new_ptr).childType();
+                const null_inst = try sema.addConstant(opt_ty, Value.@"null");
+                _ = try block.addBinOp(.store, new_ptr, null_inst);
+                return Air.Inst.Ref.void_value;
+            }
+            return sema.bitCast(block, ptr_ty, new_ptr, src);
+        }
+
         const trash_inst = trash_block.instructions.pop();
+
         switch (air_tags[trash_inst]) {
             .bitcast => {
-                if (Air.indexToRef(trash_inst) == dummy_operand) {
-                    if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| {
-                        return sema.addConstant(ptr_ty, ptr_val);
-                    }
-                    if (pointee_ty.eql(Type.@"null", sema.mod)) {
-                        const opt_ty = sema.typeOf(new_ptr).childType();
-                        const null_inst = try sema.addConstant(opt_ty, Value.@"null");
-                        _ = try block.addBinOp(.store, new_ptr, null_inst);
-                        return Air.Inst.Ref.void_value;
-                    }
-                    return sema.bitCast(block, ptr_ty, new_ptr, src);
-                }
                 const ty_op = air_datas[trash_inst].ty_op;
                 const operand_ty = sema.typeOf(ty_op.operand);
                 const ptr_operand_ty = try Type.ptr(sema.arena, sema.mod, .{
@@ -3309,8 +3314,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
                 defer bitcast_block.instructions.deinit(gpa);
 
                 trash_block.instructions.shrinkRetainingCapacity(empty_trash_count);
-                const pointee_ty = sema.typeOf(peer_inst_list[i]);
-                const sub_ptr = try coerceResultPtr(sema, &bitcast_block, src, ptr, dummy_ptr, pointee_ty, &trash_block);
+                const sub_ptr = try coerceResultPtr(sema, &bitcast_block, src, ptr, dummy_ptr, peer_inst_list[i], &trash_block);
 
                 assert(bitcast_block.instructions.items.len > 0);
                 // If only one instruction is produced then we can replace the bitcast
@@ -4190,7 +4194,7 @@ fn storeToInferredAlloc(
         .stored_inst = operand,
         .placeholder = Air.refToIndex(bitcasted_ptr).?,
     });
-    return sema.storePtr(block, src, bitcasted_ptr, operand);
+    return sema.storePtr2(block, src, bitcasted_ptr, src, operand, src, .bitcast);
 }
 
 fn storeToInferredAllocComptime(
@@ -21707,8 +21711,6 @@ fn storePtr2(
     if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null)
         return;
 
-    // TODO handle if the element type requires comptime
-
     if (air_tag == .bitcast) {
         // `air_tag == .bitcast` is used as a special case for `zirCoerceResultPtr`
         // to avoid calling `requireRuntimeBlock` for the dummy block.
test/behavior/array.zig
@@ -570,10 +570,7 @@ test "type coercion of pointer to anon struct literal to pointer to array" {
 }
 
 test "array with comptime only element type" {
-    const a = [_]type{
-        u32,
-        i32,
-    };
+    const a = [_]type{ u32, i32 };
     try testing.expect(a[0] == u32);
     try testing.expect(a[1] == i32);
 }
test/behavior/if.zig
@@ -140,3 +140,19 @@ test "if-else expression with runtime condition result location is inferred opti
     const e = if (d) A{ .b = 15, .c = 30 } else null;
     try expect(e != null);
 }
+
+test "result location with inferred type ends up being pointer to comptime_int" {
+    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
+
+    var a: ?u32 = 1234;
+    var b: u32 = 2000;
+    var c = if (a) |d| blk: {
+        if (d < b) break :blk @as(u32, 1);
+        break :blk 0;
+    } else @as(u32, 0);
+    try expect(c == 1);
+}