| ... | @@ -1826,6 +1826,7 @@ fn blockExprStmts( | ... | @@ -1826,6 +1826,7 @@ fn blockExprStmts( |
| 1826 | } | 1826 | } |
| 1827 | | 1827 | |
| 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 | } |
| 1830 | | 1831 | |
| 1831 | fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) InnerError!void { | 1832 | fn 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 | } |
| 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 | fn deferStmt( | 2188 | fn 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; |
| 2935 | | 2967 | |
| ... | @@ -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); |
| 3372 | | 3404 | |
| | 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); |
| 3375 | | 3408 | |
| ... | @@ -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_ref | 6171 | // 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 known | 6172 | // 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 | break | 6187 | 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 | }; |
| 8345 | | 8387 | |
| 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 | }; |
| 8362 | | 8406 | |
| 8363 | const Defer = struct { | 8407 | const Defer = struct { |