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(...@@ -1164,6 +1164,10 @@ fn fnProtoExpr(
1164 const tree = astgen.tree;1164 const tree = astgen.tree;
1165 const token_tags = tree.tokens.items(.tag);1165 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
1167 const is_extern = blk: {1171 const is_extern = blk: {
1168 const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false;1172 const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false;
1169 break :blk token_tags[maybe_extern_token] == .keyword_extern;1173 break :blk token_tags[maybe_extern_token] == .keyword_extern;
src/Sema.zig+25-28
...@@ -2497,18 +2497,6 @@ fn zirEnumDecl(...@@ -2497,18 +2497,6 @@ fn zirEnumDecl(
2497 extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl);2497 extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl);
24982498
2499 const body = sema.code.extra[extra_index..][0..body_len];2499 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 }
2512 extra_index += body.len;2500 extra_index += body.len;
25132501
2514 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;2502 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
...@@ -2566,6 +2554,9 @@ fn zirEnumDecl(...@@ -2566,6 +2554,9 @@ fn zirEnumDecl(
2566 }2554 }
2567 enum_obj.tag_ty = try ty.copy(decl_arena_allocator);2555 enum_obj.tag_ty = try ty.copy(decl_arena_allocator);
2568 enum_obj.tag_ty_inferred = false;2556 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;
2569 } else {2560 } else {
2570 const bits = std.math.log2_int_ceil(usize, fields_len);2561 const bits = std.math.log2_int_ceil(usize, fields_len);
2571 enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, bits);2562 enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, bits);
...@@ -3788,6 +3779,7 @@ fn validateStructInit(...@@ -3788,6 +3779,7 @@ fn validateStructInit(
3788 if ((is_comptime or block.is_comptime) and3779 if ((is_comptime or block.is_comptime) and
3789 (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null)3780 (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null)
3790 {3781 {
3782 try sema.resolveStructLayout(block, init_src, struct_ty);
3791 // In this case the only thing we need to do is evaluate the implicit3783 // In this case the only thing we need to do is evaluate the implicit
3792 // store instructions for default field values, and report any missing fields.3784 // store instructions for default field values, and report any missing fields.
3793 // Avoid the cost of the extra machinery for detecting a comptime struct init value.3785 // Avoid the cost of the extra machinery for detecting a comptime struct init value.
...@@ -3982,6 +3974,7 @@ fn validateStructInit(...@@ -3982,6 +3974,7 @@ fn validateStructInit(
3982 try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store);3974 try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store);
3983 return;3975 return;
3984 }3976 }
3977 try sema.resolveStructLayout(block, init_src, struct_ty);
39853978
3986 // Our task is to insert `store` instructions for all the default field values.3979 // Our task is to insert `store` instructions for all the default field values.
3987 for (found_fields) |field_ptr, i| {3980 for (found_fields) |field_ptr, i| {
...@@ -9003,6 +8996,9 @@ fn zirSwitchCond(...@@ -9003,6 +8996,9 @@ fn zirSwitchCond(
9003 .ErrorSet,8996 .ErrorSet,
9004 .Enum,8997 .Enum,
9005 => {8998 => {
8999 if (operand_ty.isSlice()) {
9000 return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(sema.mod)});
9001 }
9006 if ((try sema.typeHasOnePossibleValue(block, operand_src, operand_ty))) |opv| {9002 if ((try sema.typeHasOnePossibleValue(block, operand_src, operand_ty))) |opv| {
9007 return sema.addConstant(operand_ty, opv);9003 return sema.addConstant(operand_ty, opv);
9008 }9004 }
...@@ -15849,6 +15845,7 @@ fn finishStructInit(...@@ -15849,6 +15845,7 @@ fn finishStructInit(
15849 }15845 }
1585015846
15851 if (is_ref) {15847 if (is_ref) {
15848 try sema.resolveStructLayout(block, dest_src, struct_ty);
15852 const target = sema.mod.getTarget();15849 const target = sema.mod.getTarget();
15853 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{15850 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
15854 .pointee_type = struct_ty,15851 .pointee_type = struct_ty,
...@@ -21895,17 +21892,18 @@ fn unionFieldPtr(...@@ -21895,17 +21892,18 @@ fn unionFieldPtr(
21895 if (union_val.isUndef()) {21892 if (union_val.isUndef()) {
21896 return sema.failWithUseOfUndef(block, src);21893 return sema.failWithUseOfUndef(block, src);
21897 }21894 }
21895 const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?;
21898 const tag_and_val = union_val.castTag(.@"union").?.data;21896 const tag_and_val = union_val.castTag(.@"union").?.data;
21899 var field_tag_buf: Value.Payload.U32 = .{21897 var field_tag_buf: Value.Payload.U32 = .{
21900 .base = .{ .tag = .enum_field_index },21898 .base = .{ .tag = .enum_field_index },
21901 .data = field_index,21899 .data = @intCast(u32, enum_field_index),
21902 };21900 };
21903 const field_tag = Value.initPayload(&field_tag_buf.base);21901 const field_tag = Value.initPayload(&field_tag_buf.base);
21904 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);21902 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
21905 if (!tag_matches) {21903 if (!tag_matches) {
21906 const msg = msg: {21904 const msg = msg: {
21907 const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;21905 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);
21909 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });21907 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
21910 errdefer msg.destroy(sema.gpa);21908 errdefer msg.destroy(sema.gpa);
21911 try sema.addDeclaredHereNote(msg, union_ty);21909 try sema.addDeclaredHereNote(msg, union_ty);
...@@ -21930,12 +21928,11 @@ fn unionFieldPtr(...@@ -21930,12 +21928,11 @@ fn unionFieldPtr(
21930 if (!initializing and union_obj.layout == .Auto and block.wantSafety() and21928 if (!initializing and union_obj.layout == .Auto and block.wantSafety() and
21931 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)21929 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
21932 {21930 {
21933 const enum_ty = union_ty.unionTagTypeHypothetical();
21934 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);21931 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);
21936 // TODO would it be better if get_union_tag supported pointers to unions?21933 // TODO would it be better if get_union_tag supported pointers to unions?
21937 const union_val = try block.addTyOp(.load, union_ty, union_ptr);21934 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);
21939 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);21936 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
21940 try sema.addSafetyCheck(block, ok, .inactive_union_field);21937 try sema.addSafetyCheck(block, ok, .inactive_union_field);
21941 }21938 }
...@@ -21966,9 +21963,10 @@ fn unionFieldVal(...@@ -21966,9 +21963,10 @@ fn unionFieldVal(
21966 if (union_val.isUndef()) return sema.addConstUndef(field.ty);21963 if (union_val.isUndef()) return sema.addConstUndef(field.ty);
2196721964
21968 const tag_and_val = union_val.castTag(.@"union").?.data;21965 const tag_and_val = union_val.castTag(.@"union").?.data;
21966 const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?;
21969 var field_tag_buf: Value.Payload.U32 = .{21967 var field_tag_buf: Value.Payload.U32 = .{
21970 .base = .{ .tag = .enum_field_index },21968 .base = .{ .tag = .enum_field_index },
21971 .data = field_index,21969 .data = @intCast(u32, enum_field_index),
21972 };21970 };
21973 const field_tag = Value.initPayload(&field_tag_buf.base);21971 const field_tag = Value.initPayload(&field_tag_buf.base);
21974 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);21972 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
...@@ -21979,7 +21977,7 @@ fn unionFieldVal(...@@ -21979,7 +21977,7 @@ fn unionFieldVal(
21979 } else {21977 } else {
21980 const msg = msg: {21978 const msg = msg: {
21981 const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;21979 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);
21983 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });21981 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
21984 errdefer msg.destroy(sema.gpa);21982 errdefer msg.destroy(sema.gpa);
21985 try sema.addDeclaredHereNote(msg, union_ty);21983 try sema.addDeclaredHereNote(msg, union_ty);
...@@ -22004,10 +22002,9 @@ fn unionFieldVal(...@@ -22004,10 +22002,9 @@ fn unionFieldVal(
22004 if (union_obj.layout == .Auto and block.wantSafety() and22002 if (union_obj.layout == .Auto and block.wantSafety() and
22005 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)22003 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
22006 {22004 {
22007 const enum_ty = union_ty.unionTagTypeHypothetical();
22008 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);22005 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);22006 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
22010 const active_tag = try block.addTyOp(.get_union_tag, enum_ty, union_byval);22007 const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval);
22011 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);22008 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
22012 try sema.addSafetyCheck(block, ok, .inactive_union_field);22009 try sema.addSafetyCheck(block, ok, .inactive_union_field);
22013 }22010 }
...@@ -22254,8 +22251,7 @@ fn tupleField(...@@ -22254,8 +22251,7 @@ fn tupleField(
2225422251
22255 if (try sema.resolveMaybeUndefVal(block, tuple_src, tuple)) |tuple_val| {22252 if (try sema.resolveMaybeUndefVal(block, tuple_src, tuple)) |tuple_val| {
22256 if (tuple_val.isUndef()) return sema.addConstUndef(field_ty);22253 if (tuple_val.isUndef()) return sema.addConstUndef(field_ty);
22257 const field_values = tuple_val.castTag(.aggregate).?.data;22254 return sema.addConstant(field_ty, tuple_val.fieldValue(tuple_ty, field_index));
22258 return sema.addConstant(field_ty, field_values[field_index]);
22259 }22255 }
2226022256
22261 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src);22257 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src);
...@@ -28854,10 +28850,11 @@ pub fn typeHasOnePossibleValue(...@@ -28854,10 +28850,11 @@ pub fn typeHasOnePossibleValue(
2885428850
28855 .tuple, .anon_struct => {28851 .tuple, .anon_struct => {
28856 const tuple = ty.tupleFields();28852 const tuple = ty.tupleFields();
28857 for (tuple.values) |val| {28853 for (tuple.values) |val, i| {
28858 if (val.tag() == .unreachable_value) {28854 const is_comptime = val.tag() != .unreachable_value;
28859 return null; // non-comptime field28855 if (is_comptime) continue;
28860 }28856 if ((try sema.typeHasOnePossibleValue(block, src, tuple.types[i])) != null) continue;
28857 return null;
28861 }28858 }
28862 return Value.initTag(.empty_struct_value);28859 return Value.initTag(.empty_struct_value);
28863 },28860 },
src/print_zir.zig+5-5
...@@ -1721,13 +1721,13 @@ const Writer = struct {...@@ -1721,13 +1721,13 @@ const Writer = struct {
1721 const body = self.code.extra[extra_index..][0..body_len];1721 const body = self.code.extra[extra_index..][0..body_len];
1722 extra_index += body.len;1722 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);
1724 if (fields_len == 0) {1727 if (fields_len == 0) {
1725 assert(body.len == 0);1728 try stream.writeAll(", {})");
1726 try stream.writeAll("{}, {})");1729 self.parent_decl_node = prev_parent_decl_node;
1727 } else {1730 } 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);
1731 try stream.writeAll(", {\n");1731 try stream.writeAll(", {\n");
17321732
1733 self.indent += 2;1733 self.indent += 2;
src/type.zig+8-7
...@@ -4979,19 +4979,20 @@ pub const Type = extern union {...@@ -4979,19 +4979,20 @@ pub const Type = extern union {
4979 const s = ty.castTag(.@"struct").?.data;4979 const s = ty.castTag(.@"struct").?.data;
4980 assert(s.haveFieldTypes());4980 assert(s.haveFieldTypes());
4981 for (s.fields.values()) |field| {4981 for (s.fields.values()) |field| {
4982 if (field.ty.onePossibleValue() == null) {4982 if (field.is_comptime) continue;
4983 return null;4983 if (field.ty.onePossibleValue() != null) continue;
4984 }4984 return null;
4985 }4985 }
4986 return Value.initTag(.empty_struct_value);4986 return Value.initTag(.empty_struct_value);
4987 },4987 },
49884988
4989 .tuple, .anon_struct => {4989 .tuple, .anon_struct => {
4990 const tuple = ty.tupleFields();4990 const tuple = ty.tupleFields();
4991 for (tuple.values) |val| {4991 for (tuple.values) |val, i| {
4992 if (val.tag() == .unreachable_value) {4992 const is_comptime = val.tag() != .unreachable_value;
4993 return null; // non-comptime field4993 if (is_comptime) continue;
4994 }4994 if (tuple.types[i].onePossibleValue() != null) continue;
4995 return null;
4995 }4996 }
4996 return Value.initTag(.empty_struct_value);4997 return Value.initTag(.empty_struct_value);
4997 },4998 },
test/behavior/enum.zig+5
...@@ -1170,3 +1170,8 @@ test "switch on an extern enum with negative value" {...@@ -1170,3 +1170,8 @@ test "switch on an extern enum with negative value" {
1170 Foo.Bar => return,1170 Foo.Bar => return,
1171 }1171 }
1172}1172}
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" {...@@ -564,3 +564,18 @@ test "nested packed struct field access test" {
564 try std.testing.expect(arg.g.h == 6);564 try std.testing.expect(arg.g.h == 6);
565 try std.testing.expect(arg.g.i == 8);565 try std.testing.expect(arg.g.i == 8);
566}566}
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" {...@@ -301,3 +301,30 @@ test "tuple type with void field" {
301 const x = T{{}};301 const x = T{{}};
302 try expect(@TypeOf(x[0]) == void);302 try expect(@TypeOf(x[0]) == void);
303}303}
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'