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(...@@ -21892,17 +21892,18 @@ fn unionFieldPtr(
21892 if (union_val.isUndef()) {21892 if (union_val.isUndef()) {
21893 return sema.failWithUseOfUndef(block, src);21893 return sema.failWithUseOfUndef(block, src);
21894 }21894 }
21895 const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?;
21895 const tag_and_val = union_val.castTag(.@"union").?.data;21896 const tag_and_val = union_val.castTag(.@"union").?.data;
21896 var field_tag_buf: Value.Payload.U32 = .{21897 var field_tag_buf: Value.Payload.U32 = .{
21897 .base = .{ .tag = .enum_field_index },21898 .base = .{ .tag = .enum_field_index },
21898 .data = field_index,21899 .data = @intCast(u32, enum_field_index),
21899 };21900 };
21900 const field_tag = Value.initPayload(&field_tag_buf.base);21901 const field_tag = Value.initPayload(&field_tag_buf.base);
21901 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);
21902 if (!tag_matches) {21903 if (!tag_matches) {
21903 const msg = msg: {21904 const msg = msg: {
21904 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;
21905 const active_field_name = union_obj.fields.keys()[active_index];21906 const active_field_name = union_obj.tag_ty.enumFieldName(active_index);
21906 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 });
21907 errdefer msg.destroy(sema.gpa);21908 errdefer msg.destroy(sema.gpa);
21908 try sema.addDeclaredHereNote(msg, union_ty);21909 try sema.addDeclaredHereNote(msg, union_ty);
...@@ -21927,12 +21928,11 @@ fn unionFieldPtr(...@@ -21927,12 +21928,11 @@ fn unionFieldPtr(
21927 if (!initializing and union_obj.layout == .Auto and block.wantSafety() and21928 if (!initializing and union_obj.layout == .Auto and block.wantSafety() and
21928 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)21929 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
21929 {21930 {
21930 const enum_ty = union_ty.unionTagTypeHypothetical();
21931 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);
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);
21933 // 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?
21934 const union_val = try block.addTyOp(.load, union_ty, union_ptr);21934 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);
21936 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);21936 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
21937 try sema.addSafetyCheck(block, ok, .inactive_union_field);21937 try sema.addSafetyCheck(block, ok, .inactive_union_field);
21938 }21938 }
...@@ -21963,9 +21963,10 @@ fn unionFieldVal(...@@ -21963,9 +21963,10 @@ fn unionFieldVal(
21963 if (union_val.isUndef()) return sema.addConstUndef(field.ty);21963 if (union_val.isUndef()) return sema.addConstUndef(field.ty);
2196421964
21965 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).?;
21966 var field_tag_buf: Value.Payload.U32 = .{21967 var field_tag_buf: Value.Payload.U32 = .{
21967 .base = .{ .tag = .enum_field_index },21968 .base = .{ .tag = .enum_field_index },
21968 .data = field_index,21969 .data = @intCast(u32, enum_field_index),
21969 };21970 };
21970 const field_tag = Value.initPayload(&field_tag_buf.base);21971 const field_tag = Value.initPayload(&field_tag_buf.base);
21971 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);
...@@ -21976,7 +21977,7 @@ fn unionFieldVal(...@@ -21976,7 +21977,7 @@ fn unionFieldVal(
21976 } else {21977 } else {
21977 const msg = msg: {21978 const msg = msg: {
21978 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;
21979 const active_field_name = union_obj.fields.keys()[active_index];21980 const active_field_name = union_obj.tag_ty.enumFieldName(active_index);
21980 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 });
21981 errdefer msg.destroy(sema.gpa);21982 errdefer msg.destroy(sema.gpa);
21982 try sema.addDeclaredHereNote(msg, union_ty);21983 try sema.addDeclaredHereNote(msg, union_ty);
...@@ -22001,10 +22002,9 @@ fn unionFieldVal(...@@ -22001,10 +22002,9 @@ fn unionFieldVal(
22001 if (union_obj.layout == .Auto and block.wantSafety() and22002 if (union_obj.layout == .Auto and block.wantSafety() and
22002 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)22003 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
22003 {22004 {
22004 const enum_ty = union_ty.unionTagTypeHypothetical();
22005 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);
22006 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);
22007 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);
22008 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);22008 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
22009 try sema.addSafetyCheck(block, ok, .inactive_union_field);22009 try sema.addSafetyCheck(block, ok, .inactive_union_field);
22010 }22010 }
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