From f43ea43ac920d3fbd629175e4e7fbe4309c6eab5 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 29 Jul 2022 10:30:10 +0300 Subject: stage2: fix hashing of struct values Closes #12279 --- src/value.zig | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) (limited to 'src/value.zig') 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, -- cgit v1.2.3 From 17622b9db14cb1d8dd600b21f60c8a1041e5b0e1 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 29 Jul 2022 11:55:53 +0300 Subject: Sema: implement `@Type` for functions Closes #12280 --- src/Sema.zig | 194 +++++++++++++++++++-- src/value.zig | 13 ++ .../reify_type.Fn_with_is_generic_true.zig | 17 ++ ...Fn_with_is_var_args_true_and_non-C_callconv.zig | 17 ++ .../reify_type.Fn_with_return_type_null.zig | 17 ++ ...r_exhaustive_enum_with_non-integer_tag_type.zig | 18 ++ ...for_exhaustive_enum_with_undefined_tag_type.zig | 18 ++ ...y_type_for_exhaustive_enum_with_zero_fields.zig | 18 ++ ...type_for_tagged_union_with_extra_enum_field.zig | 36 ++++ ...ype_for_tagged_union_with_extra_union_field.zig | 35 ++++ .../reify_type_for_union_with_zero_fields.zig | 17 ++ .../reify_type_union_payload_is_undefined.zig | 10 ++ .../compile_errors/reify_type_with_Type.Int.zig | 15 ++ .../compile_errors/reify_type_with_undefined.zig | 20 +++ .../obj/reify_type.Fn_with_is_generic_true.zig | 17 -- ...Fn_with_is_var_args_true_and_non-C_callconv.zig | 17 -- .../obj/reify_type.Fn_with_return_type_null.zig | 17 -- ...ify_type.Pointer_with_invalid_address_space.zig | 18 -- ...r_exhaustive_enum_with_non-integer_tag_type.zig | 18 -- ...for_exhaustive_enum_with_undefined_tag_type.zig | 18 -- ...y_type_for_exhaustive_enum_with_zero_fields.zig | 18 -- ...type_for_tagged_union_with_extra_enum_field.zig | 34 ---- ...ype_for_tagged_union_with_extra_union_field.zig | 35 ---- .../obj/reify_type_for_union_with_zero_fields.zig | 17 -- .../obj/reify_type_union_payload_is_undefined.zig | 10 -- .../stage1/obj/reify_type_with_Type.Int.zig | 13 -- .../reify_type_with_non-constant_expression.zig | 11 -- .../stage1/obj/reify_type_with_undefined.zig | 20 --- ...ify_type.Pointer_with_invalid_address_space.zig | 18 ++ .../reify_type_with_non-constant_expression.zig | 11 ++ 30 files changed, 463 insertions(+), 274 deletions(-) create mode 100644 test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig create mode 100644 test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig create mode 100644 test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig create mode 100644 test/cases/compile_errors/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig create mode 100644 test/cases/compile_errors/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig create mode 100644 test/cases/compile_errors/reify_type_for_exhaustive_enum_with_zero_fields.zig create mode 100644 test/cases/compile_errors/reify_type_for_tagged_union_with_extra_enum_field.zig create mode 100644 test/cases/compile_errors/reify_type_for_tagged_union_with_extra_union_field.zig create mode 100644 test/cases/compile_errors/reify_type_for_union_with_zero_fields.zig create mode 100644 test/cases/compile_errors/reify_type_union_payload_is_undefined.zig create mode 100644 test/cases/compile_errors/reify_type_with_Type.Int.zig create mode 100644 test/cases/compile_errors/reify_type_with_undefined.zig delete mode 100644 test/cases/compile_errors/stage1/obj/reify_type.Fn_with_is_generic_true.zig delete mode 100644 test/cases/compile_errors/stage1/obj/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig delete mode 100644 test/cases/compile_errors/stage1/obj/reify_type.Fn_with_return_type_null.zig delete mode 100644 test/cases/compile_errors/stage1/obj/reify_type.Pointer_with_invalid_address_space.zig delete mode 100644 test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig delete mode 100644 test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig delete mode 100644 test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_zero_fields.zig delete mode 100644 test/cases/compile_errors/stage1/obj/reify_type_for_tagged_union_with_extra_enum_field.zig delete mode 100644 test/cases/compile_errors/stage1/obj/reify_type_for_tagged_union_with_extra_union_field.zig delete mode 100644 test/cases/compile_errors/stage1/obj/reify_type_for_union_with_zero_fields.zig delete mode 100644 test/cases/compile_errors/stage1/obj/reify_type_union_payload_is_undefined.zig delete mode 100644 test/cases/compile_errors/stage1/obj/reify_type_with_Type.Int.zig delete mode 100644 test/cases/compile_errors/stage1/obj/reify_type_with_non-constant_expression.zig delete mode 100644 test/cases/compile_errors/stage1/obj/reify_type_with_undefined.zig create mode 100644 test/cases/compile_errors/stage1/reify_type.Pointer_with_invalid_address_space.zig create mode 100644 test/cases/compile_errors/stage1/reify_type_with_non-constant_expression.zig (limited to 'src/value.zig') 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/reify_type.Fn_with_is_generic_true.zig b/test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig new file mode 100644 index 0000000000..cf80c9f4ba --- /dev/null +++ b/test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig @@ -0,0 +1,17 @@ +const Foo = @Type(.{ + .Fn = .{ + .calling_convention = .Unspecified, + .alignment = 0, + .is_generic = true, + .is_var_args = false, + .return_type = u0, + .args = &.{}, + }, +}); +comptime { _ = Foo; } + +// error +// backend=stage2 +// target=native +// +// :1:13: error: Type.Fn.is_generic must be false for @Type diff --git a/test/cases/compile_errors/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 new file mode 100644 index 0000000000..8328ee9b97 --- /dev/null +++ b/test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig @@ -0,0 +1,17 @@ +const Foo = @Type(.{ + .Fn = .{ + .calling_convention = .Unspecified, + .alignment = 0, + .is_generic = false, + .is_var_args = true, + .return_type = u0, + .args = &.{}, + }, +}); +comptime { _ = Foo; } + +// error +// backend=stage2 +// target=native +// +// :1:13: error: varargs functions must have C calling convention diff --git a/test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig b/test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig new file mode 100644 index 0000000000..f6587dcd7e --- /dev/null +++ b/test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig @@ -0,0 +1,17 @@ +const Foo = @Type(.{ + .Fn = .{ + .calling_convention = .Unspecified, + .alignment = 0, + .is_generic = false, + .is_var_args = false, + .return_type = null, + .args = &.{}, + }, +}); +comptime { _ = Foo; } + +// error +// backend=stage2 +// target=native +// +// :1:13: error: Type.Fn.return_type must be non-null for @Type diff --git a/test/cases/compile_errors/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 new file mode 100644 index 0000000000..e72b783d83 --- /dev/null +++ b/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig @@ -0,0 +1,18 @@ +const Tag = @Type(.{ + .Enum = .{ + .layout = .Auto, + .tag_type = bool, + .fields = &.{}, + .decls = &.{}, + .is_exhaustive = false, + }, +}); +export fn entry() void { + _ = @intToEnum(Tag, 0); +} + +// error +// backend=stage2 +// target=native +// +// :1:13: error: Type.Enum.tag_type must be an integer type diff --git a/test/cases/compile_errors/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 new file mode 100644 index 0000000000..1c237a17bd --- /dev/null +++ b/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig @@ -0,0 +1,18 @@ +const Tag = @Type(.{ + .Enum = .{ + .layout = .Auto, + .tag_type = undefined, + .fields = &.{}, + .decls = &.{}, + .is_exhaustive = false, + }, +}); +export fn entry() void { + _ = @intToEnum(Tag, 0); +} + +// error +// backend=stage2 +// target=native +// +// :1:13: error: use of undefined value here causes undefined behavior diff --git a/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_zero_fields.zig b/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_zero_fields.zig new file mode 100644 index 0000000000..44876e938a --- /dev/null +++ b/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_zero_fields.zig @@ -0,0 +1,18 @@ +const Tag = @Type(.{ + .Enum = .{ + .layout = .Auto, + .tag_type = u1, + .fields = &.{}, + .decls = &.{}, + .is_exhaustive = true, + }, +}); +export fn entry() void { + _ = @intToEnum(Tag, 0); +} + +// error +// backend=stage2 +// target=native +// +// :1:13: error: enums must have at least one field diff --git a/test/cases/compile_errors/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 new file mode 100644 index 0000000000..ccd0000494 --- /dev/null +++ b/test/cases/compile_errors/reify_type_for_tagged_union_with_extra_enum_field.zig @@ -0,0 +1,36 @@ +const Tag = @Type(.{ + .Enum = .{ + .layout = .Auto, + .tag_type = u2, + .fields = &.{ + .{ .name = "signed", .value = 0 }, + .{ .name = "unsigned", .value = 1 }, + .{ .name = "arst", .value = 2 }, + }, + .decls = &.{}, + .is_exhaustive = true, + }, +}); +const Tagged = @Type(.{ + .Union = .{ + .layout = .Auto, + .tag_type = Tag, + .fields = &.{ + .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) }, + .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) }, + }, + .decls = &.{}, + }, +}); +export fn entry() void { + var tagged = Tagged{ .signed = -1 }; + tagged = .{ .unsigned = 1 }; +} + +// error +// backend=stage2 +// target=native +// +// :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/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 new file mode 100644 index 0000000000..414bf2ce5e --- /dev/null +++ b/test/cases/compile_errors/reify_type_for_tagged_union_with_extra_union_field.zig @@ -0,0 +1,35 @@ +const Tag = @Type(.{ + .Enum = .{ + .layout = .Auto, + .tag_type = u1, + .fields = &.{ + .{ .name = "signed", .value = 0 }, + .{ .name = "unsigned", .value = 1 }, + }, + .decls = &.{}, + .is_exhaustive = true, + }, +}); +const Tagged = @Type(.{ + .Union = .{ + .layout = .Auto, + .tag_type = Tag, + .fields = &.{ + .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) }, + .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) }, + .{ .name = "arst", .field_type = f32, .alignment = @alignOf(f32) }, + }, + .decls = &.{}, + }, +}); +export fn entry() void { + var tagged = Tagged{ .signed = -1 }; + tagged = .{ .unsigned = 1 }; +} + +// error +// backend=stage2 +// target=native +// +// :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/reify_type_for_union_with_zero_fields.zig b/test/cases/compile_errors/reify_type_for_union_with_zero_fields.zig new file mode 100644 index 0000000000..0b4f395c81 --- /dev/null +++ b/test/cases/compile_errors/reify_type_for_union_with_zero_fields.zig @@ -0,0 +1,17 @@ +const Untagged = @Type(.{ + .Union = .{ + .layout = .Auto, + .tag_type = null, + .fields = &.{}, + .decls = &.{}, + }, +}); +export fn entry() void { + _ = Untagged{}; +} + +// error +// backend=stage2 +// target=native +// +// :1:18: error: unions must have at least one field diff --git a/test/cases/compile_errors/reify_type_union_payload_is_undefined.zig b/test/cases/compile_errors/reify_type_union_payload_is_undefined.zig new file mode 100644 index 0000000000..410bb92658 --- /dev/null +++ b/test/cases/compile_errors/reify_type_union_payload_is_undefined.zig @@ -0,0 +1,10 @@ +const Foo = @Type(.{ + .Struct = undefined, +}); +comptime { _ = Foo; } + +// error +// backend=stage2 +// target=native +// +// :1:13: error: use of undefined value here causes undefined behavior diff --git a/test/cases/compile_errors/reify_type_with_Type.Int.zig b/test/cases/compile_errors/reify_type_with_Type.Int.zig new file mode 100644 index 0000000000..bd98912a03 --- /dev/null +++ b/test/cases/compile_errors/reify_type_with_Type.Int.zig @@ -0,0 +1,15 @@ +const builtin = @import("std").builtin; +export fn entry() void { + _ = @Type(builtin.Type.Int{ + .signedness = .signed, + .bits = 8, + }); +} + +// error +// backend=stage2 +// target=native +// +// :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/reify_type_with_undefined.zig b/test/cases/compile_errors/reify_type_with_undefined.zig new file mode 100644 index 0000000000..e5753fa420 --- /dev/null +++ b/test/cases/compile_errors/reify_type_with_undefined.zig @@ -0,0 +1,20 @@ +comptime { + _ = @Type(.{ .Array = .{ .len = 0, .child = u8, .sentinel = undefined } }); +} +comptime { + _ = @Type(.{ + .Struct = .{ + .fields = undefined, + .decls = undefined, + .is_tuple = false, + .layout = .Auto, + }, + }); +} + +// error +// backend=stage2 +// target=native +// +// :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.Fn_with_is_generic_true.zig b/test/cases/compile_errors/stage1/obj/reify_type.Fn_with_is_generic_true.zig deleted file mode 100644 index f2849b5eb4..0000000000 --- a/test/cases/compile_errors/stage1/obj/reify_type.Fn_with_is_generic_true.zig +++ /dev/null @@ -1,17 +0,0 @@ -const Foo = @Type(.{ - .Fn = .{ - .calling_convention = .Unspecified, - .alignment = 0, - .is_generic = true, - .is_var_args = false, - .return_type = u0, - .args = &.{}, - }, -}); -comptime { _ = Foo; } - -// error -// backend=stage1 -// target=native -// -// tmp.zig:1:20: 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/stage1/obj/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig deleted file mode 100644 index 4d449e9eb9..0000000000 --- a/test/cases/compile_errors/stage1/obj/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig +++ /dev/null @@ -1,17 +0,0 @@ -const Foo = @Type(.{ - .Fn = .{ - .calling_convention = .Unspecified, - .alignment = 0, - .is_generic = false, - .is_var_args = true, - .return_type = u0, - .args = &.{}, - }, -}); -comptime { _ = Foo; } - -// error -// backend=stage1 -// target=native -// -// tmp.zig:1:20: 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/stage1/obj/reify_type.Fn_with_return_type_null.zig deleted file mode 100644 index 98cbc37d41..0000000000 --- a/test/cases/compile_errors/stage1/obj/reify_type.Fn_with_return_type_null.zig +++ /dev/null @@ -1,17 +0,0 @@ -const Foo = @Type(.{ - .Fn = .{ - .calling_convention = .Unspecified, - .alignment = 0, - .is_generic = false, - .is_var_args = false, - .return_type = null, - .args = &.{}, - }, -}); -comptime { _ = Foo; } - -// error -// backend=stage1 -// target=native -// -// tmp.zig:1:20: error: Type.Fn.return_type must be non-null for @Type diff --git a/test/cases/compile_errors/stage1/obj/reify_type.Pointer_with_invalid_address_space.zig b/test/cases/compile_errors/stage1/obj/reify_type.Pointer_with_invalid_address_space.zig deleted file mode 100644 index 1ca97ce250..0000000000 --- a/test/cases/compile_errors/stage1/obj/reify_type.Pointer_with_invalid_address_space.zig +++ /dev/null @@ -1,18 +0,0 @@ -export fn entry() void { - _ = @Type(.{ .Pointer = .{ - .size = .One, - .is_const = false, - .is_volatile = false, - .alignment = 1, - .address_space = .gs, - .child = u8, - .is_allowzero = false, - .sentinel = null, - }}); -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:2:16: error: address space 'gs' not available in stage 1 compiler, must be .generic 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/stage1/obj/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig deleted file mode 100644 index 56d05578be..0000000000 --- a/test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig +++ /dev/null @@ -1,18 +0,0 @@ -const Tag = @Type(.{ - .Enum = .{ - .layout = .Auto, - .tag_type = bool, - .fields = &.{}, - .decls = &.{}, - .is_exhaustive = false, - }, -}); -export fn entry() void { - _ = @intToEnum(Tag, 0); -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:1:20: error: Type.Enum.tag_type must be an integer type, not 'bool' diff --git a/test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig b/test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig deleted file mode 100644 index e6454d2ee5..0000000000 --- a/test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig +++ /dev/null @@ -1,18 +0,0 @@ -const Tag = @Type(.{ - .Enum = .{ - .layout = .Auto, - .tag_type = undefined, - .fields = &.{}, - .decls = &.{}, - .is_exhaustive = false, - }, -}); -export fn entry() void { - _ = @intToEnum(Tag, 0); -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:1:20: 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/stage1/obj/reify_type_for_exhaustive_enum_with_zero_fields.zig deleted file mode 100644 index d3ce70c1b0..0000000000 --- a/test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_zero_fields.zig +++ /dev/null @@ -1,18 +0,0 @@ -const Tag = @Type(.{ - .Enum = .{ - .layout = .Auto, - .tag_type = u1, - .fields = &.{}, - .decls = &.{}, - .is_exhaustive = true, - }, -}); -export fn entry() void { - _ = @intToEnum(Tag, 0); -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:1:20: error: enums must have 1 or more fields diff --git a/test/cases/compile_errors/stage1/obj/reify_type_for_tagged_union_with_extra_enum_field.zig b/test/cases/compile_errors/stage1/obj/reify_type_for_tagged_union_with_extra_enum_field.zig deleted file mode 100644 index 0c56cb91ea..0000000000 --- a/test/cases/compile_errors/stage1/obj/reify_type_for_tagged_union_with_extra_enum_field.zig +++ /dev/null @@ -1,34 +0,0 @@ -const Tag = @Type(.{ - .Enum = .{ - .layout = .Auto, - .tag_type = u2, - .fields = &.{ - .{ .name = "signed", .value = 0 }, - .{ .name = "unsigned", .value = 1 }, - .{ .name = "arst", .value = 2 }, - }, - .decls = &.{}, - .is_exhaustive = true, - }, -}); -const Tagged = @Type(.{ - .Union = .{ - .layout = .Auto, - .tag_type = Tag, - .fields = &.{ - .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) }, - .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) }, - }, - .decls = &.{}, - }, -}); -export fn entry() void { - var tagged = Tagged{ .signed = -1 }; - tagged = .{ .unsigned = 1 }; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:14:23: error: enum field missing: 'arst' diff --git a/test/cases/compile_errors/stage1/obj/reify_type_for_tagged_union_with_extra_union_field.zig b/test/cases/compile_errors/stage1/obj/reify_type_for_tagged_union_with_extra_union_field.zig deleted file mode 100644 index 63cf1f178e..0000000000 --- a/test/cases/compile_errors/stage1/obj/reify_type_for_tagged_union_with_extra_union_field.zig +++ /dev/null @@ -1,35 +0,0 @@ -const Tag = @Type(.{ - .Enum = .{ - .layout = .Auto, - .tag_type = u1, - .fields = &.{ - .{ .name = "signed", .value = 0 }, - .{ .name = "unsigned", .value = 1 }, - }, - .decls = &.{}, - .is_exhaustive = true, - }, -}); -const Tagged = @Type(.{ - .Union = .{ - .layout = .Auto, - .tag_type = Tag, - .fields = &.{ - .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) }, - .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) }, - .{ .name = "arst", .field_type = f32, .alignment = @alignOf(f32) }, - }, - .decls = &.{}, - }, -}); -export fn entry() void { - var tagged = Tagged{ .signed = -1 }; - tagged = .{ .unsigned = 1 }; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:13:23: error: enum field not found: 'arst' -// tmp.zig:1:20: 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/stage1/obj/reify_type_for_union_with_zero_fields.zig deleted file mode 100644 index 578f902697..0000000000 --- a/test/cases/compile_errors/stage1/obj/reify_type_for_union_with_zero_fields.zig +++ /dev/null @@ -1,17 +0,0 @@ -const Untagged = @Type(.{ - .Union = .{ - .layout = .Auto, - .tag_type = null, - .fields = &.{}, - .decls = &.{}, - }, -}); -export fn entry() void { - _ = Untagged{}; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:1:25: error: unions must have 1 or more fields diff --git a/test/cases/compile_errors/stage1/obj/reify_type_union_payload_is_undefined.zig b/test/cases/compile_errors/stage1/obj/reify_type_union_payload_is_undefined.zig deleted file mode 100644 index 47be31c711..0000000000 --- a/test/cases/compile_errors/stage1/obj/reify_type_union_payload_is_undefined.zig +++ /dev/null @@ -1,10 +0,0 @@ -const Foo = @Type(.{ - .Struct = undefined, -}); -comptime { _ = Foo; } - -// error -// backend=stage1 -// target=native -// -// tmp.zig:1:20: 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/stage1/obj/reify_type_with_Type.Int.zig deleted file mode 100644 index 116bd86e0f..0000000000 --- a/test/cases/compile_errors/stage1/obj/reify_type_with_Type.Int.zig +++ /dev/null @@ -1,13 +0,0 @@ -const builtin = @import("std").builtin; -export fn entry() void { - _ = @Type(builtin.Type.Int{ - .signedness = .signed, - .bits = 8, - }); -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:3:31: error: expected type 'std.builtin.Type', found 'std.builtin.Type.Int' diff --git a/test/cases/compile_errors/stage1/obj/reify_type_with_non-constant_expression.zig b/test/cases/compile_errors/stage1/obj/reify_type_with_non-constant_expression.zig deleted file mode 100644 index 7eec6b395a..0000000000 --- a/test/cases/compile_errors/stage1/obj/reify_type_with_non-constant_expression.zig +++ /dev/null @@ -1,11 +0,0 @@ -const builtin = @import("std").builtin; -var globalTypeInfo : builtin.Type = undefined; -export fn entry() void { - _ = @Type(globalTypeInfo); -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:4:15: error: unable to evaluate constant expression diff --git a/test/cases/compile_errors/stage1/obj/reify_type_with_undefined.zig b/test/cases/compile_errors/stage1/obj/reify_type_with_undefined.zig deleted file mode 100644 index 1de93ccdf6..0000000000 --- a/test/cases/compile_errors/stage1/obj/reify_type_with_undefined.zig +++ /dev/null @@ -1,20 +0,0 @@ -comptime { - _ = @Type(.{ .Array = .{ .len = 0, .child = u8, .sentinel = undefined } }); -} -comptime { - _ = @Type(.{ - .Struct = .{ - .fields = undefined, - .decls = undefined, - .is_tuple = false, - .layout = .Auto, - }, - }); -} - -// error -// backend=stage1 -// 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 diff --git a/test/cases/compile_errors/stage1/reify_type.Pointer_with_invalid_address_space.zig b/test/cases/compile_errors/stage1/reify_type.Pointer_with_invalid_address_space.zig new file mode 100644 index 0000000000..1ca97ce250 --- /dev/null +++ b/test/cases/compile_errors/stage1/reify_type.Pointer_with_invalid_address_space.zig @@ -0,0 +1,18 @@ +export fn entry() void { + _ = @Type(.{ .Pointer = .{ + .size = .One, + .is_const = false, + .is_volatile = false, + .alignment = 1, + .address_space = .gs, + .child = u8, + .is_allowzero = false, + .sentinel = null, + }}); +} + +// error +// backend=stage1 +// target=native +// +// tmp.zig:2:16: error: address space 'gs' not available in stage 1 compiler, must be .generic diff --git a/test/cases/compile_errors/stage1/reify_type_with_non-constant_expression.zig b/test/cases/compile_errors/stage1/reify_type_with_non-constant_expression.zig new file mode 100644 index 0000000000..7eec6b395a --- /dev/null +++ b/test/cases/compile_errors/stage1/reify_type_with_non-constant_expression.zig @@ -0,0 +1,11 @@ +const builtin = @import("std").builtin; +var globalTypeInfo : builtin.Type = undefined; +export fn entry() void { + _ = @Type(globalTypeInfo); +} + +// error +// backend=stage1 +// target=native +// +// tmp.zig:4:15: error: unable to evaluate constant expression -- cgit v1.2.3 From c0a1b4fa46dfd00d0cc4d1b6954bc07ae762e31e Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Sat, 30 Jul 2022 06:34:49 -0700 Subject: stage2: Fix AIR printing Packed structs never have comptime fields, and a slice might actually be backed by a variable, which we need to catch before iterating its elements. --- src/TypedValue.zig | 14 ++++++++++---- src/value.zig | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) (limited to 'src/value.zig') diff --git a/src/TypedValue.zig b/src/TypedValue.zig index 21d8629061..ba32e55f1e 100644 --- a/src/TypedValue.zig +++ b/src/TypedValue.zig @@ -73,6 +73,9 @@ pub fn print( const target = mod.getTarget(); var val = tv.val; var ty = tv.ty; + if (val.isVariable(mod)) + return writer.writeAll("(variable)"); + while (true) switch (val.tag()) { .u1_type => return writer.writeAll("u1"), .u8_type => return writer.writeAll("u8"), @@ -155,9 +158,12 @@ pub fn print( } try print(.{ .ty = ty.structFieldType(i), - .val = ty.structFieldValueComptime(i) orelse b: { - const vals = val.castTag(.aggregate).?.data; - break :b vals[i]; + .val = switch (ty.containerLayout()) { + .Packed => val.castTag(.aggregate).?.data[i], + else => ty.structFieldValueComptime(i) orelse b: { + const vals = val.castTag(.aggregate).?.data; + break :b vals[i]; + }, }, }, writer, level - 1, mod); } @@ -241,7 +247,7 @@ pub fn print( mod.declPtr(val.castTag(.function).?.data.owner_decl).name, }), .extern_fn => return writer.writeAll("(extern function)"), - .variable => return writer.writeAll("(variable)"), + .variable => unreachable, .decl_ref_mut => { const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index; const decl = mod.declPtr(decl_index); diff --git a/src/value.zig b/src/value.zig index 46624a822d..fd71aeabdc 100644 --- a/src/value.zig +++ b/src/value.zig @@ -2664,6 +2664,26 @@ pub const Value = extern union { } } + /// Returns true if a Value is backed by a variable + pub fn isVariable( + val: Value, + mod: *Module, + ) bool { + return switch (val.tag()) { + .slice => val.castTag(.slice).?.data.ptr.isVariable(mod), + .comptime_field_ptr => val.castTag(.comptime_field_ptr).?.data.field_val.isVariable(mod), + .elem_ptr => val.castTag(.elem_ptr).?.data.array_ptr.isVariable(mod), + .field_ptr => val.castTag(.field_ptr).?.data.container_ptr.isVariable(mod), + .eu_payload_ptr => val.castTag(.eu_payload_ptr).?.data.container_ptr.isVariable(mod), + .opt_payload_ptr => val.castTag(.opt_payload_ptr).?.data.container_ptr.isVariable(mod), + .decl_ref => mod.declPtr(val.castTag(.decl_ref).?.data).val.isVariable(mod), + .decl_ref_mut => mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index).val.isVariable(mod), + + .variable => true, + else => false, + }; + } + // Asserts that the provided start/end are in-bounds. pub fn sliceArray( val: Value, -- cgit v1.2.3