authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-14 18:10:54-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-14 18:11:46-07:00
log04572f6e341e6ff19877d1ae3b79e3baa653e652
tree07b91717329efb36bd8c8bd266b047fff60692ff
parentd7711ec9532d4c38bf1911f5c0ed2c813705ae15

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.

3 files changed, 39 insertions(+), 24 deletions(-)

src/Sema.zig+22-20
...@@ -2030,7 +2030,8 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -2030,7 +2030,8 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
2030 defer trash_block.instructions.deinit(sema.gpa);2030 defer trash_block.instructions.deinit(sema.gpa);
20312031
2032 const dummy_ptr = try trash_block.addTy(.alloc, sema.typeOf(ptr));2032 const dummy_ptr = try trash_block.addTy(.alloc, sema.typeOf(ptr));
2033 return coerceResultPtr(sema, block, src, ptr, dummy_ptr, pointee_ty, &trash_block);2033 const dummy_operand = try trash_block.addBitCast(pointee_ty, .void_value);
2034 return coerceResultPtr(sema, block, src, ptr, dummy_ptr, dummy_operand, &trash_block);
2034}2035}
20352036
2036fn coerceResultPtr(2037fn coerceResultPtr(
...@@ -2039,13 +2040,14 @@ fn coerceResultPtr(...@@ -2039,13 +2040,14 @@ fn coerceResultPtr(
2039 src: LazySrcLoc,2040 src: LazySrcLoc,
2040 ptr: Air.Inst.Ref,2041 ptr: Air.Inst.Ref,
2041 dummy_ptr: Air.Inst.Ref,2042 dummy_ptr: Air.Inst.Ref,
2042 pointee_ty: Type,2043 dummy_operand: Air.Inst.Ref,
2043 trash_block: *Block,2044 trash_block: *Block,
2044) CompileError!Air.Inst.Ref {2045) CompileError!Air.Inst.Ref {
2045 const target = sema.mod.getTarget();2046 const target = sema.mod.getTarget();
2046 const addr_space = target_util.defaultAddressSpace(target, .local);2047 const addr_space = target_util.defaultAddressSpace(target, .local);
2048 const pointee_ty = sema.typeOf(dummy_operand);
2049 const prev_trash_len = trash_block.instructions.items.len;
20472050
2048 const dummy_operand = try trash_block.addBitCast(pointee_ty, .void_value);
2049 try sema.storePtr2(trash_block, src, dummy_ptr, src, dummy_operand, src, .bitcast);2051 try sema.storePtr2(trash_block, src, dummy_ptr, src, dummy_operand, src, .bitcast);
20502052
2051 {2053 {
...@@ -2078,21 +2080,24 @@ fn coerceResultPtr(...@@ -2078,21 +2080,24 @@ fn coerceResultPtr(
2078 while (true) {2080 while (true) {
2079 const air_tags = sema.air_instructions.items(.tag);2081 const air_tags = sema.air_instructions.items(.tag);
2080 const air_datas = sema.air_instructions.items(.data);2082 const air_datas = sema.air_instructions.items(.data);
2083
2084 if (trash_block.instructions.items.len == prev_trash_len) {
2085 if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| {
2086 return sema.addConstant(ptr_ty, ptr_val);
2087 }
2088 if (pointee_ty.eql(Type.@"null", sema.mod)) {
2089 const opt_ty = sema.typeOf(new_ptr).childType();
2090 const null_inst = try sema.addConstant(opt_ty, Value.@"null");
2091 _ = try block.addBinOp(.store, new_ptr, null_inst);
2092 return Air.Inst.Ref.void_value;
2093 }
2094 return sema.bitCast(block, ptr_ty, new_ptr, src);
2095 }
2096
2081 const trash_inst = trash_block.instructions.pop();2097 const trash_inst = trash_block.instructions.pop();
2098
2082 switch (air_tags[trash_inst]) {2099 switch (air_tags[trash_inst]) {
2083 .bitcast => {2100 .bitcast => {
2084 if (Air.indexToRef(trash_inst) == dummy_operand) {
2085 if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| {
2086 return sema.addConstant(ptr_ty, ptr_val);
2087 }
2088 if (pointee_ty.eql(Type.@"null", sema.mod)) {
2089 const opt_ty = sema.typeOf(new_ptr).childType();
2090 const null_inst = try sema.addConstant(opt_ty, Value.@"null");
2091 _ = try block.addBinOp(.store, new_ptr, null_inst);
2092 return Air.Inst.Ref.void_value;
2093 }
2094 return sema.bitCast(block, ptr_ty, new_ptr, src);
2095 }
2096 const ty_op = air_datas[trash_inst].ty_op;2101 const ty_op = air_datas[trash_inst].ty_op;
2097 const operand_ty = sema.typeOf(ty_op.operand);2102 const operand_ty = sema.typeOf(ty_op.operand);
2098 const ptr_operand_ty = try Type.ptr(sema.arena, sema.mod, .{2103 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...@@ -3309,8 +3314,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
3309 defer bitcast_block.instructions.deinit(gpa);3314 defer bitcast_block.instructions.deinit(gpa);
33103315
3311 trash_block.instructions.shrinkRetainingCapacity(empty_trash_count);3316 trash_block.instructions.shrinkRetainingCapacity(empty_trash_count);
3312 const pointee_ty = sema.typeOf(peer_inst_list[i]);3317 const sub_ptr = try coerceResultPtr(sema, &bitcast_block, src, ptr, dummy_ptr, peer_inst_list[i], &trash_block);
3313 const sub_ptr = try coerceResultPtr(sema, &bitcast_block, src, ptr, dummy_ptr, pointee_ty, &trash_block);
33143318
3315 assert(bitcast_block.instructions.items.len > 0);3319 assert(bitcast_block.instructions.items.len > 0);
3316 // If only one instruction is produced then we can replace the bitcast3320 // If only one instruction is produced then we can replace the bitcast
...@@ -4190,7 +4194,7 @@ fn storeToInferredAlloc(...@@ -4190,7 +4194,7 @@ fn storeToInferredAlloc(
4190 .stored_inst = operand,4194 .stored_inst = operand,
4191 .placeholder = Air.refToIndex(bitcasted_ptr).?,4195 .placeholder = Air.refToIndex(bitcasted_ptr).?,
4192 });4196 });
4193 return sema.storePtr(block, src, bitcasted_ptr, operand);4197 return sema.storePtr2(block, src, bitcasted_ptr, src, operand, src, .bitcast);
4194}4198}
41954199
4196fn storeToInferredAllocComptime(4200fn storeToInferredAllocComptime(
...@@ -21707,8 +21711,6 @@ fn storePtr2(...@@ -21707,8 +21711,6 @@ fn storePtr2(
21707 if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null)21711 if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null)
21708 return;21712 return;
2170921713
21710 // TODO handle if the element type requires comptime
21711
21712 if (air_tag == .bitcast) {21714 if (air_tag == .bitcast) {
21713 // `air_tag == .bitcast` is used as a special case for `zirCoerceResultPtr`21715 // `air_tag == .bitcast` is used as a special case for `zirCoerceResultPtr`
21714 // to avoid calling `requireRuntimeBlock` for the dummy block.21716 // to avoid calling `requireRuntimeBlock` for the dummy block.
test/behavior/array.zig+1-4
...@@ -570,10 +570,7 @@ test "type coercion of pointer to anon struct literal to pointer to array" {...@@ -570,10 +570,7 @@ test "type coercion of pointer to anon struct literal to pointer to array" {
570}570}
571571
572test "array with comptime only element type" {572test "array with comptime only element type" {
573 const a = [_]type{573 const a = [_]type{ u32, i32 };
574 u32,
575 i32,
576 };
577 try testing.expect(a[0] == u32);574 try testing.expect(a[0] == u32);
578 try testing.expect(a[1] == i32);575 try testing.expect(a[1] == i32);
579}576}
test/behavior/if.zig+16
...@@ -140,3 +140,19 @@ test "if-else expression with runtime condition result location is inferred opti...@@ -140,3 +140,19 @@ test "if-else expression with runtime condition result location is inferred opti
140 const e = if (d) A{ .b = 15, .c = 30 } else null;140 const e = if (d) A{ .b = 15, .c = 30 } else null;
141 try expect(e != null);141 try expect(e != null);
142}142}
143
144test "result location with inferred type ends up being pointer to comptime_int" {
145 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
146 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
147 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
149 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
150
151 var a: ?u32 = 1234;
152 var b: u32 = 2000;
153 var c = if (a) |d| blk: {
154 if (d < b) break :blk @as(u32, 1);
155 break :blk 0;
156 } else @as(u32, 0);
157 try expect(c == 1);
158}