authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-07 22:02:45-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-07 22:02:45-07:00
loge730172e47749db8a9d3be5949231bde95343b39
treed77ee85e8f3c99a6a13979a22e8650063677b75a
parentb67378fb08fb3129b66385479a278a93940f09f5

stage2: fix switch validation of handling all enum values

There were several problems, all fixed: * AstGen was storing field names as references to the original source code bytes. However, that data would be destroyed when the source file is updated. Now, it correctly stores the field names in the Decl arena for the enum. The same fix applies to error set field names. * Sema was missing a memset inside `analyzeSwitch`, leaving the "seen enum fields" array with undefined memory. Now that they are all properly set to null, the validation works. * Moved the "enum declared here" note to the end. It looked weird interrupting the notes for which enum values were missing.

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

src/Module.zig+16-5
......@@ -4582,28 +4582,39 @@ pub fn optimizeMode(mod: Module) std.builtin.Mode {
45824582/// Otherwise, returns a reference to the source code bytes directly.
45834583/// See also `appendIdentStr` and `parseStrLit`.
45844584pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) InnerError![]const u8 {
4585 return mod.identifierTokenStringTreeArena(scope, token, scope.tree(), scope.arena());
4585 const tree = scope.tree();
4586 const token_tags = tree.tokens.items(.tag);
4587 assert(token_tags[token] == .identifier);
4588 const ident_name = tree.tokenSlice(token);
4589 if (!mem.startsWith(u8, ident_name, "@")) {
4590 return ident_name;
4591 }
4592 var buf: ArrayListUnmanaged(u8) = .{};
4593 defer buf.deinit(mod.gpa);
4594 try parseStrLit(mod, scope, token, &buf, ident_name, 1);
4595 const duped = try scope.arena().dupe(u8, buf.items);
4596 return duped;
45864597}
45874598
45884599/// `scope` is only used for error reporting.
4600/// The string is stored in `arena` regardless of whether it uses @"" syntax.
45894601pub fn identifierTokenStringTreeArena(
45904602 mod: *Module,
45914603 scope: *Scope,
45924604 token: ast.TokenIndex,
45934605 tree: *const ast.Tree,
45944606 arena: *Allocator,
4595) InnerError![]const u8 {
4607) InnerError![]u8 {
45964608 const token_tags = tree.tokens.items(.tag);
45974609 assert(token_tags[token] == .identifier);
45984610 const ident_name = tree.tokenSlice(token);
45994611 if (!mem.startsWith(u8, ident_name, "@")) {
4600 return ident_name;
4612 return arena.dupe(u8, ident_name);
46014613 }
46024614 var buf: ArrayListUnmanaged(u8) = .{};
46034615 defer buf.deinit(mod.gpa);
46044616 try parseStrLit(mod, scope, token, &buf, ident_name, 1);
4605 const duped = try arena.dupe(u8, buf.items);
4606 return duped;
4617 return arena.dupe(u8, buf.items);
46074618}
46084619
46094620/// Given an identifier token, obtain the string for it (possibly parsing as a string
src/Sema.zig+9-7
......@@ -2789,6 +2789,8 @@ fn analyzeSwitch(
27892789 var seen_fields = try gpa.alloc(?AstGen.SwitchProngSrc, operand.ty.enumFieldCount());
27902790 defer gpa.free(seen_fields);
27912791
2792 mem.set(?AstGen.SwitchProngSrc, seen_fields, null);
2793
27922794 var extra_index: usize = special.end;
27932795 {
27942796 var scalar_i: u32 = 0;
......@@ -2849,12 +2851,6 @@ fn analyzeSwitch(
28492851 .{},
28502852 );
28512853 errdefer msg.destroy(sema.gpa);
2852 try mod.errNoteNonLazy(
2853 operand.ty.declSrcLoc(),
2854 msg,
2855 "enum '{}' declared here",
2856 .{operand.ty},
2857 );
28582854 for (seen_fields) |seen_src, i| {
28592855 if (seen_src != null) continue;
28602856
......@@ -2865,10 +2861,16 @@ fn analyzeSwitch(
28652861 &block.base,
28662862 src,
28672863 msg,
2868 "unhandled enumeration value: '{s}",
2864 "unhandled enumeration value: '{s}'",
28692865 .{field_name},
28702866 );
28712867 }
2868 try mod.errNoteNonLazy(
2869 operand.ty.declSrcLoc(),
2870 msg,
2871 "enum '{}' declared here",
2872 .{operand.ty},
2873 );
28722874 break :msg msg;
28732875 };
28742876 return mod.failWithOwnedErrorMsg(&block.base, msg);
test/stage2/cbe.zig+15
......@@ -702,6 +702,21 @@ pub fn addCases(ctx: *TestContext) !void {
702702 ":3:15: error: enum 'E' has no tag with value 3",
703703 ":1:11: note: enum declared here",
704704 });
705
706 case.addError(
707 \\const E = enum { a, b, c };
708 \\export fn foo() void {
709 \\ var x: E = .a;
710 \\ switch (x) {
711 \\ .a => {},
712 \\ .c => {},
713 \\ }
714 \\}
715 , &.{
716 ":4:5: error: switch must handle all possibilities",
717 ":4:5: note: unhandled enumeration value: 'b'",
718 ":1:11: note: enum 'E' declared here",
719 });
705720 }
706721
707722 ctx.c("empty start function", linux_x64,