authorgravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-06-08 20:32:44-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-06-21 17:03:02-07:00
log75f7a8913eb6c22a7d2d4514512adb6ef535bb47
tree36700c31f1ee628858956753b89eb0bb66a2916b
parent8a6de78e0787015153707361a58659834d4c39c2

stage2 astgen: find unused vars


2 files changed, 53 insertions(+), 1 deletions(-)

src/AstGen.zig+45-1
......@@ -1826,6 +1826,7 @@ fn blockExprStmts(
18261826 }
18271827
18281828 try genDefers(gz, parent_scope, scope, .none);
1829 try checkUsed(gz, parent_scope, scope);
18291830}
18301831
18311832fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) InnerError!void {
......@@ -2154,6 +2155,36 @@ fn genDefers(
21542155 }
21552156}
21562157
2158fn checkUsed(
2159 gz: *GenZir,
2160 outer_scope: *Scope,
2161 inner_scope: *Scope,
2162) InnerError!void {
2163 const astgen = gz.astgen;
2164 const tree = astgen.tree;
2165 const node_datas = tree.nodes.items(.data);
2166
2167 var scope = inner_scope;
2168 while (scope != outer_scope) {
2169 switch (scope.tag) {
2170 .gen_zir => scope = scope.cast(GenZir).?.parent,
2171 .local_val => {
2172 const s = scope.cast(Scope.LocalVal).?;
2173 if (!s.used) return astgen.failTok(s.token_src, "unused local constant", .{});
2174 scope = s.parent;
2175 },
2176 .local_ptr => {
2177 const s = scope.cast(Scope.LocalPtr).?;
2178 if (!s.used) return astgen.failTok(s.token_src, "unused local variable", .{});
2179 scope = s.parent;
2180 },
2181 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
2182 .namespace => unreachable,
2183 .top => unreachable,
2184 }
2185 }
2186}
2187
21572188fn deferStmt(
21582189 gz: *GenZir,
21592190 scope: *Scope,
......@@ -2930,6 +2961,7 @@ fn fnDecl(
29302961 .name = param_name,
29312962 .inst = arg_inst,
29322963 .token_src = name_token,
2964 // TODO make function paramater have different message instead of unused constant
29332965 };
29342966 params_scope = &sub_scope.base;
29352967
......@@ -3370,6 +3402,7 @@ fn structDeclInner(
33703402 };
33713403 defer block_scope.instructions.deinit(gpa);
33723404
3405 // TODO should we change this to scope in other places too?
33733406 var namespace: Scope.Namespace = .{ .parent = scope };
33743407 defer namespace.decls.deinit(gpa);
33753408
......@@ -6131,10 +6164,14 @@ fn identifier(
61316164 while (true) switch (s.tag) {
61326165 .local_val => {
61336166 const local_val = s.cast(Scope.LocalVal).?;
6167 if (local_val.name == name_str_index) {
6168 local_val.used = true;
6169 }
61346170 if (hit_namespace) {
61356171 // captures of non-locals need to be emitted as decl_val or decl_ref
61366172 // This *might* be capturable depending on if it is comptime known
6137 break;
6173 s = local_val.parent;
6174 continue;
61386175 }
61396176 if (local_val.name == name_str_index) {
61406177 return rvalue(gz, scope, rl, local_val.inst, ident);
......@@ -6144,6 +6181,7 @@ fn identifier(
61446181 .local_ptr => {
61456182 const local_ptr = s.cast(Scope.LocalPtr).?;
61466183 if (local_ptr.name == name_str_index) {
6184 local_ptr.used = true;
61476185 if (hit_namespace) {
61486186 if (local_ptr.is_comptime)
61496187 break
......@@ -6151,6 +6189,8 @@ fn identifier(
61516189 return astgen.failNodeNotes(ident, "'{s}' not accessible from inner function", .{ident_name}, &.{
61526190 try astgen.errNoteTok(local_ptr.token_src, "declared here", .{}),
61536191 // TODO add crossed function definition here note.
6192 // Maybe add a note to the error about it being because of the var,
6193 // maybe recommend copying it into a const variable. -SpexGuy
61546194 });
61556195 }
61566196 switch (rl) {
......@@ -8341,6 +8381,8 @@ const Scope = struct {
83418381 token_src: ast.TokenIndex,
83428382 /// String table index.
83438383 name: u32,
8384 /// has this variable been referenced?
8385 used: bool = false,
83448386 };
83458387
83468388 /// This could be a `const` or `var` local. It has a pointer instead of a value.
......@@ -8358,6 +8400,8 @@ const Scope = struct {
83588400 /// String table index.
83598401 name: u32,
83608402 is_comptime: bool,
8403 /// has this variable been referenced?
8404 used: bool = false,
83618405 };
83628406
83638407 const Defer = struct {
test/stage2/test.zig+8
......@@ -246,6 +246,14 @@ pub fn addCases(ctx: *TestContext) !void {
246246 "",
247247 );
248248 }
249 {
250 var case = ctx.exe("unused vars", linux_x64);
251 case.addError(
252 \\pub fn main() void {
253 \\ const x = 1;
254 \\}
255 , &.{":2:11: error: unused local constant"});
256 }
249257 {
250258 var case = ctx.exe("@TypeOf", linux_x64);
251259 case.addCompareOutput(