authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-29 16:46:51-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-08-29 16:46:51-04:00
log9cca6728e58351bb34cc7f4880481350a279fede
treef87cb9fef812ba510ab6938eff266010cd7343e2
parent5bb8c03697fce798a966feb131f6d906863047ae
parenta4b52ccd9fb538bdcd77cf2d45b9310e189cc243
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #12663 from Vexu/stage2-fixes

Stage2 fixes

12 files changed, 156 insertions(+), 40 deletions(-)

src/AstGen.zig+4
......@@ -1164,6 +1164,10 @@ fn fnProtoExpr(
11641164 const tree = astgen.tree;
11651165 const token_tags = tree.tokens.items(.tag);
11661166
1167 if (fn_proto.name_token) |some| {
1168 return astgen.failTok(some, "function type cannot have a name", .{});
1169 }
1170
11671171 const is_extern = blk: {
11681172 const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false;
11691173 break :blk token_tags[maybe_extern_token] == .keyword_extern;
src/Sema.zig+25-28
......@@ -2497,18 +2497,6 @@ fn zirEnumDecl(
24972497 extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl);
24982498
24992499 const body = sema.code.extra[extra_index..][0..body_len];
2500 if (fields_len == 0) {
2501 assert(body.len == 0);
2502 if (tag_type_ref != .none) {
2503 const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref);
2504 if (ty.zigTypeTag() != .Int and ty.zigTypeTag() != .ComptimeInt) {
2505 return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(sema.mod)});
2506 }
2507 enum_obj.tag_ty = try ty.copy(new_decl_arena_allocator);
2508 enum_obj.tag_ty_inferred = false;
2509 }
2510 return decl_val;
2511 }
25122500 extra_index += body.len;
25132501
25142502 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
......@@ -2566,6 +2554,9 @@ fn zirEnumDecl(
25662554 }
25672555 enum_obj.tag_ty = try ty.copy(decl_arena_allocator);
25682556 enum_obj.tag_ty_inferred = false;
2557 } else if (fields_len == 0) {
2558 enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, 0);
2559 enum_obj.tag_ty_inferred = true;
25692560 } else {
25702561 const bits = std.math.log2_int_ceil(usize, fields_len);
25712562 enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, bits);
......@@ -3788,6 +3779,7 @@ fn validateStructInit(
37883779 if ((is_comptime or block.is_comptime) and
37893780 (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null)
37903781 {
3782 try sema.resolveStructLayout(block, init_src, struct_ty);
37913783 // In this case the only thing we need to do is evaluate the implicit
37923784 // store instructions for default field values, and report any missing fields.
37933785 // Avoid the cost of the extra machinery for detecting a comptime struct init value.
......@@ -3982,6 +3974,7 @@ fn validateStructInit(
39823974 try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store);
39833975 return;
39843976 }
3977 try sema.resolveStructLayout(block, init_src, struct_ty);
39853978
39863979 // Our task is to insert `store` instructions for all the default field values.
39873980 for (found_fields) |field_ptr, i| {
......@@ -9003,6 +8996,9 @@ fn zirSwitchCond(
90038996 .ErrorSet,
90048997 .Enum,
90058998 => {
8999 if (operand_ty.isSlice()) {
9000 return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(sema.mod)});
9001 }
90069002 if ((try sema.typeHasOnePossibleValue(block, operand_src, operand_ty))) |opv| {
90079003 return sema.addConstant(operand_ty, opv);
90089004 }
......@@ -15849,6 +15845,7 @@ fn finishStructInit(
1584915845 }
1585015846
1585115847 if (is_ref) {
15848 try sema.resolveStructLayout(block, dest_src, struct_ty);
1585215849 const target = sema.mod.getTarget();
1585315850 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
1585415851 .pointee_type = struct_ty,
......@@ -21895,17 +21892,18 @@ fn unionFieldPtr(
2189521892 if (union_val.isUndef()) {
2189621893 return sema.failWithUseOfUndef(block, src);
2189721894 }
21895 const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?;
2189821896 const tag_and_val = union_val.castTag(.@"union").?.data;
2189921897 var field_tag_buf: Value.Payload.U32 = .{
2190021898 .base = .{ .tag = .enum_field_index },
21901 .data = field_index,
21899 .data = @intCast(u32, enum_field_index),
2190221900 };
2190321901 const field_tag = Value.initPayload(&field_tag_buf.base);
2190421902 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
2190521903 if (!tag_matches) {
2190621904 const msg = msg: {
2190721905 const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;
21908 const active_field_name = union_obj.fields.keys()[active_index];
21906 const active_field_name = union_obj.tag_ty.enumFieldName(active_index);
2190921907 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
2191021908 errdefer msg.destroy(sema.gpa);
2191121909 try sema.addDeclaredHereNote(msg, union_ty);
......@@ -21930,12 +21928,11 @@ fn unionFieldPtr(
2193021928 if (!initializing and union_obj.layout == .Auto and block.wantSafety() and
2193121929 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
2193221930 {
21933 const enum_ty = union_ty.unionTagTypeHypothetical();
2193421931 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);
21935 const wanted_tag = try sema.addConstant(enum_ty, wanted_tag_val);
21932 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
2193621933 // TODO would it be better if get_union_tag supported pointers to unions?
2193721934 const union_val = try block.addTyOp(.load, union_ty, union_ptr);
21938 const active_tag = try block.addTyOp(.get_union_tag, enum_ty, union_val);
21935 const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_val);
2193921936 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
2194021937 try sema.addSafetyCheck(block, ok, .inactive_union_field);
2194121938 }
......@@ -21966,9 +21963,10 @@ fn unionFieldVal(
2196621963 if (union_val.isUndef()) return sema.addConstUndef(field.ty);
2196721964
2196821965 const tag_and_val = union_val.castTag(.@"union").?.data;
21966 const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?;
2196921967 var field_tag_buf: Value.Payload.U32 = .{
2197021968 .base = .{ .tag = .enum_field_index },
21971 .data = field_index,
21969 .data = @intCast(u32, enum_field_index),
2197221970 };
2197321971 const field_tag = Value.initPayload(&field_tag_buf.base);
2197421972 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
......@@ -21979,7 +21977,7 @@ fn unionFieldVal(
2197921977 } else {
2198021978 const msg = msg: {
2198121979 const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;
21982 const active_field_name = union_obj.fields.keys()[active_index];
21980 const active_field_name = union_obj.tag_ty.enumFieldName(active_index);
2198321981 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
2198421982 errdefer msg.destroy(sema.gpa);
2198521983 try sema.addDeclaredHereNote(msg, union_ty);
......@@ -22004,10 +22002,9 @@ fn unionFieldVal(
2200422002 if (union_obj.layout == .Auto and block.wantSafety() and
2200522003 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
2200622004 {
22007 const enum_ty = union_ty.unionTagTypeHypothetical();
2200822005 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);
22009 const wanted_tag = try sema.addConstant(enum_ty, wanted_tag_val);
22010 const active_tag = try block.addTyOp(.get_union_tag, enum_ty, union_byval);
22006 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
22007 const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval);
2201122008 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
2201222009 try sema.addSafetyCheck(block, ok, .inactive_union_field);
2201322010 }
......@@ -22254,8 +22251,7 @@ fn tupleField(
2225422251
2225522252 if (try sema.resolveMaybeUndefVal(block, tuple_src, tuple)) |tuple_val| {
2225622253 if (tuple_val.isUndef()) return sema.addConstUndef(field_ty);
22257 const field_values = tuple_val.castTag(.aggregate).?.data;
22258 return sema.addConstant(field_ty, field_values[field_index]);
22254 return sema.addConstant(field_ty, tuple_val.fieldValue(tuple_ty, field_index));
2225922255 }
2226022256
2226122257 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src);
......@@ -28854,10 +28850,11 @@ pub fn typeHasOnePossibleValue(
2885428850
2885528851 .tuple, .anon_struct => {
2885628852 const tuple = ty.tupleFields();
28857 for (tuple.values) |val| {
28858 if (val.tag() == .unreachable_value) {
28859 return null; // non-comptime field
28860 }
28853 for (tuple.values) |val, i| {
28854 const is_comptime = val.tag() != .unreachable_value;
28855 if (is_comptime) continue;
28856 if ((try sema.typeHasOnePossibleValue(block, src, tuple.types[i])) != null) continue;
28857 return null;
2886128858 }
2886228859 return Value.initTag(.empty_struct_value);
2886328860 },
src/print_zir.zig+5-5
......@@ -1721,13 +1721,13 @@ const Writer = struct {
17211721 const body = self.code.extra[extra_index..][0..body_len];
17221722 extra_index += body.len;
17231723
1724 const prev_parent_decl_node = self.parent_decl_node;
1725 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
1726 try self.writeBracedDecl(stream, body);
17241727 if (fields_len == 0) {
1725 assert(body.len == 0);
1726 try stream.writeAll("{}, {})");
1728 try stream.writeAll(", {})");
1729 self.parent_decl_node = prev_parent_decl_node;
17271730 } else {
1728 const prev_parent_decl_node = self.parent_decl_node;
1729 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
1730 try self.writeBracedDecl(stream, body);
17311731 try stream.writeAll(", {\n");
17321732
17331733 self.indent += 2;
src/type.zig+8-7
......@@ -4979,19 +4979,20 @@ pub const Type = extern union {
49794979 const s = ty.castTag(.@"struct").?.data;
49804980 assert(s.haveFieldTypes());
49814981 for (s.fields.values()) |field| {
4982 if (field.ty.onePossibleValue() == null) {
4983 return null;
4984 }
4982 if (field.is_comptime) continue;
4983 if (field.ty.onePossibleValue() != null) continue;
4984 return null;
49854985 }
49864986 return Value.initTag(.empty_struct_value);
49874987 },
49884988
49894989 .tuple, .anon_struct => {
49904990 const tuple = ty.tupleFields();
4991 for (tuple.values) |val| {
4992 if (val.tag() == .unreachable_value) {
4993 return null; // non-comptime field
4994 }
4991 for (tuple.values) |val, i| {
4992 const is_comptime = val.tag() != .unreachable_value;
4993 if (is_comptime) continue;
4994 if (tuple.types[i].onePossibleValue() != null) continue;
4995 return null;
49954996 }
49964997 return Value.initTag(.empty_struct_value);
49974998 },
test/behavior/enum.zig+5
......@@ -1170,3 +1170,8 @@ test "switch on an extern enum with negative value" {
11701170 Foo.Bar => return,
11711171 }
11721172}
1173
1174test "Non-exhaustive enum with nonstandard int size behaves correctly" {
1175 const E = enum(u15) { _ };
1176 try expect(@sizeOf(E) == @sizeOf(u15));
1177}
test/behavior/packed-struct.zig+15
......@@ -564,3 +564,18 @@ test "nested packed struct field access test" {
564564 try std.testing.expect(arg.g.h == 6);
565565 try std.testing.expect(arg.g.i == 8);
566566}
567
568test "runtime init of unnamed packed struct type" {
569 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
570 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
571 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
572 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
573
574 var z: u8 = 123;
575 try (packed struct {
576 x: u8,
577 pub fn m(s: @This()) !void {
578 try expect(s.x == 123);
579 }
580 }{ .x = z }).m();
581}
test/behavior/tuple.zig+27
......@@ -301,3 +301,30 @@ test "tuple type with void field" {
301301 const x = T{{}};
302302 try expect(@TypeOf(x[0]) == void);
303303}
304
305test "zero sized struct in tuple handled correctly" {
306 const State = struct {
307 const Self = @This();
308 data: @Type(.{
309 .Struct = .{
310 .is_tuple = true,
311 .layout = .Auto,
312 .decls = &.{},
313 .fields = &.{.{
314 .name = "0",
315 .field_type = struct {},
316 .default_value = null,
317 .is_comptime = false,
318 .alignment = 0,
319 }},
320 },
321 }),
322
323 pub fn do(this: Self) usize {
324 return @sizeOf(@TypeOf(this));
325 }
326 };
327
328 var s: State = undefined;
329 try expect(s.do() == 0);
330}
test/cases/compile_errors/access_inactive_union_field_comptime.zig created+23
......@@ -0,0 +1,23 @@
1const Enum = enum(u32) { a, b };
2const TaggedUnion = union(Enum) {
3 b: []const u8,
4 a: []const u8,
5};
6pub export fn entry() void {
7 const result = TaggedUnion{ .b = "b" };
8 _ = result.b;
9 _ = result.a;
10}
11pub export fn entry1() void {
12 const result = TaggedUnion{ .b = "b" };
13 _ = &result.b;
14 _ = &result.a;
15}
16
17// error
18// backend=stage2
19// target=native
20//
21// :9:15: error: access of union field 'a' while field 'b' is active
22// :2:21: note: union declared here
23// :14:16: error: access of union field 'a' while field 'b' is active
test/cases/compile_errors/duplicate_field_in_discarded_anon_init.zig created+10
......@@ -0,0 +1,10 @@
1pub export fn entry() void {
2 _ = .{ .a = 0, .a = 1 };
3}
4
5// error
6// backend=stage2
7// target=native
8//
9// :2:21: error: duplicate field
10// :2:13: note: other field here
test/cases/compile_errors/function_type_named.zig created+7
......@@ -0,0 +1,7 @@
1const aFunc = fn someFunc(x: i32) void;
2
3// error
4// backend=stage2
5// target=native
6//
7// :1:18: error: function type cannot have a name
test/cases/compile_errors/struct_init_passed_to_type_param.zig created+14
......@@ -0,0 +1,14 @@
1const MyStruct = struct { x: i32 };
2
3fn hi(comptime T: type) usize {
4 return @sizeOf(T);
5}
6
7export const value = hi(MyStruct{ .x = 12 });
8
9// error
10// backend=stage2
11// target=native
12//
13// :7:33: error: expected type 'type', found 'tmp.MyStruct'
14// :1:18: note: struct declared here
test/cases/compile_errors/switch_on_slice.zig created+13
......@@ -0,0 +1,13 @@
1pub export fn entry() void {
2 var a: [:0]const u8 = "foo";
3 switch (a) {
4 "--version", "version" => unreachable,
5 else => {},
6 }
7}
8
9// error
10// backend=stage2
11// target=native
12//
13// :3:13: error: switch on type '[:0]const u8'