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(...@@ -1826,6 +1826,7 @@ fn blockExprStmts(
1826 }1826 }
18271827
1828 try genDefers(gz, parent_scope, scope, .none);1828 try genDefers(gz, parent_scope, scope, .none);
1829 try checkUsed(gz, parent_scope, scope);
1829}1830}
18301831
1831fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) InnerError!void {1832fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) InnerError!void {
...@@ -2154,6 +2155,36 @@ fn genDefers(...@@ -2154,6 +2155,36 @@ fn genDefers(
2154 }2155 }
2155}2156}
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
2157fn deferStmt(2188fn deferStmt(
2158 gz: *GenZir,2189 gz: *GenZir,
2159 scope: *Scope,2190 scope: *Scope,
...@@ -2930,6 +2961,7 @@ fn fnDecl(...@@ -2930,6 +2961,7 @@ fn fnDecl(
2930 .name = param_name,2961 .name = param_name,
2931 .inst = arg_inst,2962 .inst = arg_inst,
2932 .token_src = name_token,2963 .token_src = name_token,
2964 // TODO make function paramater have different message instead of unused constant
2933 };2965 };
2934 params_scope = &sub_scope.base;2966 params_scope = &sub_scope.base;
29352967
...@@ -3370,6 +3402,7 @@ fn structDeclInner(...@@ -3370,6 +3402,7 @@ fn structDeclInner(
3370 };3402 };
3371 defer block_scope.instructions.deinit(gpa);3403 defer block_scope.instructions.deinit(gpa);
33723404
3405 // TODO should we change this to scope in other places too?
3373 var namespace: Scope.Namespace = .{ .parent = scope };3406 var namespace: Scope.Namespace = .{ .parent = scope };
3374 defer namespace.decls.deinit(gpa);3407 defer namespace.decls.deinit(gpa);
33753408
...@@ -6131,10 +6164,14 @@ fn identifier(...@@ -6131,10 +6164,14 @@ fn identifier(
6131 while (true) switch (s.tag) {6164 while (true) switch (s.tag) {
6132 .local_val => {6165 .local_val => {
6133 const local_val = s.cast(Scope.LocalVal).?;6166 const local_val = s.cast(Scope.LocalVal).?;
6167 if (local_val.name == name_str_index) {
6168 local_val.used = true;
6169 }
6134 if (hit_namespace) {6170 if (hit_namespace) {
6135 // captures of non-locals need to be emitted as decl_val or decl_ref6171 // captures of non-locals need to be emitted as decl_val or decl_ref
6136 // This *might* be capturable depending on if it is comptime known6172 // This *might* be capturable depending on if it is comptime known
6137 break;6173 s = local_val.parent;
6174 continue;
6138 }6175 }
6139 if (local_val.name == name_str_index) {6176 if (local_val.name == name_str_index) {
6140 return rvalue(gz, scope, rl, local_val.inst, ident);6177 return rvalue(gz, scope, rl, local_val.inst, ident);
...@@ -6144,6 +6181,7 @@ fn identifier(...@@ -6144,6 +6181,7 @@ fn identifier(
6144 .local_ptr => {6181 .local_ptr => {
6145 const local_ptr = s.cast(Scope.LocalPtr).?;6182 const local_ptr = s.cast(Scope.LocalPtr).?;
6146 if (local_ptr.name == name_str_index) {6183 if (local_ptr.name == name_str_index) {
6184 local_ptr.used = true;
6147 if (hit_namespace) {6185 if (hit_namespace) {
6148 if (local_ptr.is_comptime)6186 if (local_ptr.is_comptime)
6149 break6187 break
...@@ -6151,6 +6189,8 @@ fn identifier(...@@ -6151,6 +6189,8 @@ fn identifier(
6151 return astgen.failNodeNotes(ident, "'{s}' not accessible from inner function", .{ident_name}, &.{6189 return astgen.failNodeNotes(ident, "'{s}' not accessible from inner function", .{ident_name}, &.{
6152 try astgen.errNoteTok(local_ptr.token_src, "declared here", .{}),6190 try astgen.errNoteTok(local_ptr.token_src, "declared here", .{}),
6153 // TODO add crossed function definition here note.6191 // 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
6154 });6194 });
6155 }6195 }
6156 switch (rl) {6196 switch (rl) {
...@@ -8341,6 +8381,8 @@ const Scope = struct {...@@ -8341,6 +8381,8 @@ const Scope = struct {
8341 token_src: ast.TokenIndex,8381 token_src: ast.TokenIndex,
8342 /// String table index.8382 /// String table index.
8343 name: u32,8383 name: u32,
8384 /// has this variable been referenced?
8385 used: bool = false,
8344 };8386 };
83458387
8346 /// This could be a `const` or `var` local. It has a pointer instead of a value.8388 /// This could be a `const` or `var` local. It has a pointer instead of a value.
...@@ -8358,6 +8400,8 @@ const Scope = struct {...@@ -8358,6 +8400,8 @@ const Scope = struct {
8358 /// String table index.8400 /// String table index.
8359 name: u32,8401 name: u32,
8360 is_comptime: bool,8402 is_comptime: bool,
8403 /// has this variable been referenced?
8404 used: bool = false,
8361 };8405 };
83628406
8363 const Defer = struct {8407 const Defer = struct {
test/stage2/test.zig+8
...@@ -246,6 +246,14 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -246,6 +246,14 @@ pub fn addCases(ctx: *TestContext) !void {
246 "",246 "",
247 );247 );
248 }248 }
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 }
249 {257 {
250 var case = ctx.exe("@TypeOf", linux_x64);258 var case = ctx.exe("@TypeOf", linux_x64);
251 case.addCompareOutput(259 case.addCompareOutput(