| ... | @@ -2685,11 +2685,7 @@ fn genDefers( | ... | @@ -2685,11 +2685,7 @@ fn genDefers( |
| 2685 | } | 2685 | } |
| 2686 | } | 2686 | } |
| 2687 | | 2687 | |
| 2688 | fn checkUsed( | 2688 | fn checkUsed(gz: *GenZir, outer_scope: *Scope, inner_scope: *Scope) InnerError!void { |
| 2689 | gz: *GenZir, | | |
| 2690 | outer_scope: *Scope, | | |
| 2691 | inner_scope: *Scope, | | |
| 2692 | ) InnerError!void { | | |
| 2693 | const astgen = gz.astgen; | 2689 | const astgen = gz.astgen; |
| 2694 | | 2690 | |
| 2695 | var scope = inner_scope; | 2691 | var scope = inner_scope; |
| ... | @@ -2698,15 +2694,23 @@ fn checkUsed( | ... | @@ -2698,15 +2694,23 @@ fn checkUsed( |
| 2698 | .gen_zir => scope = scope.cast(GenZir).?.parent, | 2694 | .gen_zir => scope = scope.cast(GenZir).?.parent, |
| 2699 | .local_val => { | 2695 | .local_val => { |
| 2700 | const s = scope.cast(Scope.LocalVal).?; | 2696 | const s = scope.cast(Scope.LocalVal).?; |
| 2701 | if (!s.used) { | 2697 | if (s.used == 0 and s.discarded == 0) { |
| 2702 | try astgen.appendErrorTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)}); | 2698 | try astgen.appendErrorTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)}); |
| | 2699 | } else if (s.used != 0 and s.discarded != 0) { |
| | 2700 | try astgen.appendErrorTokNotes(s.discarded, "pointless discard of {s}", .{@tagName(s.id_cat)}, &[_]u32{ |
| | 2701 | try gz.astgen.errNoteTok(s.used, "used here", .{}), |
| | 2702 | }); |
| 2703 | } | 2703 | } |
| 2704 | scope = s.parent; | 2704 | scope = s.parent; |
| 2705 | }, | 2705 | }, |
| 2706 | .local_ptr => { | 2706 | .local_ptr => { |
| 2707 | const s = scope.cast(Scope.LocalPtr).?; | 2707 | const s = scope.cast(Scope.LocalPtr).?; |
| 2708 | if (!s.used) { | 2708 | if (s.used == 0 and s.discarded == 0) { |
| 2709 | try astgen.appendErrorTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)}); | 2709 | try astgen.appendErrorTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)}); |
| | 2710 | } else if (s.used != 0 and s.discarded != 0) { |
| | 2711 | try astgen.appendErrorTokNotes(s.discarded, "pointless discard of {s}", .{@tagName(s.id_cat)}, &[_]u32{ |
| | 2712 | try gz.astgen.errNoteTok(s.used, "used here", .{}), |
| | 2713 | }); |
| 2710 | } | 2714 | } |
| 2711 | scope = s.parent; | 2715 | scope = s.parent; |
| 2712 | }, | 2716 | }, |
| ... | @@ -6848,11 +6852,10 @@ fn localVarRef( | ... | @@ -6848,11 +6852,10 @@ fn localVarRef( |
| 6848 | scope: *Scope, | 6852 | scope: *Scope, |
| 6849 | rl: ResultLoc, | 6853 | rl: ResultLoc, |
| 6850 | ident: Ast.Node.Index, | 6854 | ident: Ast.Node.Index, |
| 6851 | ident_token: Ast.Node.Index, | 6855 | ident_token: Ast.TokenIndex, |
| 6852 | ) InnerError!Zir.Inst.Ref { | 6856 | ) InnerError!Zir.Inst.Ref { |
| 6853 | const astgen = gz.astgen; | 6857 | const astgen = gz.astgen; |
| 6854 | const gpa = astgen.gpa; | 6858 | const gpa = astgen.gpa; |
| 6855 | | | |
| 6856 | const name_str_index = try astgen.identAsString(ident_token); | 6859 | const name_str_index = try astgen.identAsString(ident_token); |
| 6857 | var s = scope; | 6860 | var s = scope; |
| 6858 | var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already | 6861 | var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already |
| ... | @@ -6865,7 +6868,11 @@ fn localVarRef( | ... | @@ -6865,7 +6868,11 @@ fn localVarRef( |
| 6865 | if (local_val.name == name_str_index) { | 6868 | if (local_val.name == name_str_index) { |
| 6866 | // Locals cannot shadow anything, so we do not need to look for ambiguous | 6869 | // Locals cannot shadow anything, so we do not need to look for ambiguous |
| 6867 | // references in this case. | 6870 | // references in this case. |
| 6868 | local_val.used = true; | 6871 | if (rl == .discard) { |
| | 6872 | local_val.discarded = ident_token; |
| | 6873 | } else { |
| | 6874 | local_val.used = ident_token; |
| | 6875 | } |
| 6869 | | 6876 | |
| 6870 | const value_inst = try tunnelThroughClosure( | 6877 | const value_inst = try tunnelThroughClosure( |
| 6871 | gz, | 6878 | gz, |
| ... | @@ -6884,7 +6891,11 @@ fn localVarRef( | ... | @@ -6884,7 +6891,11 @@ fn localVarRef( |
| 6884 | .local_ptr => { | 6891 | .local_ptr => { |
| 6885 | const local_ptr = s.cast(Scope.LocalPtr).?; | 6892 | const local_ptr = s.cast(Scope.LocalPtr).?; |
| 6886 | if (local_ptr.name == name_str_index) { | 6893 | if (local_ptr.name == name_str_index) { |
| 6887 | local_ptr.used = true; | 6894 | if (rl == .discard) { |
| | 6895 | local_ptr.discarded = ident_token; |
| | 6896 | } else { |
| | 6897 | local_ptr.used = ident_token; |
| | 6898 | } |
| 6888 | | 6899 | |
| 6889 | // Can't close over a runtime variable | 6900 | // Can't close over a runtime variable |
| 6890 | if (num_namespaces_out != 0 and !local_ptr.maybe_comptime) { | 6901 | if (num_namespaces_out != 0 and !local_ptr.maybe_comptime) { |
| ... | @@ -7519,7 +7530,7 @@ fn builtinCall( | ... | @@ -7519,7 +7530,7 @@ fn builtinCall( |
| 7519 | .local_val => { | 7530 | .local_val => { |
| 7520 | const local_val = s.cast(Scope.LocalVal).?; | 7531 | const local_val = s.cast(Scope.LocalVal).?; |
| 7521 | if (local_val.name == decl_name) { | 7532 | if (local_val.name == decl_name) { |
| 7522 | local_val.used = true; | 7533 | local_val.used = ident_token; |
| 7523 | _ = try gz.addPlNode(.export_value, node, Zir.Inst.ExportValue{ | 7534 | _ = try gz.addPlNode(.export_value, node, Zir.Inst.ExportValue{ |
| 7524 | .operand = local_val.inst, | 7535 | .operand = local_val.inst, |
| 7525 | .options = try comptimeExpr(gz, scope, .{ .coerced_ty = .export_options_type }, params[1]), | 7536 | .options = try comptimeExpr(gz, scope, .{ .coerced_ty = .export_options_type }, params[1]), |
| ... | @@ -7533,7 +7544,7 @@ fn builtinCall( | ... | @@ -7533,7 +7544,7 @@ fn builtinCall( |
| 7533 | if (local_ptr.name == decl_name) { | 7544 | if (local_ptr.name == decl_name) { |
| 7534 | if (!local_ptr.maybe_comptime) | 7545 | if (!local_ptr.maybe_comptime) |
| 7535 | return astgen.failNode(params[0], "unable to export runtime-known value", .{}); | 7546 | return astgen.failNode(params[0], "unable to export runtime-known value", .{}); |
| 7536 | local_ptr.used = true; | 7547 | local_ptr.used = ident_token; |
| 7537 | const loaded = try gz.addUnNode(.load, local_ptr.ptr, node); | 7548 | const loaded = try gz.addUnNode(.load, local_ptr.ptr, node); |
| 7538 | _ = try gz.addPlNode(.export_value, node, Zir.Inst.ExportValue{ | 7549 | _ = try gz.addPlNode(.export_value, node, Zir.Inst.ExportValue{ |
| 7539 | .operand = loaded, | 7550 | .operand = loaded, |
| ... | @@ -10065,11 +10076,15 @@ const Scope = struct { | ... | @@ -10065,11 +10076,15 @@ const Scope = struct { |
| 10065 | inst: Zir.Inst.Ref, | 10076 | inst: Zir.Inst.Ref, |
| 10066 | /// Source location of the corresponding variable declaration. | 10077 | /// Source location of the corresponding variable declaration. |
| 10067 | token_src: Ast.TokenIndex, | 10078 | token_src: Ast.TokenIndex, |
| | 10079 | /// Track the first identifer where it is referenced. |
| | 10080 | /// 0 means never referenced. |
| | 10081 | used: Ast.TokenIndex = 0, |
| | 10082 | /// Track the identifier where it is discarded, like this `_ = foo;`. |
| | 10083 | /// 0 means never discarded. |
| | 10084 | discarded: Ast.TokenIndex = 0, |
| 10068 | /// String table index. | 10085 | /// String table index. |
| 10069 | name: u32, | 10086 | name: u32, |
| 10070 | id_cat: IdCat, | 10087 | id_cat: IdCat, |
| 10071 | /// Track whether the name has been referenced. | | |
| 10072 | used: bool = false, | | |
| 10073 | }; | 10088 | }; |
| 10074 | | 10089 | |
| 10075 | /// This could be a `const` or `var` local. It has a pointer instead of a value. | 10090 | /// This could be a `const` or `var` local. It has a pointer instead of a value. |
| ... | @@ -10084,14 +10099,18 @@ const Scope = struct { | ... | @@ -10084,14 +10099,18 @@ const Scope = struct { |
| 10084 | ptr: Zir.Inst.Ref, | 10099 | ptr: Zir.Inst.Ref, |
| 10085 | /// Source location of the corresponding variable declaration. | 10100 | /// Source location of the corresponding variable declaration. |
| 10086 | token_src: Ast.TokenIndex, | 10101 | token_src: Ast.TokenIndex, |
| | 10102 | /// Track the first identifer where it is referenced. |
| | 10103 | /// 0 means never referenced. |
| | 10104 | used: Ast.TokenIndex = 0, |
| | 10105 | /// Track the identifier where it is discarded, like this `_ = foo;`. |
| | 10106 | /// 0 means never discarded. |
| | 10107 | discarded: Ast.TokenIndex = 0, |
| 10087 | /// String table index. | 10108 | /// String table index. |
| 10088 | name: u32, | 10109 | name: u32, |
| 10089 | id_cat: IdCat, | 10110 | id_cat: IdCat, |
| 10090 | /// true means we find out during Sema whether the value is comptime. | 10111 | /// true means we find out during Sema whether the value is comptime. |
| 10091 | /// false means it is already known at AstGen the value is runtime-known. | 10112 | /// false means it is already known at AstGen the value is runtime-known. |
| 10092 | maybe_comptime: bool, | 10113 | maybe_comptime: bool, |
| 10093 | /// Track whether the name has been referenced. | | |
| 10094 | used: bool = false, | | |
| 10095 | }; | 10114 | }; |
| 10096 | | 10115 | |
| 10097 | const Defer = struct { | 10116 | const Defer = struct { |