diff --git a/src/Sema.zig b/src/Sema.zig index 41398016e543b37d1f0aa3a862fa43d338044033..4588f487e253cd01083cfdbd3159c90513f1b011 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1593,27 +1593,16 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE } } - // We would like to rely on the mechanism below even for comptime values. - // However in the case that the pointer points to comptime-mutable value, - // we cannot do it. - if (try sema.resolveDefinedValue(block, src, ptr)) |ptr_val| { - if (ptr_val.isComptimeMutablePtr()) { - const ptr_ty = try Type.ptr(sema.arena, .{ - .pointee_type = pointee_ty, - .@"addrspace" = addr_space, - }); - return sema.addConstant(ptr_ty, ptr_val); - } - } - // Make a dummy store through the pointer to test the coercion. // We will then use the generated instructions to decide what // kind of transformations to make on the result pointer. var trash_block = block.makeSubBlock(); + trash_block.is_comptime = false; defer trash_block.instructions.deinit(sema.gpa); + const dummy_ptr = try trash_block.addTy(.alloc, sema.typeOf(ptr)); const dummy_operand = try trash_block.addBitCast(pointee_ty, .void_value); - try sema.storePtr(&trash_block, src, ptr, dummy_operand); + try sema.storePtr(&trash_block, src, dummy_ptr, dummy_operand); { const air_tags = sema.air_instructions.items(.tag); @@ -1644,6 +1633,9 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE 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); + } return sema.bitCast(block, ptr_ty, new_ptr, src); } const ty_op = air_datas[trash_inst].ty_op; @@ -1652,7 +1644,11 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE .pointee_type = operand_ty, .@"addrspace" = addr_space, }); - new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src); + if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| { + new_ptr = try sema.addConstant(ptr_operand_ty, ptr_val); + } else { + new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src); + } }, .wrap_optional => { new_ptr = try sema.analyzeOptionalPayloadPtr(block, src, new_ptr, false, true); @@ -1673,7 +1669,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE } }, } - } else unreachable; // TODO should not need else unreachable + } } pub fn analyzeStructDecl( @@ -16937,7 +16933,6 @@ fn wrapErrorUnionPayload( const dest_payload_ty = dest_ty.errorUnionPayload(); const coerced = try sema.coerce(block, dest_payload_ty, inst, inst_src); if (try sema.resolveMaybeUndefVal(block, inst_src, coerced)) |val| { - if (val.isUndef()) return sema.addConstUndef(dest_ty); return sema.addConstant(dest_ty, try Value.Tag.eu_payload.create(sema.arena, val)); } try sema.requireRuntimeBlock(block, inst_src); diff --git a/src/type.zig b/src/type.zig index 4eb78b0656bf7060734bcd663ea81af08ab2e69c..581465c51a81a40fea12231d027aa0a3f331bd65 100644 --- a/src/type.zig +++ b/src/type.zig @@ -3980,7 +3980,7 @@ pub const Type = extern union { pub fn structFields(ty: Type) Module.Struct.Fields { switch (ty.tag()) { - .empty_struct => return .{}, + .empty_struct, .empty_struct_literal => return .{}, .@"struct" => { const struct_obj = ty.castTag(.@"struct").?.data; assert(struct_obj.haveFieldTypes()); @@ -3996,7 +3996,7 @@ pub const Type = extern union { const struct_obj = ty.castTag(.@"struct").?.data; return struct_obj.fields.count(); }, - .empty_struct => return 0, + .empty_struct, .empty_struct_literal => return 0, .tuple => return ty.castTag(.tuple).?.data.types.len, else => unreachable, } diff --git a/src/value.zig b/src/value.zig index 4df36f79a1f19a11585f33222f390d7c663ac312..7c28398b73343e51850f9d2ed2fe988f8606a408 100644 --- a/src/value.zig +++ b/src/value.zig @@ -791,19 +791,24 @@ pub const Value = extern union { return decl_val.toAllocatedBytes(decl.ty, allocator); }, .the_only_possible_value => return &[_]u8{}, - .slice => return toAllocatedBytes(val.castTag(.slice).?.data.ptr, ty, allocator), - else => { - const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen())); - var elem_value_buf: ElemValueBuffer = undefined; - for (result) |*elem, i| { - const elem_val = val.elemValueBuffer(i, &elem_value_buf); - elem.* = @intCast(u8, elem_val.toUnsignedInt()); - } - return result; + .slice => { + const slice = val.castTag(.slice).?.data; + return arrayToAllocatedBytes(slice.ptr, slice.len.toUnsignedInt(), allocator); }, + else => return arrayToAllocatedBytes(val, ty.arrayLen(), allocator), } } + fn arrayToAllocatedBytes(val: Value, len: u64, allocator: Allocator) ![]u8 { + const result = try allocator.alloc(u8, @intCast(usize, len)); + var elem_value_buf: ElemValueBuffer = undefined; + for (result) |*elem, i| { + const elem_val = val.elemValueBuffer(i, &elem_value_buf); + elem.* = @intCast(u8, elem_val.toUnsignedInt()); + } + return result; + } + pub const ToTypeBuffer = Type.Payload.Bits; /// Asserts that the value is representable as a type. diff --git a/test/behavior.zig b/test/behavior.zig index 12d840b1958636454334682b0c1e56fd4c55e20e..2e27563afced7e4b98358292b3e101966796002d 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -127,8 +127,11 @@ test { _ = @import("behavior/bugs/726.zig"); _ = @import("behavior/bugs/1421.zig"); _ = @import("behavior/bugs/1442.zig"); + _ = @import("behavior/bugs/1607.zig"); _ = @import("behavior/bugs/2114.zig"); + _ = @import("behavior/bugs/3384.zig"); _ = @import("behavior/bugs/3742.zig"); + _ = @import("behavior/bugs/5398.zig"); _ = @import("behavior/struct_contains_null_ptr_itself.zig"); _ = @import("behavior/switch_prong_err_enum.zig"); _ = @import("behavior/switch_prong_implicit_cast.zig"); @@ -147,11 +150,8 @@ test { _ = @import("behavior/bugs/828.zig"); _ = @import("behavior/bugs/920.zig"); _ = @import("behavior/bugs/1120.zig"); - _ = @import("behavior/bugs/1607.zig"); _ = @import("behavior/bugs/1851.zig"); - _ = @import("behavior/bugs/3384.zig"); _ = @import("behavior/bugs/3779.zig"); - _ = @import("behavior/bugs/5398.zig"); _ = @import("behavior/bugs/5413.zig"); _ = @import("behavior/bugs/5487.zig"); _ = @import("behavior/bugs/6456.zig"); diff --git a/test/behavior/bugs/5398.zig b/test/behavior/bugs/5398.zig index 4921c05703a2721f1e49fda053e1c46923cd1fb5..8dc170c7363d14e8a374edf25fd2d9934da9c3ca 100644 --- a/test/behavior/bugs/5398.zig +++ b/test/behavior/bugs/5398.zig @@ -25,7 +25,7 @@ test "assignment of field with padding" { .emits_shadows = false, }, }; - try testing.expectEqual(false, renderable.material.transparent); - try testing.expectEqual(false, renderable.material.emits_shadows); - try testing.expectEqual(true, renderable.material.render_color); + try testing.expect(false == renderable.material.transparent); + try testing.expect(false == renderable.material.emits_shadows); + try testing.expect(true == renderable.material.render_color); } diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 0ddbf6458aa9f111cf2ac8be5cd481368beab7bd..50d99897c8687615dec780db42180a10378d866b 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -371,7 +371,9 @@ fn testPeerResolveArrayConstSlice(b: bool) !void { } test "implicitly cast from T to anyerror!?T" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; try castToOptionalTypeError(1); comptime try castToOptionalTypeError(1); @@ -387,7 +389,7 @@ fn castToOptionalTypeError(z: i32) !void { const f = z; const g: anyerror!?i32 = f; - _ = g catch {}; + _ = try g; const a = A{ .a = z }; const b: anyerror!?A = a; diff --git a/test/behavior/error.zig b/test/behavior/error.zig index 028bd26047fa6a337cc96e62743e53534fef1336..82814dc587690a05946b2b93a60d2418615c92dc 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -294,10 +294,11 @@ fn quux_1() !i32 { } test "error: Zero sized error set returned with value payload crash" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - _ = foo3(0) catch {}; - _ = comptime foo3(0) catch {}; + _ = try foo3(0); + _ = comptime try foo3(0); } const Error = error{}; diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index a1d60632a928ac8e951eb000ceea23f69f23f78e..1da2b0373de0fb2a64b7233b25fe0124a6c01c98 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -1237,3 +1237,28 @@ test "anon init through error union" { try S.doTheTest(); comptime try S.doTheTest(); } + +test "typed init through error unions and optionals" { + if (builtin.zig_backend == .stage1) return error.SkipZigTest; + if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest; // TODO + + const S = struct { + a: u32, + + fn foo() anyerror!?anyerror!@This() { + return @This(){ .a = 1 }; + } + fn bar() ?anyerror![2]u8 { + return [2]u8{ 1, 2 }; + } + + fn doTheTest() !void { + var a = try (try foo()).?; + var b = try bar().?; + try expect(a.a + b[1] == 3); + } + }; + + try S.doTheTest(); + comptime try S.doTheTest(); +}