| ... | @@ -2139,10 +2139,7 @@ fn genDefers( | ... | @@ -2139,10 +2139,7 @@ fn genDefers( |
| 2139 | .defer_error => { | 2139 | .defer_error => { |
| 2140 | const defer_scope = scope.cast(Scope.Defer).?; | 2140 | const defer_scope = scope.cast(Scope.Defer).?; |
| 2141 | scope = defer_scope.parent; | 2141 | scope = defer_scope.parent; |
| 2142 | // TODO add this back when we have more errdefer support | 2142 | if (err_code == .none) continue; |
| 2143 | // right now it is making stuff not get evaluated which causes | | |
| 2144 | // unused vars. | | |
| 2145 | // if (err_code == .none) continue; | | |
| 2146 | const expr_node = node_datas[defer_scope.defer_node].rhs; | 2143 | const expr_node = node_datas[defer_scope.defer_node].rhs; |
| 2147 | const prev_in_defer = gz.in_defer; | 2144 | const prev_in_defer = gz.in_defer; |
| 2148 | gz.in_defer = true; | 2145 | gz.in_defer = true; |
| ... | @@ -2168,12 +2165,26 @@ fn checkUsed( | ... | @@ -2168,12 +2165,26 @@ fn checkUsed( |
| 2168 | .gen_zir => scope = scope.cast(GenZir).?.parent, | 2165 | .gen_zir => scope = scope.cast(GenZir).?.parent, |
| 2169 | .local_val => { | 2166 | .local_val => { |
| 2170 | const s = scope.cast(Scope.LocalVal).?; | 2167 | const s = scope.cast(Scope.LocalVal).?; |
| 2171 | if (!s.used) return astgen.failTok(s.token_src, "unused local constant", .{}); | 2168 | switch (s.used) { |
| | 2169 | .used => {}, |
| | 2170 | .fn_param => return astgen.failTok(s.token_src, "unused function parameter", .{}), |
| | 2171 | .constant => return astgen.failTok(s.token_src, "unused local constant", .{}), |
| | 2172 | .variable => unreachable, |
| | 2173 | .loop_index => unreachable, |
| | 2174 | .capture => return astgen.failTok(s.token_src, "unused capture", .{}), |
| | 2175 | } |
| 2172 | scope = s.parent; | 2176 | scope = s.parent; |
| 2173 | }, | 2177 | }, |
| 2174 | .local_ptr => { | 2178 | .local_ptr => { |
| 2175 | const s = scope.cast(Scope.LocalPtr).?; | 2179 | const s = scope.cast(Scope.LocalPtr).?; |
| 2176 | if (!s.used) return astgen.failTok(s.token_src, "unused local variable", .{}); | 2180 | switch (s.used) { |
| | 2181 | .used => {}, |
| | 2182 | .fn_param => unreachable, |
| | 2183 | .constant => return astgen.failTok(s.token_src, "unused local constant", .{}), |
| | 2184 | .variable => return astgen.failTok(s.token_src, "unused local variable", .{}), |
| | 2185 | .loop_index => return astgen.failTok(s.token_src, "unused loop index capture", .{}), |
| | 2186 | .capture => unreachable, |
| | 2187 | } |
| 2177 | scope = s.parent; | 2188 | scope = s.parent; |
| 2178 | }, | 2189 | }, |
| 2179 | .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, | 2190 | .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, |
| ... | @@ -2303,6 +2314,7 @@ fn varDecl( | ... | @@ -2303,6 +2314,7 @@ fn varDecl( |
| 2303 | .name = ident_name, | 2314 | .name = ident_name, |
| 2304 | .inst = init_inst, | 2315 | .inst = init_inst, |
| 2305 | .token_src = name_token, | 2316 | .token_src = name_token, |
| | 2317 | .used = .constant, |
| 2306 | }; | 2318 | }; |
| 2307 | return &sub_scope.base; | 2319 | return &sub_scope.base; |
| 2308 | } | 2320 | } |
| ... | @@ -2370,6 +2382,7 @@ fn varDecl( | ... | @@ -2370,6 +2382,7 @@ fn varDecl( |
| 2370 | .name = ident_name, | 2382 | .name = ident_name, |
| 2371 | .inst = init_inst, | 2383 | .inst = init_inst, |
| 2372 | .token_src = name_token, | 2384 | .token_src = name_token, |
| | 2385 | .used = .constant, |
| 2373 | }; | 2386 | }; |
| 2374 | return &sub_scope.base; | 2387 | return &sub_scope.base; |
| 2375 | } | 2388 | } |
| ... | @@ -2399,6 +2412,7 @@ fn varDecl( | ... | @@ -2399,6 +2412,7 @@ fn varDecl( |
| 2399 | .ptr = init_scope.rl_ptr, | 2412 | .ptr = init_scope.rl_ptr, |
| 2400 | .token_src = name_token, | 2413 | .token_src = name_token, |
| 2401 | .maybe_comptime = true, | 2414 | .maybe_comptime = true, |
| | 2415 | .used = .constant, |
| 2402 | }; | 2416 | }; |
| 2403 | return &sub_scope.base; | 2417 | return &sub_scope.base; |
| 2404 | }, | 2418 | }, |
| ... | @@ -2455,6 +2469,7 @@ fn varDecl( | ... | @@ -2455,6 +2469,7 @@ fn varDecl( |
| 2455 | .ptr = var_data.alloc, | 2469 | .ptr = var_data.alloc, |
| 2456 | .token_src = name_token, | 2470 | .token_src = name_token, |
| 2457 | .maybe_comptime = is_comptime, | 2471 | .maybe_comptime = is_comptime, |
| | 2472 | .used = .variable, |
| 2458 | }; | 2473 | }; |
| 2459 | return &sub_scope.base; | 2474 | return &sub_scope.base; |
| 2460 | }, | 2475 | }, |
| ... | @@ -2943,6 +2958,10 @@ fn fnDecl( | ... | @@ -2943,6 +2958,10 @@ fn fnDecl( |
| 2943 | const name_token = param.name_token orelse { | 2958 | const name_token = param.name_token orelse { |
| 2944 | return astgen.failNode(param.type_expr, "missing parameter name", .{}); | 2959 | return astgen.failNode(param.type_expr, "missing parameter name", .{}); |
| 2945 | }; | 2960 | }; |
| | 2961 | if (param.type_expr != 0) |
| | 2962 | _ = try typeExpr(&fn_gz, params_scope, param.type_expr); |
| | 2963 | if (mem.eql(u8, "_", tree.tokenSlice(name_token))) |
| | 2964 | continue; |
| 2946 | const param_name = try astgen.identAsString(name_token); | 2965 | const param_name = try astgen.identAsString(name_token); |
| 2947 | // Create an arg instruction. This is needed to emit a semantic analysis | 2966 | // Create an arg instruction. This is needed to emit a semantic analysis |
| 2948 | // error for shadowing decls. | 2967 | // error for shadowing decls. |
| ... | @@ -2955,17 +2974,19 @@ fn fnDecl( | ... | @@ -2955,17 +2974,19 @@ fn fnDecl( |
| 2955 | .name = param_name, | 2974 | .name = param_name, |
| 2956 | .inst = arg_inst, | 2975 | .inst = arg_inst, |
| 2957 | .token_src = name_token, | 2976 | .token_src = name_token, |
| 2958 | // TODO make function paramater have different message instead of unused constant | 2977 | .used = .fn_param, |
| 2959 | }; | 2978 | }; |
| 2960 | params_scope = &sub_scope.base; | 2979 | params_scope = &sub_scope.base; |
| 2961 | | 2980 | |
| 2962 | // Additionally put the param name into `string_bytes` and reference it with | 2981 | // Additionally put the param name into `string_bytes` and reference it with |
| 2963 | // `extra` so that we have access to the data in codegen, for debug info. | 2982 | // `extra` so that we have access to the data in codegen, for debug info. |
| 2964 | const str_index = try astgen.identAsString(name_token); | 2983 | const str_index = try astgen.identAsString(name_token); |
| 2965 | astgen.extra.appendAssumeCapacity(str_index); | 2984 | try astgen.extra.append(astgen.gpa, str_index); |
| 2966 | } | 2985 | } |
| | 2986 | _ = try typeExpr(&fn_gz, params_scope, fn_proto.ast.return_type); |
| 2967 | | 2987 | |
| 2968 | _ = try expr(&fn_gz, params_scope, .none, body_node); | 2988 | _ = try expr(&fn_gz, params_scope, .none, body_node); |
| | 2989 | try checkUsed(gz, &fn_gz.base, params_scope); |
| 2969 | } | 2990 | } |
| 2970 | | 2991 | |
| 2971 | const need_implicit_ret = blk: { | 2992 | const need_implicit_ret = blk: { |
| ... | @@ -3396,7 +3417,6 @@ fn structDeclInner( | ... | @@ -3396,7 +3417,6 @@ fn structDeclInner( |
| 3396 | }; | 3417 | }; |
| 3397 | defer block_scope.instructions.deinit(gpa); | 3418 | defer block_scope.instructions.deinit(gpa); |
| 3398 | | 3419 | |
| 3399 | // TODO should we change this to scope in other places too? | | |
| 3400 | var namespace: Scope.Namespace = .{ .parent = scope }; | 3420 | var namespace: Scope.Namespace = .{ .parent = scope }; |
| 3401 | defer namespace.decls.deinit(gpa); | 3421 | defer namespace.decls.deinit(gpa); |
| 3402 | | 3422 | |
| ... | @@ -3659,7 +3679,7 @@ fn unionDeclInner( | ... | @@ -3659,7 +3679,7 @@ fn unionDeclInner( |
| 3659 | }; | 3679 | }; |
| 3660 | defer block_scope.instructions.deinit(gpa); | 3680 | defer block_scope.instructions.deinit(gpa); |
| 3661 | | 3681 | |
| 3662 | var namespace: Scope.Namespace = .{ .parent = &gz.base }; | 3682 | var namespace: Scope.Namespace = .{ .parent = scope }; |
| 3663 | defer namespace.decls.deinit(gpa); | 3683 | defer namespace.decls.deinit(gpa); |
| 3664 | | 3684 | |
| 3665 | var wip_decls: WipDecls = .{}; | 3685 | var wip_decls: WipDecls = .{}; |
| ... | @@ -4060,7 +4080,7 @@ fn containerDecl( | ... | @@ -4060,7 +4080,7 @@ fn containerDecl( |
| 4060 | }; | 4080 | }; |
| 4061 | defer block_scope.instructions.deinit(gpa); | 4081 | defer block_scope.instructions.deinit(gpa); |
| 4062 | | 4082 | |
| 4063 | var namespace: Scope.Namespace = .{ .parent = &gz.base }; | 4083 | var namespace: Scope.Namespace = .{ .parent = scope }; |
| 4064 | defer namespace.decls.deinit(gpa); | 4084 | defer namespace.decls.deinit(gpa); |
| 4065 | | 4085 | |
| 4066 | var wip_decls: WipDecls = .{}; | 4086 | var wip_decls: WipDecls = .{}; |
| ... | @@ -4287,7 +4307,7 @@ fn containerDecl( | ... | @@ -4287,7 +4307,7 @@ fn containerDecl( |
| 4287 | return rvalue(gz, scope, rl, gz.indexToRef(decl_inst), node); | 4307 | return rvalue(gz, scope, rl, gz.indexToRef(decl_inst), node); |
| 4288 | }, | 4308 | }, |
| 4289 | .keyword_opaque => { | 4309 | .keyword_opaque => { |
| 4290 | var namespace: Scope.Namespace = .{ .parent = &gz.base }; | 4310 | var namespace: Scope.Namespace = .{ .parent = scope }; |
| 4291 | defer namespace.decls.deinit(gpa); | 4311 | defer namespace.decls.deinit(gpa); |
| 4292 | | 4312 | |
| 4293 | var wip_decls: WipDecls = .{}; | 4313 | var wip_decls: WipDecls = .{}; |
| ... | @@ -4622,12 +4642,15 @@ fn orelseCatchExpr( | ... | @@ -4622,12 +4642,15 @@ fn orelseCatchExpr( |
| 4622 | .name = err_name, | 4642 | .name = err_name, |
| 4623 | .inst = try then_scope.addUnNode(unwrap_code_op, operand, node), | 4643 | .inst = try then_scope.addUnNode(unwrap_code_op, operand, node), |
| 4624 | .token_src = payload, | 4644 | .token_src = payload, |
| | 4645 | .used = .capture, |
| 4625 | }; | 4646 | }; |
| 4626 | break :blk &err_val_scope.base; | 4647 | break :blk &err_val_scope.base; |
| 4627 | }; | 4648 | }; |
| 4628 | | 4649 | |
| 4629 | block_scope.break_count += 1; | 4650 | block_scope.break_count += 1; |
| 4630 | const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_loc, rhs); | 4651 | const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_loc, rhs); |
| | 4652 | try checkUsed(parent_gz, &then_scope.base, then_sub_scope); |
| | 4653 | |
| 4631 | // We hold off on the break instructions as well as copying the then/else | 4654 | // We hold off on the break instructions as well as copying the then/else |
| 4632 | // instructions into place until we know whether to keep store_to_block_ptr | 4655 | // instructions into place until we know whether to keep store_to_block_ptr |
| 4633 | // instructions or not. | 4656 | // instructions or not. |
| ... | @@ -4900,27 +4923,38 @@ fn ifExpr( | ... | @@ -4900,27 +4923,38 @@ fn ifExpr( |
| 4900 | var payload_val_scope: Scope.LocalVal = undefined; | 4923 | var payload_val_scope: Scope.LocalVal = undefined; |
| 4901 | | 4924 | |
| 4902 | const then_sub_scope = s: { | 4925 | const then_sub_scope = s: { |
| 4903 | if (if_full.error_token) |error_token| { | 4926 | if (if_full.error_token != null) { |
| 4904 | const tag: Zir.Inst.Tag = if (payload_is_ref) | 4927 | if (if_full.payload_token) |payload_token| { |
| 4905 | .err_union_payload_unsafe_ptr | 4928 | const tag: Zir.Inst.Tag = if (payload_is_ref) |
| 4906 | else | 4929 | .err_union_payload_unsafe_ptr |
| 4907 | .err_union_payload_unsafe; | 4930 | else |
| 4908 | const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); | 4931 | .err_union_payload_unsafe; |
| 4909 | const ident_name = try astgen.identAsString(error_token); | 4932 | const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); |
| 4910 | payload_val_scope = .{ | 4933 | const token_name_index = payload_token + @boolToInt(payload_is_ref); |
| 4911 | .parent = &then_scope.base, | 4934 | const ident_name = try astgen.identAsString(token_name_index); |
| 4912 | .gen_zir = &then_scope, | 4935 | const token_name_str = tree.tokenSlice(token_name_index); |
| 4913 | .name = ident_name, | 4936 | if (mem.eql(u8, "_", token_name_str)) |
| 4914 | .inst = payload_inst, | 4937 | break :s &then_scope.base; |
| 4915 | .token_src = error_token, | 4938 | payload_val_scope = .{ |
| 4916 | }; | 4939 | .parent = &then_scope.base, |
| 4917 | break :s &payload_val_scope.base; | 4940 | .gen_zir = &then_scope, |
| | 4941 | .name = ident_name, |
| | 4942 | .inst = payload_inst, |
| | 4943 | .token_src = payload_token, |
| | 4944 | .used = .capture, |
| | 4945 | }; |
| | 4946 | break :s &payload_val_scope.base; |
| | 4947 | } else { |
| | 4948 | break :s &then_scope.base; |
| | 4949 | } |
| 4918 | } else if (if_full.payload_token) |payload_token| { | 4950 | } else if (if_full.payload_token) |payload_token| { |
| 4919 | const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; | 4951 | const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; |
| 4920 | const tag: Zir.Inst.Tag = if (payload_is_ref) | 4952 | const tag: Zir.Inst.Tag = if (payload_is_ref) |
| 4921 | .optional_payload_unsafe_ptr | 4953 | .optional_payload_unsafe_ptr |
| 4922 | else | 4954 | else |
| 4923 | .optional_payload_unsafe; | 4955 | .optional_payload_unsafe; |
| | 4956 | if (mem.eql(u8, "_", tree.tokenSlice(ident_token))) |
| | 4957 | break :s &then_scope.base; |
| 4924 | const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); | 4958 | const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); |
| 4925 | const ident_name = try astgen.identAsString(ident_token); | 4959 | const ident_name = try astgen.identAsString(ident_token); |
| 4926 | payload_val_scope = .{ | 4960 | payload_val_scope = .{ |
| ... | @@ -4929,6 +4963,7 @@ fn ifExpr( | ... | @@ -4929,6 +4963,7 @@ fn ifExpr( |
| 4929 | .name = ident_name, | 4963 | .name = ident_name, |
| 4930 | .inst = payload_inst, | 4964 | .inst = payload_inst, |
| 4931 | .token_src = ident_token, | 4965 | .token_src = ident_token, |
| | 4966 | .used = .capture, |
| 4932 | }; | 4967 | }; |
| 4933 | break :s &payload_val_scope.base; | 4968 | break :s &payload_val_scope.base; |
| 4934 | } else { | 4969 | } else { |
| ... | @@ -4938,6 +4973,7 @@ fn ifExpr( | ... | @@ -4938,6 +4973,7 @@ fn ifExpr( |
| 4938 | | 4973 | |
| 4939 | block_scope.break_count += 1; | 4974 | block_scope.break_count += 1; |
| 4940 | const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_loc, if_full.ast.then_expr); | 4975 | const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_loc, if_full.ast.then_expr); |
| | 4976 | try checkUsed(parent_gz, &then_scope.base, then_sub_scope); |
| 4941 | // We hold off on the break instructions as well as copying the then/else | 4977 | // We hold off on the break instructions as well as copying the then/else |
| 4942 | // instructions into place until we know whether to keep store_to_block_ptr | 4978 | // instructions into place until we know whether to keep store_to_block_ptr |
| 4943 | // instructions or not. | 4979 | // instructions or not. |
| ... | @@ -4959,21 +4995,27 @@ fn ifExpr( | ... | @@ -4959,21 +4995,27 @@ fn ifExpr( |
| 4959 | .err_union_code; | 4995 | .err_union_code; |
| 4960 | const payload_inst = try else_scope.addUnNode(tag, cond.inst, node); | 4996 | const payload_inst = try else_scope.addUnNode(tag, cond.inst, node); |
| 4961 | const ident_name = try astgen.identAsString(error_token); | 4997 | const ident_name = try astgen.identAsString(error_token); |
| | 4998 | const error_token_str = tree.tokenSlice(error_token); |
| | 4999 | if (mem.eql(u8, "_", error_token_str)) |
| | 5000 | break :s &else_scope.base; |
| 4962 | payload_val_scope = .{ | 5001 | payload_val_scope = .{ |
| 4963 | .parent = &else_scope.base, | 5002 | .parent = &else_scope.base, |
| 4964 | .gen_zir = &else_scope, | 5003 | .gen_zir = &else_scope, |
| 4965 | .name = ident_name, | 5004 | .name = ident_name, |
| 4966 | .inst = payload_inst, | 5005 | .inst = payload_inst, |
| 4967 | .token_src = error_token, | 5006 | .token_src = error_token, |
| | 5007 | .used = .capture, |
| 4968 | }; | 5008 | }; |
| 4969 | break :s &payload_val_scope.base; | 5009 | break :s &payload_val_scope.base; |
| 4970 | } else { | 5010 | } else { |
| 4971 | break :s &else_scope.base; | 5011 | break :s &else_scope.base; |
| 4972 | } | 5012 | } |
| 4973 | }; | 5013 | }; |
| | 5014 | const e = try expr(&else_scope, sub_scope, block_scope.break_result_loc, else_node); |
| | 5015 | try checkUsed(parent_gz, &else_scope.base, sub_scope); |
| 4974 | break :blk .{ | 5016 | break :blk .{ |
| 4975 | .src = else_node, | 5017 | .src = else_node, |
| 4976 | .result = try expr(&else_scope, sub_scope, block_scope.break_result_loc, else_node), | 5018 | .result = e, |
| 4977 | }; | 5019 | }; |
| 4978 | } else .{ | 5020 | } else .{ |
| 4979 | .src = if_full.ast.then_expr, | 5021 | .src = if_full.ast.then_expr, |
| ... | @@ -5161,21 +5203,29 @@ fn whileExpr( | ... | @@ -5161,21 +5203,29 @@ fn whileExpr( |
| 5161 | var payload_val_scope: Scope.LocalVal = undefined; | 5203 | var payload_val_scope: Scope.LocalVal = undefined; |
| 5162 | | 5204 | |
| 5163 | const then_sub_scope = s: { | 5205 | const then_sub_scope = s: { |
| 5164 | if (while_full.error_token) |error_token| { | 5206 | if (while_full.error_token != null) { |
| 5165 | const tag: Zir.Inst.Tag = if (payload_is_ref) | 5207 | if (while_full.payload_token) |payload_token| { |
| 5166 | .err_union_payload_unsafe_ptr | 5208 | const tag: Zir.Inst.Tag = if (payload_is_ref) |
| 5167 | else | 5209 | .err_union_payload_unsafe_ptr |
| 5168 | .err_union_payload_unsafe; | 5210 | else |
| 5169 | const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); | 5211 | .err_union_payload_unsafe; |
| 5170 | const ident_name = try astgen.identAsString(error_token); | 5212 | const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); |
| 5171 | payload_val_scope = .{ | 5213 | const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; |
| 5172 | .parent = &then_scope.base, | 5214 | if (mem.eql(u8, "_", tree.tokenSlice(ident_token))) |
| 5173 | .gen_zir = &then_scope, | 5215 | break :s &then_scope.base; |
| 5174 | .name = ident_name, | 5216 | const ident_name = try astgen.identAsString(payload_token + @boolToInt(payload_is_ref)); |
| 5175 | .inst = payload_inst, | 5217 | payload_val_scope = .{ |
| 5176 | .token_src = error_token, | 5218 | .parent = &then_scope.base, |
| 5177 | }; | 5219 | .gen_zir = &then_scope, |
| 5178 | break :s &payload_val_scope.base; | 5220 | .name = ident_name, |
| | 5221 | .inst = payload_inst, |
| | 5222 | .token_src = payload_token, |
| | 5223 | .used = .capture, |
| | 5224 | }; |
| | 5225 | break :s &payload_val_scope.base; |
| | 5226 | } else { |
| | 5227 | break :s &then_scope.base; |
| | 5228 | } |
| 5179 | } else if (while_full.payload_token) |payload_token| { | 5229 | } else if (while_full.payload_token) |payload_token| { |
| 5180 | const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; | 5230 | const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; |
| 5181 | const tag: Zir.Inst.Tag = if (payload_is_ref) | 5231 | const tag: Zir.Inst.Tag = if (payload_is_ref) |
| ... | @@ -5184,12 +5234,15 @@ fn whileExpr( | ... | @@ -5184,12 +5234,15 @@ fn whileExpr( |
| 5184 | .optional_payload_unsafe; | 5234 | .optional_payload_unsafe; |
| 5185 | const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); | 5235 | const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); |
| 5186 | const ident_name = try astgen.identAsString(ident_token); | 5236 | const ident_name = try astgen.identAsString(ident_token); |
| | 5237 | if (mem.eql(u8, "_", tree.tokenSlice(ident_token))) |
| | 5238 | break :s &then_scope.base; |
| 5187 | payload_val_scope = .{ | 5239 | payload_val_scope = .{ |
| 5188 | .parent = &then_scope.base, | 5240 | .parent = &then_scope.base, |
| 5189 | .gen_zir = &then_scope, | 5241 | .gen_zir = &then_scope, |
| 5190 | .name = ident_name, | 5242 | .name = ident_name, |
| 5191 | .inst = payload_inst, | 5243 | .inst = payload_inst, |
| 5192 | .token_src = ident_token, | 5244 | .token_src = ident_token, |
| | 5245 | .used = .capture, |
| 5193 | }; | 5246 | }; |
| 5194 | break :s &payload_val_scope.base; | 5247 | break :s &payload_val_scope.base; |
| 5195 | } else { | 5248 | } else { |
| ... | @@ -5199,6 +5252,7 @@ fn whileExpr( | ... | @@ -5199,6 +5252,7 @@ fn whileExpr( |
| 5199 | | 5252 | |
| 5200 | loop_scope.break_count += 1; | 5253 | loop_scope.break_count += 1; |
| 5201 | const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr); | 5254 | const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr); |
| | 5255 | try checkUsed(parent_gz, &then_scope.base, then_sub_scope); |
| 5202 | | 5256 | |
| 5203 | var else_scope = parent_gz.makeSubBlock(&continue_scope.base); | 5257 | var else_scope = parent_gz.makeSubBlock(&continue_scope.base); |
| 5204 | defer else_scope.instructions.deinit(astgen.gpa); | 5258 | defer else_scope.instructions.deinit(astgen.gpa); |
| ... | @@ -5217,21 +5271,26 @@ fn whileExpr( | ... | @@ -5217,21 +5271,26 @@ fn whileExpr( |
| 5217 | .err_union_code; | 5271 | .err_union_code; |
| 5218 | const payload_inst = try else_scope.addUnNode(tag, cond.inst, node); | 5272 | const payload_inst = try else_scope.addUnNode(tag, cond.inst, node); |
| 5219 | const ident_name = try astgen.identAsString(error_token); | 5273 | const ident_name = try astgen.identAsString(error_token); |
| | 5274 | if (mem.eql(u8, tree.tokenSlice(error_token), "_")) |
| | 5275 | break :s &else_scope.base; |
| 5220 | payload_val_scope = .{ | 5276 | payload_val_scope = .{ |
| 5221 | .parent = &else_scope.base, | 5277 | .parent = &else_scope.base, |
| 5222 | .gen_zir = &else_scope, | 5278 | .gen_zir = &else_scope, |
| 5223 | .name = ident_name, | 5279 | .name = ident_name, |
| 5224 | .inst = payload_inst, | 5280 | .inst = payload_inst, |
| 5225 | .token_src = error_token, | 5281 | .token_src = error_token, |
| | 5282 | .used = .capture, |
| 5226 | }; | 5283 | }; |
| 5227 | break :s &payload_val_scope.base; | 5284 | break :s &payload_val_scope.base; |
| 5228 | } else { | 5285 | } else { |
| 5229 | break :s &else_scope.base; | 5286 | break :s &else_scope.base; |
| 5230 | } | 5287 | } |
| 5231 | }; | 5288 | }; |
| | 5289 | const e = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node); |
| | 5290 | try checkUsed(parent_gz, &else_scope.base, sub_scope); |
| 5232 | break :blk .{ | 5291 | break :blk .{ |
| 5233 | .src = else_node, | 5292 | .src = else_node, |
| 5234 | .result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node), | 5293 | .result = e, |
| 5235 | }; | 5294 | }; |
| 5236 | } else .{ | 5295 | } else .{ |
| 5237 | .src = while_full.ast.then_expr, | 5296 | .src = while_full.ast.then_expr, |
| ... | @@ -5362,6 +5421,7 @@ fn forExpr( | ... | @@ -5362,6 +5421,7 @@ fn forExpr( |
| 5362 | .name = name_str_index, | 5421 | .name = name_str_index, |
| 5363 | .inst = payload_inst, | 5422 | .inst = payload_inst, |
| 5364 | .token_src = ident, | 5423 | .token_src = ident, |
| | 5424 | .used = .capture, |
| 5365 | }; | 5425 | }; |
| 5366 | payload_sub_scope = &payload_val_scope.base; | 5426 | payload_sub_scope = &payload_val_scope.base; |
| 5367 | } else if (is_ptr) { | 5427 | } else if (is_ptr) { |
| ... | @@ -5385,12 +5445,14 @@ fn forExpr( | ... | @@ -5385,12 +5445,14 @@ fn forExpr( |
| 5385 | .ptr = index_ptr, | 5445 | .ptr = index_ptr, |
| 5386 | .token_src = index_token, | 5446 | .token_src = index_token, |
| 5387 | .maybe_comptime = is_inline, | 5447 | .maybe_comptime = is_inline, |
| | 5448 | .used = .loop_index, |
| 5388 | }; | 5449 | }; |
| 5389 | break :blk &index_scope.base; | 5450 | break :blk &index_scope.base; |
| 5390 | }; | 5451 | }; |
| 5391 | | 5452 | |
| 5392 | loop_scope.break_count += 1; | 5453 | loop_scope.break_count += 1; |
| 5393 | const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr); | 5454 | const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr); |
| | 5455 | try checkUsed(parent_gz, &then_scope.base, then_sub_scope); |
| 5394 | | 5456 | |
| 5395 | var else_scope = parent_gz.makeSubBlock(&cond_scope.base); | 5457 | var else_scope = parent_gz.makeSubBlock(&cond_scope.base); |
| 5396 | defer else_scope.instructions.deinit(astgen.gpa); | 5458 | defer else_scope.instructions.deinit(astgen.gpa); |
| ... | @@ -5631,10 +5693,12 @@ fn switchExpr( | ... | @@ -5631,10 +5693,12 @@ fn switchExpr( |
| 5631 | .name = capture_name, | 5693 | .name = capture_name, |
| 5632 | .inst = capture, | 5694 | .inst = capture, |
| 5633 | .token_src = payload_token, | 5695 | .token_src = payload_token, |
| | 5696 | .used = .capture, |
| 5634 | }; | 5697 | }; |
| 5635 | break :blk &capture_val_scope.base; | 5698 | break :blk &capture_val_scope.base; |
| 5636 | }; | 5699 | }; |
| 5637 | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); | 5700 | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); |
| | 5701 | try checkUsed(parent_gz, &case_scope.base, sub_scope); |
| 5638 | if (!parent_gz.refIsNoReturn(case_result)) { | 5702 | if (!parent_gz.refIsNoReturn(case_result)) { |
| 5639 | block_scope.break_count += 1; | 5703 | block_scope.break_count += 1; |
| 5640 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); | 5704 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); |
| ... | @@ -5723,6 +5787,7 @@ fn switchExpr( | ... | @@ -5723,6 +5787,7 @@ fn switchExpr( |
| 5723 | .name = capture_name, | 5787 | .name = capture_name, |
| 5724 | .inst = capture, | 5788 | .inst = capture, |
| 5725 | .token_src = payload_token, | 5789 | .token_src = payload_token, |
| | 5790 | .used = .capture, |
| 5726 | }; | 5791 | }; |
| 5727 | break :blk &capture_val_scope.base; | 5792 | break :blk &capture_val_scope.base; |
| 5728 | }; | 5793 | }; |
| ... | @@ -5756,6 +5821,7 @@ fn switchExpr( | ... | @@ -5756,6 +5821,7 @@ fn switchExpr( |
| 5756 | } | 5821 | } |
| 5757 | | 5822 | |
| 5758 | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); | 5823 | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); |
| | 5824 | try checkUsed(parent_gz, &case_scope.base, sub_scope); |
| 5759 | if (!parent_gz.refIsNoReturn(case_result)) { | 5825 | if (!parent_gz.refIsNoReturn(case_result)) { |
| 5760 | block_scope.break_count += 1; | 5826 | block_scope.break_count += 1; |
| 5761 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); | 5827 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); |
| ... | @@ -5769,6 +5835,7 @@ fn switchExpr( | ... | @@ -5769,6 +5835,7 @@ fn switchExpr( |
| 5769 | const item_node = case.ast.values[0]; | 5835 | const item_node = case.ast.values[0]; |
| 5770 | const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node); | 5836 | const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node); |
| 5771 | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); | 5837 | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); |
| | 5838 | try checkUsed(parent_gz, &case_scope.base, sub_scope); |
| 5772 | if (!parent_gz.refIsNoReturn(case_result)) { | 5839 | if (!parent_gz.refIsNoReturn(case_result)) { |
| 5773 | block_scope.break_count += 1; | 5840 | block_scope.break_count += 1; |
| 5774 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); | 5841 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); |
| ... | @@ -6147,24 +6214,21 @@ fn identifier( | ... | @@ -6147,24 +6214,21 @@ fn identifier( |
| 6147 | while (true) switch (s.tag) { | 6214 | while (true) switch (s.tag) { |
| 6148 | .local_val => { | 6215 | .local_val => { |
| 6149 | const local_val = s.cast(Scope.LocalVal).?; | 6216 | const local_val = s.cast(Scope.LocalVal).?; |
| | 6217 | |
| 6150 | if (local_val.name == name_str_index) { | 6218 | if (local_val.name == name_str_index) { |
| 6151 | local_val.used = true; | 6219 | local_val.used = .used; |
| 6152 | } | 6220 | // Captures of non-locals need to be emitted as decl_val or decl_ref. |
| 6153 | if (hit_namespace) { | 6221 | // This *might* be capturable depending on if it is comptime known. |
| 6154 | // captures of non-locals need to be emitted as decl_val or decl_ref | 6222 | if (!hit_namespace) { |
| 6155 | // This *might* be capturable depending on if it is comptime known | 6223 | return rvalue(gz, scope, rl, local_val.inst, ident); |
| 6156 | s = local_val.parent; | 6224 | } |
| 6157 | continue; | | |
| 6158 | } | | |
| 6159 | if (local_val.name == name_str_index) { | | |
| 6160 | return rvalue(gz, scope, rl, local_val.inst, ident); | | |
| 6161 | } | 6225 | } |
| 6162 | s = local_val.parent; | 6226 | s = local_val.parent; |
| 6163 | }, | 6227 | }, |
| 6164 | .local_ptr => { | 6228 | .local_ptr => { |
| 6165 | const local_ptr = s.cast(Scope.LocalPtr).?; | 6229 | const local_ptr = s.cast(Scope.LocalPtr).?; |
| 6166 | if (local_ptr.name == name_str_index) { | 6230 | if (local_ptr.name == name_str_index) { |
| 6167 | local_ptr.used = true; | 6231 | local_ptr.used = .used; |
| 6168 | if (hit_namespace) { | 6232 | if (hit_namespace) { |
| 6169 | if (local_ptr.maybe_comptime) | 6233 | if (local_ptr.maybe_comptime) |
| 6170 | break | 6234 | break |
| ... | @@ -6456,7 +6520,7 @@ fn asmExpr( | ... | @@ -6456,7 +6520,7 @@ fn asmExpr( |
| 6456 | .local_val => { | 6520 | .local_val => { |
| 6457 | const local_val = s.cast(Scope.LocalVal).?; | 6521 | const local_val = s.cast(Scope.LocalVal).?; |
| 6458 | if (local_val.name == str_index) { | 6522 | if (local_val.name == str_index) { |
| 6459 | local_val.used = true; | 6523 | local_val.used = .used; |
| 6460 | break; | 6524 | break; |
| 6461 | } | 6525 | } |
| 6462 | s = local_val.parent; | 6526 | s = local_val.parent; |
| ... | @@ -6464,7 +6528,7 @@ fn asmExpr( | ... | @@ -6464,7 +6528,7 @@ fn asmExpr( |
| 6464 | .local_ptr => { | 6528 | .local_ptr => { |
| 6465 | const local_ptr = s.cast(Scope.LocalPtr).?; | 6529 | const local_ptr = s.cast(Scope.LocalPtr).?; |
| 6466 | if (local_ptr.name == str_index) { | 6530 | if (local_ptr.name == str_index) { |
| 6467 | local_ptr.used = true; | 6531 | local_ptr.used = .used; |
| 6468 | break; | 6532 | break; |
| 6469 | } | 6533 | } |
| 6470 | s = local_ptr.parent; | 6534 | s = local_ptr.parent; |
| ... | @@ -6815,7 +6879,7 @@ fn builtinCall( | ... | @@ -6815,7 +6879,7 @@ fn builtinCall( |
| 6815 | .local_val => { | 6879 | .local_val => { |
| 6816 | const local_val = s.cast(Scope.LocalVal).?; | 6880 | const local_val = s.cast(Scope.LocalVal).?; |
| 6817 | if (local_val.name == decl_name) { | 6881 | if (local_val.name == decl_name) { |
| 6818 | local_val.used = true; | 6882 | local_val.used = .used; |
| 6819 | break; | 6883 | break; |
| 6820 | } | 6884 | } |
| 6821 | s = local_val.parent; | 6885 | s = local_val.parent; |
| ... | @@ -6825,7 +6889,7 @@ fn builtinCall( | ... | @@ -6825,7 +6889,7 @@ fn builtinCall( |
| 6825 | if (local_ptr.name == decl_name) { | 6889 | if (local_ptr.name == decl_name) { |
| 6826 | if (!local_ptr.maybe_comptime) | 6890 | if (!local_ptr.maybe_comptime) |
| 6827 | return astgen.failNode(params[0], "unable to export runtime-known value", .{}); | 6891 | return astgen.failNode(params[0], "unable to export runtime-known value", .{}); |
| 6828 | local_ptr.used = true; | 6892 | local_ptr.used = .used; |
| 6829 | break; | 6893 | break; |
| 6830 | } | 6894 | } |
| 6831 | s = local_ptr.parent; | 6895 | s = local_ptr.parent; |
| ... | @@ -8394,6 +8458,15 @@ const Scope = struct { | ... | @@ -8394,6 +8458,15 @@ const Scope = struct { |
| 8394 | top, | 8458 | top, |
| 8395 | }; | 8459 | }; |
| 8396 | | 8460 | |
| | 8461 | // either .used or the type of the var/constant |
| | 8462 | const Used = enum { |
| | 8463 | fn_param, |
| | 8464 | constant, |
| | 8465 | variable, |
| | 8466 | loop_index, |
| | 8467 | capture, |
| | 8468 | used, |
| | 8469 | }; |
| 8397 | /// This is always a `const` local and importantly the `inst` is a value type, not a pointer. | 8470 | /// This is always a `const` local and importantly the `inst` is a value type, not a pointer. |
| 8398 | /// This structure lives as long as the AST generation of the Block | 8471 | /// This structure lives as long as the AST generation of the Block |
| 8399 | /// node that contains the variable. | 8472 | /// node that contains the variable. |
| ... | @@ -8409,7 +8482,7 @@ const Scope = struct { | ... | @@ -8409,7 +8482,7 @@ const Scope = struct { |
| 8409 | /// String table index. | 8482 | /// String table index. |
| 8410 | name: u32, | 8483 | name: u32, |
| 8411 | /// has this variable been referenced? | 8484 | /// has this variable been referenced? |
| 8412 | used: bool = false, | 8485 | used: Used, |
| 8413 | }; | 8486 | }; |
| 8414 | | 8487 | |
| 8415 | /// This could be a `const` or `var` local. It has a pointer instead of a value. | 8488 | /// This could be a `const` or `var` local. It has a pointer instead of a value. |
| ... | @@ -8429,7 +8502,7 @@ const Scope = struct { | ... | @@ -8429,7 +8502,7 @@ const Scope = struct { |
| 8429 | /// true means we find out during Sema whether the value is comptime. false means it is already known at AstGen the value is runtime-known. | 8502 | /// true means we find out during Sema whether the value is comptime. false means it is already known at AstGen the value is runtime-known. |
| 8430 | maybe_comptime: bool, | 8503 | maybe_comptime: bool, |
| 8431 | /// has this variable been referenced? | 8504 | /// has this variable been referenced? |
| 8432 | used: bool = false, | 8505 | used: Used, |
| 8433 | }; | 8506 | }; |
| 8434 | | 8507 | |
| 8435 | const Defer = struct { | 8508 | const Defer = struct { |