authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-29 00:40:02+03:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-29 13:45:37-07:00
loga4b52ccd9fb538bdcd77cf2d45b9310e189cc243
treef87cb9fef812ba510ab6938eff266010cd7343e2
parent15cc4514e0566430ed1d95e85aaa462642b70364

Sema: fix access of inactive union field when enum and union fields are in different order

Closes #12667

2 files changed, 33 insertions(+), 10 deletions(-)

src/Sema.zig+10-10
......@@ -21892,17 +21892,18 @@ fn unionFieldPtr(
2189221892 if (union_val.isUndef()) {
2189321893 return sema.failWithUseOfUndef(block, src);
2189421894 }
21895 const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?;
2189521896 const tag_and_val = union_val.castTag(.@"union").?.data;
2189621897 var field_tag_buf: Value.Payload.U32 = .{
2189721898 .base = .{ .tag = .enum_field_index },
21898 .data = field_index,
21899 .data = @intCast(u32, enum_field_index),
2189921900 };
2190021901 const field_tag = Value.initPayload(&field_tag_buf.base);
2190121902 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
2190221903 if (!tag_matches) {
2190321904 const msg = msg: {
2190421905 const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;
21905 const active_field_name = union_obj.fields.keys()[active_index];
21906 const active_field_name = union_obj.tag_ty.enumFieldName(active_index);
2190621907 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
2190721908 errdefer msg.destroy(sema.gpa);
2190821909 try sema.addDeclaredHereNote(msg, union_ty);
......@@ -21927,12 +21928,11 @@ fn unionFieldPtr(
2192721928 if (!initializing and union_obj.layout == .Auto and block.wantSafety() and
2192821929 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
2192921930 {
21930 const enum_ty = union_ty.unionTagTypeHypothetical();
2193121931 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);
21932 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);
2193321933 // TODO would it be better if get_union_tag supported pointers to unions?
2193421934 const union_val = try block.addTyOp(.load, union_ty, union_ptr);
21935 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);
2193621936 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
2193721937 try sema.addSafetyCheck(block, ok, .inactive_union_field);
2193821938 }
......@@ -21963,9 +21963,10 @@ fn unionFieldVal(
2196321963 if (union_val.isUndef()) return sema.addConstUndef(field.ty);
2196421964
2196521965 const tag_and_val = union_val.castTag(.@"union").?.data;
21966 const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?;
2196621967 var field_tag_buf: Value.Payload.U32 = .{
2196721968 .base = .{ .tag = .enum_field_index },
21968 .data = field_index,
21969 .data = @intCast(u32, enum_field_index),
2196921970 };
2197021971 const field_tag = Value.initPayload(&field_tag_buf.base);
2197121972 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
......@@ -21976,7 +21977,7 @@ fn unionFieldVal(
2197621977 } else {
2197721978 const msg = msg: {
2197821979 const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;
21979 const active_field_name = union_obj.fields.keys()[active_index];
21980 const active_field_name = union_obj.tag_ty.enumFieldName(active_index);
2198021981 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
2198121982 errdefer msg.destroy(sema.gpa);
2198221983 try sema.addDeclaredHereNote(msg, union_ty);
......@@ -22001,10 +22002,9 @@ fn unionFieldVal(
2200122002 if (union_obj.layout == .Auto and block.wantSafety() and
2200222003 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
2200322004 {
22004 const enum_ty = union_ty.unionTagTypeHypothetical();
2200522005 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);
22006 const wanted_tag = try sema.addConstant(enum_ty, wanted_tag_val);
22007 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);
2200822008 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
2200922009 try sema.addSafetyCheck(block, ok, .inactive_union_field);
2201022010 }
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