| ... | ... | @@ -1826,6 +1826,7 @@ fn blockExprStmts( |
| 1826 | 1826 | } |
| 1827 | 1827 | |
| 1828 | 1828 | try genDefers(gz, parent_scope, scope, .none); |
| 1829 | try checkUsed(gz, parent_scope, scope); |
| 1829 | 1830 | } |
| 1830 | 1831 | |
| 1831 | 1832 | fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) InnerError!void { |
| ... | ... | @@ -2154,6 +2155,36 @@ fn genDefers( |
| 2154 | 2155 | } |
| 2155 | 2156 | } |
| 2156 | 2157 | |
| 2158 | fn 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 | |
| 2157 | 2188 | fn deferStmt( |
| 2158 | 2189 | gz: *GenZir, |
| 2159 | 2190 | scope: *Scope, |
| ... | ... | @@ -2930,6 +2961,7 @@ fn fnDecl( |
| 2930 | 2961 | .name = param_name, |
| 2931 | 2962 | .inst = arg_inst, |
| 2932 | 2963 | .token_src = name_token, |
| 2964 | // TODO make function paramater have different message instead of unused constant |
| 2933 | 2965 | }; |
| 2934 | 2966 | params_scope = &sub_scope.base; |
| 2935 | 2967 | |
| ... | ... | @@ -3370,6 +3402,7 @@ fn structDeclInner( |
| 3370 | 3402 | }; |
| 3371 | 3403 | defer block_scope.instructions.deinit(gpa); |
| 3372 | 3404 | |
| 3405 | // TODO should we change this to scope in other places too? |
| 3373 | 3406 | var namespace: Scope.Namespace = .{ .parent = scope }; |
| 3374 | 3407 | defer namespace.decls.deinit(gpa); |
| 3375 | 3408 | |
| ... | ... | @@ -6131,10 +6164,14 @@ fn identifier( |
| 6131 | 6164 | while (true) switch (s.tag) { |
| 6132 | 6165 | .local_val => { |
| 6133 | 6166 | const local_val = s.cast(Scope.LocalVal).?; |
| 6167 | if (local_val.name == name_str_index) { |
| 6168 | local_val.used = true; |
| 6169 | } |
| 6134 | 6170 | if (hit_namespace) { |
| 6135 | 6171 | // captures of non-locals need to be emitted as decl_val or decl_ref |
| 6136 | 6172 | // This *might* be capturable depending on if it is comptime known |
| 6137 | | break; |
| 6173 | s = local_val.parent; |
| 6174 | continue; |
| 6138 | 6175 | } |
| 6139 | 6176 | if (local_val.name == name_str_index) { |
| 6140 | 6177 | return rvalue(gz, scope, rl, local_val.inst, ident); |
| ... | ... | @@ -6144,6 +6181,7 @@ fn identifier( |
| 6144 | 6181 | .local_ptr => { |
| 6145 | 6182 | const local_ptr = s.cast(Scope.LocalPtr).?; |
| 6146 | 6183 | if (local_ptr.name == name_str_index) { |
| 6184 | local_ptr.used = true; |
| 6147 | 6185 | if (hit_namespace) { |
| 6148 | 6186 | if (local_ptr.is_comptime) |
| 6149 | 6187 | break |
| ... | ... | @@ -6151,6 +6189,8 @@ fn identifier( |
| 6151 | 6189 | return astgen.failNodeNotes(ident, "'{s}' not accessible from inner function", .{ident_name}, &.{ |
| 6152 | 6190 | try astgen.errNoteTok(local_ptr.token_src, "declared here", .{}), |
| 6153 | 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 | 6196 | switch (rl) { |
| ... | ... | @@ -8341,6 +8381,8 @@ const Scope = struct { |
| 8341 | 8381 | token_src: ast.TokenIndex, |
| 8342 | 8382 | /// String table index. |
| 8343 | 8383 | name: u32, |
| 8384 | /// has this variable been referenced? |
| 8385 | used: bool = false, |
| 8344 | 8386 | }; |
| 8345 | 8387 | |
| 8346 | 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 | 8400 | /// String table index. |
| 8359 | 8401 | name: u32, |
| 8360 | 8402 | is_comptime: bool, |
| 8403 | /// has this variable been referenced? |
| 8404 | used: bool = false, |
| 8361 | 8405 | }; |
| 8362 | 8406 | |
| 8363 | 8407 | const Defer = struct { |