diff --git a/src/Module.zig b/src/Module.zig index e596ab0aba..7f52dc23e9 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -1435,7 +1435,7 @@ pub const Fn = struct { /// All currently known errors that this error set contains. This includes direct additions /// via `return error.Foo;`, and possibly also errors that are returned from any dependent functions. /// When the inferred error set is fully resolved, this map contains all the errors that the function might return. - errors: std.StringHashMapUnmanaged(void) = .{}, + errors: ErrorSet.NameMap = .{}, /// Other inferred error sets which this inferred error set should include. inferred_error_sets: std.AutoHashMapUnmanaged(*InferredErrorSet, void) = .{}, diff --git a/src/Sema.zig b/src/Sema.zig index 4588f487e2..e5c38c8450 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1613,10 +1613,15 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE //} // The last one is always `store`. - const trash_inst = trash_block.instructions.pop(); - assert(air_tags[trash_inst] == .store); - assert(trash_inst == sema.air_instructions.len - 1); - sema.air_instructions.len -= 1; + const trash_inst = trash_block.instructions.items[trash_block.instructions.items.len - 1]; + if (air_tags[trash_inst] != .store) { + // no store instruction is generated for zero sized types + assert((try sema.typeHasOnePossibleValue(block, src, pointee_ty)) != null); + } else { + trash_block.instructions.items.len -= 1; + assert(trash_inst == sema.air_instructions.len - 1); + sema.air_instructions.len -= 1; + } } const ptr_ty = try Type.ptr(sema.arena, .{ @@ -5236,6 +5241,22 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr if (lhs_ty.tag() == .anyerror or rhs_ty.tag() == .anyerror) { return Air.Inst.Ref.anyerror_type; } + + if (lhs_ty.castTag(.error_set_inferred)) |payload| { + try sema.resolveInferredErrorSet(payload.data); + // isAnyError might have changed from a false negative to a true positive after resolution. + if (lhs_ty.isAnyError()) { + return Air.Inst.Ref.anyerror_type; + } + } + if (rhs_ty.castTag(.error_set_inferred)) |payload| { + try sema.resolveInferredErrorSet(payload.data); + // isAnyError might have changed from a false negative to a true positive after resolution. + if (rhs_ty.isAnyError()) { + return Air.Inst.Ref.anyerror_type; + } + } + // Resolve both error sets now. const lhs_names = lhs_ty.errorSetNames(); const rhs_names = rhs_ty.errorSetNames(); @@ -6809,6 +6830,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError } } + if (operand_ty.castTag(.error_set_inferred)) |inferred| { + try sema.resolveInferredErrorSet(inferred.data); + } + if (operand_ty.isAnyError()) { if (special_prong != .@"else") { return sema.fail( @@ -14597,6 +14622,12 @@ fn elemPtr( }, .Array => return sema.elemPtrArray(block, array_ptr_src, array_ptr, elem_index, elem_index_src), .Vector => return sema.fail(block, src, "TODO implement Sema for elemPtr for vector", .{}), + .Struct => { + // Tuple field access. + const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index); + const index = @intCast(u32, index_val.toUnsignedInt()); + return sema.tupleFieldPtr(block, array_ptr, index, src, elem_index_src); + }, else => unreachable, } } @@ -14673,6 +14704,45 @@ fn elemVal( } } +fn tupleFieldPtr( + sema: *Sema, + block: *Block, + tuple_ptr: Air.Inst.Ref, + field_index: u32, + tuple_src: LazySrcLoc, + field_index_src: LazySrcLoc, +) CompileError!Air.Inst.Ref { + const tuple_ptr_ty = sema.typeOf(tuple_ptr); + const tuple_ty = tuple_ptr_ty.childType(); + const tuple_info = tuple_ty.castTag(.tuple).?.data; + + if (field_index > tuple_info.types.len) { + return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{ + field_index, tuple_info.types.len, + }); + } + + const field_ty = tuple_info.types[field_index]; + const ptr_field_ty = try Type.ptr(sema.arena, .{ + .pointee_type = field_ty, + .mutable = tuple_ptr_ty.ptrIsMutable(), + .@"addrspace" = tuple_ptr_ty.ptrAddressSpace(), + }); + + if (try sema.resolveMaybeUndefVal(block, tuple_src, tuple_ptr)) |tuple_ptr_val| { + return sema.addConstant( + ptr_field_ty, + try Value.Tag.field_ptr.create(sema.arena, .{ + .container_ptr = tuple_ptr_val, + .field_index = field_index, + }), + ); + } + + try sema.requireRuntimeBlock(block, tuple_src); + return block.addStructFieldPtr(tuple_ptr, field_index, ptr_field_ty); +} + fn tupleField( sema: *Sema, block: *Block, @@ -15273,9 +15343,8 @@ fn coerceInMemoryAllowedErrorSets( return .no_match; } - var it = src_data.errors.keyIterator(); - while (it.next()) |name_ptr| { - if (!dest_ty.errorSetHasField(name_ptr.*)) { + for (src_data.errors.keys()) |key| { + if (!dest_ty.errorSetHasField(key)) { return .no_match; } } @@ -17525,9 +17594,8 @@ fn resolveInferredErrorSet(sema: *Sema, inferred_error_set: *Module.Fn.InferredE try sema.ensureDeclAnalyzed(decl); // To ensure that all dependencies are properly added to the set. try sema.resolveInferredErrorSet(other_error_set_ptr.*); - var error_it = other_error_set_ptr.*.errors.keyIterator(); - while (error_it.next()) |entry| { - try inferred_error_set.errors.put(sema.gpa, entry.*, {}); + for (other_error_set_ptr.*.errors.keys()) |key| { + try inferred_error_set.errors.put(sema.gpa, key, {}); } if (other_error_set_ptr.*.is_anyerror) inferred_error_set.is_anyerror = true; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 51bb713ed5..bc5f5ca7c7 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -4025,7 +4025,7 @@ pub const FuncGen = struct { if (self.liveness.isUnused(inst)) return null; const ptr_ty = self.air.typeOfIndex(inst); const ret_ty = ptr_ty.childType(); - if (!ret_ty.isFnOrHasRuntimeBits()) return null; + if (!ret_ty.isFnOrHasRuntimeBits()) return self.dg.lowerPtrToVoid(ptr_ty); if (self.ret_ptr) |ret_ptr| return ret_ptr; const ret_llvm_ty = try self.dg.llvmType(ret_ty); const target = self.dg.module.getTarget(); @@ -4845,6 +4845,7 @@ pub const FuncGen = struct { struct_ptr_ty: Type, field_index: u32, ) !?*const llvm.Value { + if (self.liveness.isUnused(inst)) return null; const struct_ty = struct_ptr_ty.childType(); switch (struct_ty.zigTypeTag()) { .Struct => switch (struct_ty.containerLayout()) { diff --git a/src/type.zig b/src/type.zig index 581465c51a..ccf1b37471 100644 --- a/src/type.zig +++ b/src/type.zig @@ -3878,6 +3878,12 @@ pub const Type = extern union { }, .error_set_merged => ty.castTag(.error_set_merged).?.data.keys(), .error_set => ty.castTag(.error_set).?.data.names.keys(), + .error_set_inferred => { + const inferred_error_set = ty.castTag(.error_set_inferred).?.data; + assert(inferred_error_set.is_resolved); + assert(!inferred_error_set.is_anyerror); + return inferred_error_set.errors.keys(); + }, else => unreachable, }; } diff --git a/test/behavior.zig b/test/behavior.zig index 2e27563afc..76a7c55977 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -132,6 +132,7 @@ test { _ = @import("behavior/bugs/3384.zig"); _ = @import("behavior/bugs/3742.zig"); _ = @import("behavior/bugs/5398.zig"); + _ = @import("behavior/bugs/5487.zig"); _ = @import("behavior/struct_contains_null_ptr_itself.zig"); _ = @import("behavior/switch_prong_err_enum.zig"); _ = @import("behavior/switch_prong_implicit_cast.zig"); @@ -153,7 +154,6 @@ test { _ = @import("behavior/bugs/1851.zig"); _ = @import("behavior/bugs/3779.zig"); _ = @import("behavior/bugs/5413.zig"); - _ = @import("behavior/bugs/5487.zig"); _ = @import("behavior/bugs/6456.zig"); _ = @import("behavior/bugs/6781.zig"); _ = @import("behavior/bugs/7003.zig");