From f43ea43ac920d3fbd629175e4e7fbe4309c6eab5 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 29 Jul 2022 10:30:10 +0300 Subject: [PATCH 1/5] stage2: fix hashing of struct values Closes #12279 --- src/value.zig | 18 +++--------------- test/behavior/tuple.zig | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/value.zig b/src/value.zig index 46624a822d..0d0be76542 100644 --- a/src/value.zig +++ b/src/value.zig @@ -2292,25 +2292,13 @@ pub const Value = extern union { } }, .Struct => { - if (ty.isTupleOrAnonStruct()) { - const fields = ty.tupleFields(); - for (fields.values) |field_val, i| { - field_val.hash(fields.types[i], hasher, mod); - } - return; - } - const fields = ty.structFields().values(); - if (fields.len == 0) return; switch (val.tag()) { - .empty_struct_value => { - for (fields) |field| { - field.default_val.hash(field.ty, hasher, mod); - } - }, + .empty_struct_value => {}, .aggregate => { const field_values = val.castTag(.aggregate).?.data; for (field_values) |field_val, i| { - field_val.hash(fields[i].ty, hasher, mod); + const field_ty = ty.structFieldType(i); + field_val.hash(field_ty, hasher, mod); } }, else => unreachable, diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index 2442ae3629..4c43ef6be6 100644 --- a/test/behavior/tuple.zig +++ b/test/behavior/tuple.zig @@ -255,3 +255,23 @@ test "initializing anon struct with mixed comptime-runtime fields" { var a: T = .{ .foo = -1234, .bar = x + 1 }; _ = a; } + +test "tuple in tuple passed to generic function" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + + const S = struct { + fn pair(x: f32, y: f32) std.meta.Tuple(&.{ f32, f32 }) { + return .{ x, y }; + } + + fn foo(x: anytype) !void { + try expect(x[0][0] == 1.5); + try expect(x[0][1] == 2.5); + } + }; + const x = comptime S.pair(1.5, 2.5); + try S.foo(.{x}); +} From 17622b9db14cb1d8dd600b21f60c8a1041e5b0e1 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 29 Jul 2022 11:55:53 +0300 Subject: [PATCH 2/5] Sema: implement `@Type` for functions Closes #12280 --- src/Sema.zig | 194 +++++++++++++++++- src/value.zig | 13 ++ .../reify_type.Fn_with_is_generic_true.zig | 4 +- ...th_is_var_args_true_and_non-C_callconv.zig | 4 +- .../reify_type.Fn_with_return_type_null.zig | 4 +- ...austive_enum_with_non-integer_tag_type.zig | 4 +- ...xhaustive_enum_with_undefined_tag_type.zig | 4 +- ...e_for_exhaustive_enum_with_zero_fields.zig | 4 +- ...for_tagged_union_with_extra_enum_field.zig | 6 +- ...or_tagged_union_with_extra_union_field.zig | 6 +- .../reify_type_for_union_with_zero_fields.zig | 4 +- .../reify_type_union_payload_is_undefined.zig | 4 +- .../obj => }/reify_type_with_Type.Int.zig | 6 +- .../obj => }/reify_type_with_undefined.zig | 6 +- ...ype.Pointer_with_invalid_address_space.zig | 0 ...eify_type_with_non-constant_expression.zig | 0 16 files changed, 226 insertions(+), 37 deletions(-) rename test/cases/compile_errors/{stage1/obj => }/reify_type.Fn_with_is_generic_true.zig (76%) rename test/cases/compile_errors/{stage1/obj => }/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig (74%) rename test/cases/compile_errors/{stage1/obj => }/reify_type.Fn_with_return_type_null.zig (75%) rename test/cases/compile_errors/{stage1/obj => }/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig (72%) rename test/cases/compile_errors/{stage1/obj => }/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig (73%) rename test/cases/compile_errors/{stage1/obj => }/reify_type_for_exhaustive_enum_with_zero_fields.zig (77%) rename test/cases/compile_errors/{stage1/obj => }/reify_type_for_tagged_union_with_extra_enum_field.zig (83%) rename test/cases/compile_errors/{stage1/obj => }/reify_type_for_tagged_union_with_extra_union_field.zig (87%) rename test/cases/compile_errors/{stage1/obj => }/reify_type_for_union_with_zero_fields.zig (75%) rename test/cases/compile_errors/{stage1/obj => }/reify_type_union_payload_is_undefined.zig (51%) rename test/cases/compile_errors/{stage1/obj => }/reify_type_with_Type.Int.zig (53%) rename test/cases/compile_errors/{stage1/obj => }/reify_type_with_undefined.zig (64%) rename test/cases/compile_errors/stage1/{obj => }/reify_type.Pointer_with_invalid_address_space.zig (100%) rename test/cases/compile_errors/stage1/{obj => }/reify_type_with_non-constant_expression.zig (100%) diff --git a/src/Sema.zig b/src/Sema.zig index 59b312e000..705fba9b92 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -15759,6 +15759,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I const tag_ty = type_info_ty.unionTagType().?; const target = mod.getTarget(); const tag_index = tag_ty.enumTagFieldIndex(union_val.tag, mod).?; + if (union_val.val.anyUndef()) return sema.failWithUseOfUndef(block, src); switch (@intToEnum(std.builtin.TypeId, tag_index)) { .Type => return Air.Inst.Ref.type_type, .Void => return Air.Inst.Ref.void_type, @@ -15828,7 +15829,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I const is_allowzero_val = struct_val[6]; const sentinel_val = struct_val[7]; - const abi_align = @intCast(u29, alignment_val.toUnsignedInt(target)); // TODO: Validate this value. + if (!try sema.intFitsInType(block, src, alignment_val, Type.u32, null)) { + return sema.fail(block, src, "alignment must fit in 'u32'", .{}); + } + const abi_align = @intCast(u29, alignment_val.toUnsignedInt(target)); var buffer: Value.ToTypeBuffer = undefined; const unresolved_elem_ty = child_val.toType(&buffer); @@ -15855,6 +15859,39 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I actual_sentinel = (try sema.pointerDeref(block, src, sentinel_ptr_val, ptr_ty)).?; } + if (elem_ty.zigTypeTag() == .NoReturn) { + return sema.fail(block, src, "pointer to noreturn not allowed", .{}); + } else if (elem_ty.zigTypeTag() == .Fn) { + if (ptr_size != .One) { + return sema.fail(block, src, "function pointers must be single pointers", .{}); + } + const fn_align = elem_ty.fnInfo().alignment; + if (abi_align != 0 and fn_align != 0 and + abi_align != fn_align) + { + return sema.fail(block, src, "function pointer alignment disagrees with function alignment", .{}); + } + } else if (ptr_size == .Many and elem_ty.zigTypeTag() == .Opaque) { + return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{}); + } else if (ptr_size == .C) { + if (!(try sema.validateExternType(elem_ty, .other))) { + const msg = msg: { + const msg = try sema.errMsg(block, src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)}); + errdefer msg.destroy(sema.gpa); + + const src_decl = sema.mod.declPtr(block.src_decl); + try sema.explainWhyTypeIsNotExtern(block, src, msg, src.toSrcLoc(src_decl), elem_ty, .other); + + try sema.addDeclaredHereNote(msg, elem_ty); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(block, msg); + } + if (elem_ty.zigTypeTag() == .Opaque) { + return sema.fail(block, src, "C pointers cannot point to opaque types", .{}); + } + } + const ty = try Type.ptr(sema.arena, mod, .{ .size = ptr_size, .mutable = !is_const_val.toBool(), @@ -15915,6 +15952,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I const error_set_ty = try error_set_val.toType(&buffer).copy(sema.arena); const payload_ty = try payload_val.toType(&buffer).copy(sema.arena); + if (error_set_ty.zigTypeTag() != .ErrorSet) { + return sema.fail(block, src, "Type.ErrorUnion.error_set must be an error set type", .{}); + } + const ty = try Type.Tag.error_union.create(sema.arena, .{ .error_set = error_set_ty, .payload = payload_ty, @@ -15928,7 +15969,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I const decl_index = slice_val.ptr.pointerDecl().?; try sema.ensureDeclAnalyzed(decl_index); const decl = mod.declPtr(decl_index); - const array_val = decl.val.castTag(.aggregate).?.data; + const array_val: []Value = if (decl.val.castTag(.aggregate)) |some| some.data else &.{}; var names: Module.ErrorSet.NameMap = .{}; try names.ensureUnusedCapacity(sema.arena, array_val.len); @@ -15940,7 +15981,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I const name_str = try name_val.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, sema.mod); const kv = try mod.getErrorValue(name_str); - names.putAssumeCapacityNoClobber(kv.key, {}); + const gop = names.getOrPutAssumeCapacity(kv.key); + if (gop.found_existing) { + return sema.fail(block, src, "duplicate error '{s}'", .{name_str}); + } } // names must be sorted @@ -16022,13 +16066,9 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I new_decl.owns_tv = true; errdefer mod.abortAnonDecl(new_decl_index); - // Enum tag type - var buffer: Value.ToTypeBuffer = undefined; - const int_tag_ty = try tag_type_val.toType(&buffer).copy(new_decl_arena_allocator); - enum_obj.* = .{ .owner_decl = new_decl_index, - .tag_ty = int_tag_ty, + .tag_ty = Type.@"null", .tag_ty_inferred = false, .fields = .{}, .values = .{}, @@ -16040,6 +16080,15 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I }, }; + // Enum tag type + var buffer: Value.ToTypeBuffer = undefined; + const int_tag_ty = try tag_type_val.toType(&buffer).copy(new_decl_arena_allocator); + + if (int_tag_ty.zigTypeTag() != .Int) { + return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{}); + } + enum_obj.tag_ty = int_tag_ty; + // Fields const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); if (fields_len > 0) { @@ -16077,6 +16126,8 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I .mod = mod, }); } + } else { + return sema.fail(block, src, "enums must have at least one field", .{}); } try new_decl.finalizeNewArena(&new_decl_arena); @@ -16186,11 +16237,17 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I }; // Tag type + var tag_ty_field_names: ?Module.EnumFull.NameMap = null; var enum_field_names: ?*Module.EnumNumbered.NameMap = null; const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); if (tag_type_val.optionalValue()) |payload_val| { var buffer: Value.ToTypeBuffer = undefined; union_obj.tag_ty = try payload_val.toType(&buffer).copy(new_decl_arena_allocator); + + if (union_obj.tag_ty.zigTypeTag() != .Enum) { + return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}); + } + tag_ty_field_names = try union_obj.tag_ty.enumFields().clone(sema.arena); } else { union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, fields_len, null); enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields; @@ -16222,6 +16279,19 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I set.putAssumeCapacity(field_name, {}); } + if (tag_ty_field_names) |*names| { + const enum_has_field = names.orderedRemove(field_name); + if (!enum_has_field) { + const msg = msg: { + const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) }); + errdefer msg.destroy(sema.gpa); + try sema.addDeclaredHereNote(msg, union_obj.tag_ty); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(block, msg); + } + } + const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); if (gop.found_existing) { // TODO: better source location @@ -16234,12 +16304,108 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)), }; } + } else { + return sema.fail(block, src, "unions must have at least one field", .{}); + } + + if (tag_ty_field_names) |names| { + if (names.count() > 0) { + const msg = msg: { + const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{}); + errdefer msg.destroy(sema.gpa); + + const enum_ty = union_obj.tag_ty; + for (names.keys()) |field_name| { + const field_index = enum_ty.enumFieldIndex(field_name).?; + try sema.addFieldErrNote(block, enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name}); + } + try sema.addDeclaredHereNote(msg, union_obj.tag_ty); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(block, msg); + } } try new_decl.finalizeNewArena(&new_decl_arena); return sema.analyzeDeclVal(block, src, new_decl_index); }, - .Fn => return sema.fail(block, src, "TODO: Sema.zirReify for Fn", .{}), + .Fn => { + const struct_val = union_val.val.castTag(.aggregate).?.data; + // TODO use reflection instead of magic numbers here + // calling_convention: CallingConvention, + const cc = struct_val[0].toEnum(std.builtin.CallingConvention); + // alignment: comptime_int, + const alignment_val = struct_val[1]; + // is_generic: bool, + const is_generic = struct_val[2].toBool(); + // is_var_args: bool, + const is_var_args = struct_val[3].toBool(); + // return_type: ?type, + const return_type_val = struct_val[4]; + // args: []const Param, + const args_val = struct_val[5]; + + if (is_generic) { + return sema.fail(block, src, "Type.Fn.is_generic must be false for @Type", .{}); + } + + if (is_var_args and cc != .C) { + return sema.fail(block, src, "varargs functions must have C calling convention", .{}); + } + + const alignment = @intCast(u29, alignment_val.toUnsignedInt(target)); // TODO: Validate this value. + var buf: Value.ToTypeBuffer = undefined; + + const args: []Value = if (args_val.castTag(.aggregate)) |some| some.data else &.{}; + var param_types = try sema.arena.alloc(Type, args.len); + var comptime_params = try sema.arena.alloc(bool, args.len); + var noalias_bits: u32 = 0; + for (args) |arg, i| { + const arg_val = arg.castTag(.aggregate).?.data; + // TODO use reflection instead of magic numbers here + // is_generic: bool, + const arg_is_generic = arg_val[0].toBool(); + // is_noalias: bool, + const arg_is_noalias = arg_val[1].toBool(); + // arg_type: ?type, + const param_type_val = arg_val[2]; + + if (arg_is_generic) { + return sema.fail(block, src, "Type.Fn.Param.is_generic must be false for @Type", .{}); + } + + if (arg_is_noalias) { + noalias_bits = @as(u32, 1) << (std.math.cast(u5, i) orelse + return sema.fail(block, src, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{})); + } + + const param_type = param_type_val.optionalValue() orelse + return sema.fail(block, src, "Type.Fn.Param.arg_type must be non-null for @Type", .{}); + + param_types[i] = try param_type.toType(&buf).copy(sema.arena); + } + + const return_type = return_type_val.optionalValue() orelse + return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); + + var fn_info = Type.Payload.Function.Data{ + .param_types = param_types, + .comptime_params = comptime_params.ptr, + .noalias_bits = noalias_bits, + .return_type = try return_type.toType(&buf).copy(sema.arena), + .alignment = alignment, + .cc = cc, + .is_var_args = is_var_args, + .is_generic = false, + .align_is_generic = false, + .cc_is_generic = false, + .section_is_generic = false, + .addrspace_is_generic = false, + }; + + const ty = try Type.Tag.function.create(sema.arena, fn_info); + return sema.addType(ty); + }, .BoundFn => @panic("TODO delete BoundFn from the language"), .Frame => @panic("TODO implement https://github.com/ziglang/zig/issues/10710"), } @@ -16382,6 +16548,11 @@ fn reifyStruct( // alignment: comptime_int, const alignment_val = field_struct_val[4]; + if (!try sema.intFitsInType(block, src, alignment_val, Type.u32, null)) { + return sema.fail(block, src, "alignment must fit in 'u32'", .{}); + } + const abi_align = @intCast(u29, alignment_val.toUnsignedInt(target)); + const field_name = try name_val.toAllocatedBytes( Type.initTag(.const_slice_u8), new_decl_arena_allocator, @@ -16405,7 +16576,7 @@ fn reifyStruct( var buffer: Value.ToTypeBuffer = undefined; gop.value_ptr.* = .{ .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator), - .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)), + .abi_align = abi_align, .default_val = default_val, .is_comptime = is_comptime_val.toBool(), .offset = undefined, @@ -27314,7 +27485,8 @@ fn enumFieldSrcLoc( .container_decl_arg_trailing, => tree.containerDeclArg(enum_node), - else => unreachable, + // Container was constructed with `@Type`. + else => return LazySrcLoc.nodeOffset(node_offset), }; var it_index: usize = 0; for (container_decl.ast.members) |member_node| { diff --git a/src/value.zig b/src/value.zig index 0d0be76542..3f3a2df4c3 100644 --- a/src/value.zig +++ b/src/value.zig @@ -2766,6 +2766,19 @@ pub const Value = extern union { return self.isUndef(); } + /// Returns true if any value contained in `self` is undefined. + /// TODO: check for cases such as array that is not marked undef but all the element + /// values are marked undef, or struct that is not marked undef but all fields are marked + /// undef, etc. + pub fn anyUndef(self: Value) bool { + if (self.castTag(.aggregate)) |aggregate| { + for (aggregate.data) |val| { + if (val.anyUndef()) return true; + } + } + return self.isUndef(); + } + /// Asserts the value is not undefined and not unreachable. /// Integer value 0 is considered null because of C pointers. pub fn isNull(self: Value) bool { diff --git a/test/cases/compile_errors/stage1/obj/reify_type.Fn_with_is_generic_true.zig b/test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig similarity index 76% rename from test/cases/compile_errors/stage1/obj/reify_type.Fn_with_is_generic_true.zig rename to test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig index f2849b5eb4..cf80c9f4ba 100644 --- a/test/cases/compile_errors/stage1/obj/reify_type.Fn_with_is_generic_true.zig +++ b/test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig @@ -11,7 +11,7 @@ const Foo = @Type(.{ comptime { _ = Foo; } // error -// backend=stage1 +// backend=stage2 // target=native // -// tmp.zig:1:20: error: Type.Fn.is_generic must be false for @Type +// :1:13: error: Type.Fn.is_generic must be false for @Type diff --git a/test/cases/compile_errors/stage1/obj/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig b/test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig similarity index 74% rename from test/cases/compile_errors/stage1/obj/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig rename to test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig index 4d449e9eb9..8328ee9b97 100644 --- a/test/cases/compile_errors/stage1/obj/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig +++ b/test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig @@ -11,7 +11,7 @@ const Foo = @Type(.{ comptime { _ = Foo; } // error -// backend=stage1 +// backend=stage2 // target=native // -// tmp.zig:1:20: error: varargs functions must have C calling convention +// :1:13: error: varargs functions must have C calling convention diff --git a/test/cases/compile_errors/stage1/obj/reify_type.Fn_with_return_type_null.zig b/test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig similarity index 75% rename from test/cases/compile_errors/stage1/obj/reify_type.Fn_with_return_type_null.zig rename to test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig index 98cbc37d41..f6587dcd7e 100644 --- a/test/cases/compile_errors/stage1/obj/reify_type.Fn_with_return_type_null.zig +++ b/test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig @@ -11,7 +11,7 @@ const Foo = @Type(.{ comptime { _ = Foo; } // error -// backend=stage1 +// backend=stage2 // target=native // -// tmp.zig:1:20: error: Type.Fn.return_type must be non-null for @Type +// :1:13: error: Type.Fn.return_type must be non-null for @Type diff --git a/test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig b/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig similarity index 72% rename from test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig rename to test/cases/compile_errors/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig index 56d05578be..e72b783d83 100644 --- a/test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig +++ b/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig @@ -12,7 +12,7 @@ export fn entry() void { } // error -// backend=stage1 +// backend=stage2 // target=native // -// tmp.zig:1:20: error: Type.Enum.tag_type must be an integer type, not 'bool' +// :1:13: error: Type.Enum.tag_type must be an integer type diff --git a/test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig b/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig similarity index 73% rename from test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig rename to test/cases/compile_errors/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig index e6454d2ee5..1c237a17bd 100644 --- a/test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig +++ b/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig @@ -12,7 +12,7 @@ export fn entry() void { } // error -// backend=stage1 +// backend=stage2 // target=native // -// tmp.zig:1:20: error: use of undefined value here causes undefined behavior +// :1:13: error: use of undefined value here causes undefined behavior diff --git a/test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_zero_fields.zig b/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_zero_fields.zig similarity index 77% rename from test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_zero_fields.zig rename to test/cases/compile_errors/reify_type_for_exhaustive_enum_with_zero_fields.zig index d3ce70c1b0..44876e938a 100644 --- a/test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_zero_fields.zig +++ b/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_zero_fields.zig @@ -12,7 +12,7 @@ export fn entry() void { } // error -// backend=stage1 +// backend=stage2 // target=native // -// tmp.zig:1:20: error: enums must have 1 or more fields +// :1:13: error: enums must have at least one field diff --git a/test/cases/compile_errors/stage1/obj/reify_type_for_tagged_union_with_extra_enum_field.zig b/test/cases/compile_errors/reify_type_for_tagged_union_with_extra_enum_field.zig similarity index 83% rename from test/cases/compile_errors/stage1/obj/reify_type_for_tagged_union_with_extra_enum_field.zig rename to test/cases/compile_errors/reify_type_for_tagged_union_with_extra_enum_field.zig index 0c56cb91ea..ccd0000494 100644 --- a/test/cases/compile_errors/stage1/obj/reify_type_for_tagged_union_with_extra_enum_field.zig +++ b/test/cases/compile_errors/reify_type_for_tagged_union_with_extra_enum_field.zig @@ -28,7 +28,9 @@ export fn entry() void { } // error -// backend=stage1 +// backend=stage2 // target=native // -// tmp.zig:14:23: error: enum field missing: 'arst' +// :14:16: error: enum field(s) missing in union +// :1:13: note: field 'arst' missing, declared here +// :1:13: note: enum declared here diff --git a/test/cases/compile_errors/stage1/obj/reify_type_for_tagged_union_with_extra_union_field.zig b/test/cases/compile_errors/reify_type_for_tagged_union_with_extra_union_field.zig similarity index 87% rename from test/cases/compile_errors/stage1/obj/reify_type_for_tagged_union_with_extra_union_field.zig rename to test/cases/compile_errors/reify_type_for_tagged_union_with_extra_union_field.zig index 63cf1f178e..414bf2ce5e 100644 --- a/test/cases/compile_errors/stage1/obj/reify_type_for_tagged_union_with_extra_union_field.zig +++ b/test/cases/compile_errors/reify_type_for_tagged_union_with_extra_union_field.zig @@ -28,8 +28,8 @@ export fn entry() void { } // error -// backend=stage1 +// backend=stage2 // target=native // -// tmp.zig:13:23: error: enum field not found: 'arst' -// tmp.zig:1:20: note: enum declared here +// :13:16: error: no field named 'arst' in enum 'tmp.Tag__enum_264' +// :1:13: note: enum declared here diff --git a/test/cases/compile_errors/stage1/obj/reify_type_for_union_with_zero_fields.zig b/test/cases/compile_errors/reify_type_for_union_with_zero_fields.zig similarity index 75% rename from test/cases/compile_errors/stage1/obj/reify_type_for_union_with_zero_fields.zig rename to test/cases/compile_errors/reify_type_for_union_with_zero_fields.zig index 578f902697..0b4f395c81 100644 --- a/test/cases/compile_errors/stage1/obj/reify_type_for_union_with_zero_fields.zig +++ b/test/cases/compile_errors/reify_type_for_union_with_zero_fields.zig @@ -11,7 +11,7 @@ export fn entry() void { } // error -// backend=stage1 +// backend=stage2 // target=native // -// tmp.zig:1:25: error: unions must have 1 or more fields +// :1:18: error: unions must have at least one field diff --git a/test/cases/compile_errors/stage1/obj/reify_type_union_payload_is_undefined.zig b/test/cases/compile_errors/reify_type_union_payload_is_undefined.zig similarity index 51% rename from test/cases/compile_errors/stage1/obj/reify_type_union_payload_is_undefined.zig rename to test/cases/compile_errors/reify_type_union_payload_is_undefined.zig index 47be31c711..410bb92658 100644 --- a/test/cases/compile_errors/stage1/obj/reify_type_union_payload_is_undefined.zig +++ b/test/cases/compile_errors/reify_type_union_payload_is_undefined.zig @@ -4,7 +4,7 @@ const Foo = @Type(.{ comptime { _ = Foo; } // error -// backend=stage1 +// backend=stage2 // target=native // -// tmp.zig:1:20: error: use of undefined value here causes undefined behavior +// :1:13: error: use of undefined value here causes undefined behavior diff --git a/test/cases/compile_errors/stage1/obj/reify_type_with_Type.Int.zig b/test/cases/compile_errors/reify_type_with_Type.Int.zig similarity index 53% rename from test/cases/compile_errors/stage1/obj/reify_type_with_Type.Int.zig rename to test/cases/compile_errors/reify_type_with_Type.Int.zig index 116bd86e0f..bd98912a03 100644 --- a/test/cases/compile_errors/stage1/obj/reify_type_with_Type.Int.zig +++ b/test/cases/compile_errors/reify_type_with_Type.Int.zig @@ -7,7 +7,9 @@ export fn entry() void { } // error -// backend=stage1 +// backend=stage2 // target=native // -// tmp.zig:3:31: error: expected type 'std.builtin.Type', found 'std.builtin.Type.Int' +// :3:31: error: expected type 'builtin.Type', found 'builtin.Type.Int' +// :?:?: note: struct declared here +// :?:?: note: union declared here diff --git a/test/cases/compile_errors/stage1/obj/reify_type_with_undefined.zig b/test/cases/compile_errors/reify_type_with_undefined.zig similarity index 64% rename from test/cases/compile_errors/stage1/obj/reify_type_with_undefined.zig rename to test/cases/compile_errors/reify_type_with_undefined.zig index 1de93ccdf6..e5753fa420 100644 --- a/test/cases/compile_errors/stage1/obj/reify_type_with_undefined.zig +++ b/test/cases/compile_errors/reify_type_with_undefined.zig @@ -13,8 +13,8 @@ comptime { } // error -// backend=stage1 +// backend=stage2 // target=native // -// tmp.zig:2:16: error: use of undefined value here causes undefined behavior -// tmp.zig:5:16: error: use of undefined value here causes undefined behavior +// :2:9: error: use of undefined value here causes undefined behavior +// :5:9: error: use of undefined value here causes undefined behavior diff --git a/test/cases/compile_errors/stage1/obj/reify_type.Pointer_with_invalid_address_space.zig b/test/cases/compile_errors/stage1/reify_type.Pointer_with_invalid_address_space.zig similarity index 100% rename from test/cases/compile_errors/stage1/obj/reify_type.Pointer_with_invalid_address_space.zig rename to test/cases/compile_errors/stage1/reify_type.Pointer_with_invalid_address_space.zig diff --git a/test/cases/compile_errors/stage1/obj/reify_type_with_non-constant_expression.zig b/test/cases/compile_errors/stage1/reify_type_with_non-constant_expression.zig similarity index 100% rename from test/cases/compile_errors/stage1/obj/reify_type_with_non-constant_expression.zig rename to test/cases/compile_errors/stage1/reify_type_with_non-constant_expression.zig From 4758752e5d64a3e36086483de569188f62519bac Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 29 Jul 2022 12:30:27 +0300 Subject: [PATCH 3/5] Sema: implement coercion from tuples to tuples Closes #12242 --- src/Sema.zig | 107 +++++++++++++++++- test/behavior/tuple.zig | 15 +++ ...type_mismatch_with_tuple_concatenation.zig | 11 -- ...type_mismatch_with_tuple_concatenation.zig | 10 ++ 4 files changed, 130 insertions(+), 13 deletions(-) delete mode 100644 test/cases/compile_errors/stage1/test/type_mismatch_with_tuple_concatenation.zig create mode 100644 test/cases/compile_errors/type_mismatch_with_tuple_concatenation.zig diff --git a/src/Sema.zig b/src/Sema.zig index 705fba9b92..31a0e41d95 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -24528,8 +24528,7 @@ fn coerceTupleToStruct( const struct_ty = try sema.resolveTypeFields(block, dest_ty_src, dest_ty); if (struct_ty.isTupleOrAnonStruct()) { - // NOTE remember to handle comptime fields - return sema.fail(block, dest_ty_src, "TODO: implement coercion from tuples to tuples", .{}); + return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src); } const fields = struct_ty.structFields(); @@ -24612,6 +24611,110 @@ fn coerceTupleToStruct( ); } +fn coerceTupleToTuple( + sema: *Sema, + block: *Block, + tuple_ty: Type, + inst: Air.Inst.Ref, + inst_src: LazySrcLoc, +) !Air.Inst.Ref { + const field_count = tuple_ty.structFieldCount(); + const field_vals = try sema.arena.alloc(Value, field_count); + const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); + mem.set(Air.Inst.Ref, field_refs, .none); + + const inst_ty = sema.typeOf(inst); + const tuple = inst_ty.tupleFields(); + var runtime_src: ?LazySrcLoc = null; + for (tuple.types) |_, i_usize| { + const i = @intCast(u32, i_usize); + const field_src = inst_src; // TODO better source location + const field_name = if (inst_ty.castTag(.anon_struct)) |payload| + payload.data.names[i] + else + try std.fmt.allocPrint(sema.arena, "{d}", .{i}); + + if (mem.eql(u8, field_name, "len")) { + return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{}); + } + + const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src); + + const field_ty = tuple_ty.structFieldType(i); + const default_val = tuple_ty.structFieldDefaultValue(i); + const elem_ref = try tupleField(sema, block, inst_src, inst, field_src, i); + const coerced = try sema.coerce(block, field_ty, elem_ref, field_src); + field_refs[field_index] = coerced; + if (default_val.tag() != .unreachable_value) { + const init_val = (try sema.resolveMaybeUndefVal(block, field_src, coerced)) orelse { + return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime known"); + }; + + if (!init_val.eql(default_val, field_ty, sema.mod)) { + return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, i); + } + } + if (runtime_src == null) { + if (try sema.resolveMaybeUndefVal(block, field_src, coerced)) |field_val| { + field_vals[field_index] = field_val; + } else { + runtime_src = field_src; + } + } + } + + // Populate default field values and report errors for missing fields. + var root_msg: ?*Module.ErrorMsg = null; + + for (field_refs) |*field_ref, i| { + if (field_ref.* != .none) continue; + + const default_val = tuple_ty.structFieldDefaultValue(i); + const field_ty = tuple_ty.structFieldType(i); + + const field_src = inst_src; // TODO better source location + if (default_val.tag() == .unreachable_value) { + if (tuple_ty.isTuple()) { + const template = "missing tuple field: {d}"; + if (root_msg) |msg| { + try sema.errNote(block, field_src, msg, template, .{i}); + } else { + root_msg = try sema.errMsg(block, field_src, template, .{i}); + } + continue; + } + const template = "missing struct field: {s}"; + const args = .{tuple_ty.structFieldName(i)}; + if (root_msg) |msg| { + try sema.errNote(block, field_src, msg, template, args); + } else { + root_msg = try sema.errMsg(block, field_src, template, args); + } + continue; + } + if (runtime_src == null) { + field_vals[i] = default_val; + } else { + field_ref.* = try sema.addConstant(field_ty, default_val); + } + } + + if (root_msg) |msg| { + try sema.addDeclaredHereNote(msg, tuple_ty); + return sema.failWithOwnedErrorMsg(block, msg); + } + + if (runtime_src) |rs| { + try sema.requireRuntimeBlock(block, inst_src, rs); + return block.addAggregateInit(tuple_ty, field_refs); + } + + return sema.addConstant( + tuple_ty, + try Value.Tag.aggregate.create(sema.arena, field_vals), + ); +} + fn analyzeDeclVal( sema: *Sema, block: *Block, diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index 4c43ef6be6..14297bd61c 100644 --- a/test/behavior/tuple.zig +++ b/test/behavior/tuple.zig @@ -275,3 +275,18 @@ test "tuple in tuple passed to generic function" { const x = comptime S.pair(1.5, 2.5); try S.foo(.{x}); } + +test "coerce tuple to tuple" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + + const T = std.meta.Tuple(&.{u8}); + const S = struct { + fn foo(x: T) !void { + try expect(x[0] == 123); + } + }; + try S.foo(.{123}); +} diff --git a/test/cases/compile_errors/stage1/test/type_mismatch_with_tuple_concatenation.zig b/test/cases/compile_errors/stage1/test/type_mismatch_with_tuple_concatenation.zig deleted file mode 100644 index 5983224676..0000000000 --- a/test/cases/compile_errors/stage1/test/type_mismatch_with_tuple_concatenation.zig +++ /dev/null @@ -1,11 +0,0 @@ -export fn entry() void { - var x = .{}; - x = x ++ .{ 1, 2, 3 }; -} - -// error -// backend=stage1 -// target=native -// is_test=1 -// -// tmp.zig:3:11: error: expected type 'struct:2:14', found 'struct:3:11' diff --git a/test/cases/compile_errors/type_mismatch_with_tuple_concatenation.zig b/test/cases/compile_errors/type_mismatch_with_tuple_concatenation.zig new file mode 100644 index 0000000000..4e9bdfa2e5 --- /dev/null +++ b/test/cases/compile_errors/type_mismatch_with_tuple_concatenation.zig @@ -0,0 +1,10 @@ +export fn entry() void { + var x = .{}; + x = x ++ .{ 1, 2, 3 }; +} + +// error +// backend=stage2 +// target=native +// +// :3:11: error: index '0' out of bounds of tuple '@TypeOf(.{})' From d26d696ee01d3a17d17cde24c8841e7f551ba5f2 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Thu, 28 Jul 2022 22:38:48 +0300 Subject: [PATCH 4/5] parser: require expression after colon in slice expr --- lib/std/zig/parse.zig | 2 +- lib/std/zig/parser_test.zig | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index f3c219cfc6..2a7d2623ef 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -3257,7 +3257,7 @@ const Parser = struct { if (p.eatToken(.ellipsis2)) |_| { const end_expr = try p.parseExpr(); if (p.eatToken(.colon)) |_| { - const sentinel = try p.parseExpr(); + const sentinel = try p.expectExpr(); _ = try p.expectToken(.r_bracket); return p.addNode(.{ .tag = .slice_sentinel, diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 38c2960f31..a74d53f21c 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -5118,6 +5118,14 @@ test "zig fmt: while continue expr" { }); } +test "zig fmt: error for missing sentinel value in sentinel slice" { + try testError( + \\const foo = foo[0..:]; + , &[_]Error{ + .expected_expr, + }); +} + test "zig fmt: error for invalid bit range" { try testError( \\var x: []align(0:0:0)u8 = bar; From 02dc0732604236a57b43b9612d9b0571f06f905a Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Thu, 28 Jul 2022 22:21:49 +0300 Subject: [PATCH 5/5] Sema: check comptime slice sentinel --- src/Sema.zig | 96 ++++++++++++++++--- ...atch_memory_at_target_index_terminated.zig | 23 +++-- ...ch_memory_at_target_index_unterminated.zig | 23 +++-- ...entinel_does_not_match_target-sentinel.zig | 23 +++-- ...e-sentinel_is_out_of_bounds_terminated.zig | 16 ++-- ...sentinel_is_out_of_bounds_unterminated.zig | 16 ++-- .../comptime_slice_of_an_undefined_slice.zig | 4 +- 7 files changed, 146 insertions(+), 55 deletions(-) rename test/cases/compile_errors/{stage1/obj => }/comptime_slice-sentinel_does_not_match_memory_at_target_index_terminated.zig (68%) rename test/cases/compile_errors/{stage1/obj => }/comptime_slice-sentinel_does_not_match_memory_at_target_index_unterminated.zig (68%) rename test/cases/compile_errors/{stage1/obj => }/comptime_slice-sentinel_does_not_match_target-sentinel.zig (68%) rename test/cases/compile_errors/{stage1/obj => }/comptime_slice-sentinel_is_out_of_bounds_terminated.zig (72%) rename test/cases/compile_errors/{stage1/obj => }/comptime_slice-sentinel_is_out_of_bounds_unterminated.zig (72%) rename test/cases/compile_errors/{stage1/obj => }/comptime_slice_of_an_undefined_slice.zig (63%) diff --git a/src/Sema.zig b/src/Sema.zig index 31a0e41d95..a0829d6eb7 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -25150,7 +25150,10 @@ fn analyzeSlice( if (!end_is_len) { const end = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { - if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| { + if (try sema.resolveMaybeUndefVal(block, src, ptr_or_slice)) |slice_val| { + if (slice_val.isUndef()) { + return sema.fail(block, src, "slice of undefined", .{}); + } const has_sentinel = slice_ty.sentinel() != null; var int_payload: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, @@ -25213,8 +25216,8 @@ fn analyzeSlice( }; // requirement: start <= end - if (try sema.resolveDefinedValue(block, src, end)) |end_val| { - if (try sema.resolveDefinedValue(block, src, start)) |start_val| { + if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { + if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| { if (try sema.compare(block, src, start_val, .gt, end_val, Type.usize)) { return sema.fail( block, @@ -25226,6 +25229,45 @@ fn analyzeSlice( }, ); } + if (try sema.resolveMaybeUndefVal(block, ptr_src, new_ptr)) |ptr_val| sentinel_check: { + const expected_sentinel = sentinel orelse break :sentinel_check; + const start_int = start_val.getUnsignedInt(sema.mod.getTarget()).?; + const end_int = end_val.getUnsignedInt(sema.mod.getTarget()).?; + const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int); + + const elem_ptr = try ptr_val.elemPtr(sema.typeOf(new_ptr), sema.arena, sentinel_index, sema.mod); + const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false); + const actual_sentinel = switch (res) { + .runtime_load => break :sentinel_check, + .val => |v| v, + .needed_well_defined => |ty| return sema.fail( + block, + src, + "comptime dereference requires '{}' to have a well-defined layout, but it does not.", + .{ty.fmt(sema.mod)}, + ), + .out_of_bounds => |ty| return sema.fail( + block, + end_src, + "slice end index {d} exceeds bounds of containing decl of type '{}'", + .{ end_int, ty.fmt(sema.mod) }, + ), + }; + + if (!actual_sentinel.eql(expected_sentinel, elem_ty, sema.mod)) { + const msg = msg: { + const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{}); + errdefer msg.destroy(sema.gpa); + try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{ + expected_sentinel.fmtValue(elem_ty, sema.mod), + actual_sentinel.fmtValue(elem_ty, sema.mod), + }); + + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(block, msg); + } + } } } @@ -27866,9 +27908,36 @@ pub fn analyzeAddrspace( /// Returns `null` if the pointer contents cannot be loaded at comptime. fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value { const load_ty = ptr_ty.childType(); + const res = try sema.pointerDerefExtra(block, src, ptr_val, load_ty, true); + switch (res) { + .runtime_load => return null, + .val => |v| return v, + .needed_well_defined => |ty| return sema.fail( + block, + src, + "comptime dereference requires '{}' to have a well-defined layout, but it does not.", + .{ty.fmt(sema.mod)}, + ), + .out_of_bounds => |ty| return sema.fail( + block, + src, + "dereference of '{}' exceeds bounds of containing decl of type '{}'", + .{ ptr_ty.fmt(sema.mod), ty.fmt(sema.mod) }, + ), + } +} + +const DerefResult = union(enum) { + runtime_load, + val: Value, + needed_well_defined: Type, + out_of_bounds: Type, +}; + +fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, load_ty: Type, want_mutable: bool) CompileError!DerefResult { const target = sema.mod.getTarget(); const deref = sema.beginComptimePtrLoad(block, src, ptr_val, load_ty) catch |err| switch (err) { - error.RuntimeLoad => return null, + error.RuntimeLoad => return DerefResult{ .runtime_load = {} }, else => |e| return e, }; @@ -27879,39 +27948,40 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr if (coerce_in_mem_ok) { // We have a Value that lines up in virtual memory exactly with what we want to load, // and it is in-memory coercible to load_ty. It may be returned without modifications. - if (deref.is_mutable) { + if (deref.is_mutable and want_mutable) { // The decl whose value we are obtaining here may be overwritten with // a different value upon further semantic analysis, which would // invalidate this memory. So we must copy here. - return try tv.val.copy(sema.arena); + return DerefResult{ .val = try tv.val.copy(sema.arena) }; } - return tv.val; + return DerefResult{ .val = tv.val }; } } // The type is not in-memory coercible or the direct dereference failed, so it must // be bitcast according to the pointer type we are performing the load through. - if (!load_ty.hasWellDefinedLayout()) - return sema.fail(block, src, "comptime dereference requires '{}' to have a well-defined layout, but it does not.", .{load_ty.fmt(sema.mod)}); + if (!load_ty.hasWellDefinedLayout()) { + return DerefResult{ .needed_well_defined = load_ty }; + } const load_sz = try sema.typeAbiSize(block, src, load_ty); // Try the smaller bit-cast first, since that's more efficient than using the larger `parent` if (deref.pointee) |tv| if (load_sz <= try sema.typeAbiSize(block, src, tv.ty)) - return try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0); + return DerefResult{ .val = try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0) }; // If that fails, try to bit-cast from the largest parent value with a well-defined layout if (deref.parent) |parent| if (load_sz + parent.byte_offset <= try sema.typeAbiSize(block, src, parent.tv.ty)) - return try sema.bitCastVal(block, src, parent.tv.val, parent.tv.ty, load_ty, parent.byte_offset); + return DerefResult{ .val = try sema.bitCastVal(block, src, parent.tv.val, parent.tv.ty, load_ty, parent.byte_offset) }; if (deref.ty_without_well_defined_layout) |bad_ty| { // We got no parent for bit-casting, or the parent we got was too small. Either way, the problem // is that some type we encountered when de-referencing does not have a well-defined layout. - return sema.fail(block, src, "comptime dereference requires '{}' to have a well-defined layout, but it does not.", .{bad_ty.fmt(sema.mod)}); + return DerefResult{ .needed_well_defined = bad_ty }; } else { // If all encountered types had well-defined layouts, the parent is the root decl and it just // wasn't big enough for the load. - return sema.fail(block, src, "dereference of '{}' exceeds bounds of containing decl of type '{}'", .{ ptr_ty.fmt(sema.mod), deref.parent.?.tv.ty.fmt(sema.mod) }); + return DerefResult{ .out_of_bounds = deref.parent.?.tv.ty }; } } diff --git a/test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_does_not_match_memory_at_target_index_terminated.zig b/test/cases/compile_errors/comptime_slice-sentinel_does_not_match_memory_at_target_index_terminated.zig similarity index 68% rename from test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_does_not_match_memory_at_target_index_terminated.zig rename to test/cases/compile_errors/comptime_slice-sentinel_does_not_match_memory_at_target_index_terminated.zig index 598d23a305..ffa21af10a 100644 --- a/test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_does_not_match_memory_at_target_index_terminated.zig +++ b/test/cases/compile_errors/comptime_slice-sentinel_does_not_match_memory_at_target_index_terminated.zig @@ -55,13 +55,20 @@ export fn foo_slice() void { } // error -// backend=stage1 +// backend=stage2 // target=native // -// :4:29: error: slice-sentinel does not match memory at target index -// :12:29: error: slice-sentinel does not match memory at target index -// :20:29: error: slice-sentinel does not match memory at target index -// :28:29: error: slice-sentinel does not match memory at target index -// :36:29: error: slice-sentinel does not match memory at target index -// :44:29: error: slice-sentinel does not match memory at target index -// :52:29: error: slice-sentinel does not match memory at target index +// :4:29: error: value in memory does not match slice sentinel +// :4:29: note: expected '0', found '100' +// :12:29: error: value in memory does not match slice sentinel +// :12:29: note: expected '0', found '100' +// :20:29: error: value in memory does not match slice sentinel +// :20:29: note: expected '0', found '100' +// :28:29: error: value in memory does not match slice sentinel +// :28:29: note: expected '0', found '100' +// :36:29: error: value in memory does not match slice sentinel +// :36:29: note: expected '0', found '100' +// :44:29: error: value in memory does not match slice sentinel +// :44:29: note: expected '0', found '100' +// :52:29: error: value in memory does not match slice sentinel +// :52:29: note: expected '0', found '100' diff --git a/test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_does_not_match_memory_at_target_index_unterminated.zig b/test/cases/compile_errors/comptime_slice-sentinel_does_not_match_memory_at_target_index_unterminated.zig similarity index 68% rename from test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_does_not_match_memory_at_target_index_unterminated.zig rename to test/cases/compile_errors/comptime_slice-sentinel_does_not_match_memory_at_target_index_unterminated.zig index d6b469aaf1..c5bb2d9643 100644 --- a/test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_does_not_match_memory_at_target_index_unterminated.zig +++ b/test/cases/compile_errors/comptime_slice-sentinel_does_not_match_memory_at_target_index_unterminated.zig @@ -55,13 +55,20 @@ export fn foo_slice() void { } // error -// backend=stage1 +// backend=stage2 // target=native // -// :4:29: error: slice-sentinel does not match memory at target index -// :12:29: error: slice-sentinel does not match memory at target index -// :20:29: error: slice-sentinel does not match memory at target index -// :28:29: error: slice-sentinel does not match memory at target index -// :36:29: error: slice-sentinel does not match memory at target index -// :44:29: error: slice-sentinel does not match memory at target index -// :52:29: error: slice-sentinel does not match memory at target index +// :4:29: error: value in memory does not match slice sentinel +// :4:29: note: expected '0', found '100' +// :12:29: error: value in memory does not match slice sentinel +// :12:29: note: expected '0', found '100' +// :20:29: error: value in memory does not match slice sentinel +// :20:29: note: expected '0', found '100' +// :28:29: error: value in memory does not match slice sentinel +// :28:29: note: expected '0', found '100' +// :36:29: error: value in memory does not match slice sentinel +// :36:29: note: expected '0', found '100' +// :44:29: error: value in memory does not match slice sentinel +// :44:29: note: expected '0', found '100' +// :52:29: error: value in memory does not match slice sentinel +// :52:29: note: expected '0', found '100' diff --git a/test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_does_not_match_target-sentinel.zig b/test/cases/compile_errors/comptime_slice-sentinel_does_not_match_target-sentinel.zig similarity index 68% rename from test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_does_not_match_target-sentinel.zig rename to test/cases/compile_errors/comptime_slice-sentinel_does_not_match_target-sentinel.zig index b204cfc684..b574df8833 100644 --- a/test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_does_not_match_target-sentinel.zig +++ b/test/cases/compile_errors/comptime_slice-sentinel_does_not_match_target-sentinel.zig @@ -55,13 +55,20 @@ export fn foo_slice() void { } // error -// backend=stage1 +// backend=stage2 // target=native // -// :4:29: error: slice-sentinel does not match target-sentinel -// :12:29: error: slice-sentinel does not match target-sentinel -// :20:29: error: slice-sentinel does not match target-sentinel -// :28:29: error: slice-sentinel does not match target-sentinel -// :36:29: error: slice-sentinel does not match target-sentinel -// :44:29: error: slice-sentinel does not match target-sentinel -// :52:29: error: slice-sentinel does not match target-sentinel +// :4:29: error: value in memory does not match slice sentinel +// :4:29: note: expected '255', found '0' +// :12:29: error: value in memory does not match slice sentinel +// :12:29: note: expected '255', found '0' +// :20:29: error: value in memory does not match slice sentinel +// :20:29: note: expected '255', found '0' +// :28:29: error: value in memory does not match slice sentinel +// :28:29: note: expected '255', found '0' +// :36:29: error: value in memory does not match slice sentinel +// :36:29: note: expected '255', found '0' +// :44:29: error: value in memory does not match slice sentinel +// :44:29: note: expected '255', found '0' +// :52:29: error: value in memory does not match slice sentinel +// :52:29: note: expected '255', found '0' diff --git a/test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_is_out_of_bounds_terminated.zig b/test/cases/compile_errors/comptime_slice-sentinel_is_out_of_bounds_terminated.zig similarity index 72% rename from test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_is_out_of_bounds_terminated.zig rename to test/cases/compile_errors/comptime_slice-sentinel_is_out_of_bounds_terminated.zig index 82c19126c0..86bd4ce8bb 100644 --- a/test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_is_out_of_bounds_terminated.zig +++ b/test/cases/compile_errors/comptime_slice-sentinel_is_out_of_bounds_terminated.zig @@ -55,13 +55,13 @@ export fn foo_slice() void { } // error -// backend=stage1 +// backend=stage2 // target=native // -// :4:29: error: out of bounds slice -// :12:29: error: out of bounds slice -// :20:29: error: out of bounds slice -// :28:29: error: out of bounds slice -// :36:29: error: out of bounds slice -// :44:29: error: out of bounds slice -// :52:29: error: out of bounds slice +// :4:33: error: slice end index 15 exceeds bounds of containing decl of type '[14:0]u8' +// :12:33: error: slice end index 15 exceeds bounds of containing decl of type '[14:0]u8' +// :20:33: error: slice end index 15 exceeds bounds of containing decl of type '[14:0]u8' +// :28:33: error: slice end index 15 exceeds bounds of containing decl of type '[14:0]u8' +// :36:33: error: slice end index 15 exceeds bounds of containing decl of type '[14:0]u8' +// :44:33: error: slice end index 15 exceeds bounds of containing decl of type '[14:0]u8' +// :52:33: error: end index 15 out of bounds for slice of length 14 diff --git a/test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_is_out_of_bounds_unterminated.zig b/test/cases/compile_errors/comptime_slice-sentinel_is_out_of_bounds_unterminated.zig similarity index 72% rename from test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_is_out_of_bounds_unterminated.zig rename to test/cases/compile_errors/comptime_slice-sentinel_is_out_of_bounds_unterminated.zig index 952b17600a..e1b8a5bc2d 100644 --- a/test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_is_out_of_bounds_unterminated.zig +++ b/test/cases/compile_errors/comptime_slice-sentinel_is_out_of_bounds_unterminated.zig @@ -55,13 +55,13 @@ export fn foo_slice() void { } // error -// backend=stage1 +// backend=stage2 // target=native // -// :4:29: error: slice-sentinel is out of bounds -// :12:29: error: slice-sentinel is out of bounds -// :20:29: error: slice-sentinel is out of bounds -// :28:29: error: slice-sentinel is out of bounds -// :36:29: error: slice-sentinel is out of bounds -// :44:29: error: slice-sentinel is out of bounds -// :52:29: error: slice-sentinel is out of bounds +// :4:33: error: slice end index 14 exceeds bounds of containing decl of type '[14]u8' +// :12:33: error: slice end index 14 exceeds bounds of containing decl of type '[14]u8' +// :20:33: error: slice end index 14 exceeds bounds of containing decl of type '[14]u8' +// :28:33: error: slice end index 14 exceeds bounds of containing decl of type '[14]u8' +// :36:33: error: slice end index 14 exceeds bounds of containing decl of type '[14]u8' +// :44:33: error: slice end index 14 exceeds bounds of containing decl of type '[14]u8' +// :52:33: error: slice end index 14 exceeds bounds of containing decl of type '[14]u8' diff --git a/test/cases/compile_errors/stage1/obj/comptime_slice_of_an_undefined_slice.zig b/test/cases/compile_errors/comptime_slice_of_an_undefined_slice.zig similarity index 63% rename from test/cases/compile_errors/stage1/obj/comptime_slice_of_an_undefined_slice.zig rename to test/cases/compile_errors/comptime_slice_of_an_undefined_slice.zig index 4aa519f41e..d1b22d86b7 100644 --- a/test/cases/compile_errors/stage1/obj/comptime_slice_of_an_undefined_slice.zig +++ b/test/cases/compile_errors/comptime_slice_of_an_undefined_slice.zig @@ -5,7 +5,7 @@ comptime { } // error -// backend=stage1 +// backend=stage2 // target=native // -// tmp.zig:3:14: error: slice of undefined +// :3:14: error: slice of undefined