authorgravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-06-19 21:09:26-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-06-21 17:03:03-07:00
logb83b3883ba0b5e965f8f7f1298c77c6d766741af
tree5b6d0c9a9819721a862baa65283794adf6acf237
parent641ecc260f43ffb2398acb80cbd141535dbbb03d

stage2 AstGen: fix lots of bugs and catch more errors

Gotta catch 'em all! also simplify identifier( logic

1 files changed, 134 insertions(+), 61 deletions(-)

src/AstGen.zig+134-61
...@@ -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 support2142 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 analysis2966 // 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 constant2977 .used = .fn_param,
2959 };2978 };
2960 params_scope = &sub_scope.base;2979 params_scope = &sub_scope.base;
29612980
2962 // Additionally put the param name into `string_bytes` and reference it with2981 // 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);
29672987
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 }
29702991
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);
33983419
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);
34023422
...@@ -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);
36613681
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);
36643684
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);
40624082
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);
40654085
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);
42924312
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 };
46284649
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/else4654 // 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_ptr4655 // 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;
49014924
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_ptr4928 const tag: Zir.Inst.Tag = if (payload_is_ref)
4906 else4929 .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_ptr4953 .optional_payload_unsafe_ptr
4922 else4954 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(
49384973
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/else4977 // 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_ptr4978 // 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;
51625204
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_ptr5208 const tag: Zir.Inst.Tag = if (payload_is_ref)
5167 else5209 .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(
51995252
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);
52025256
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 };
53915452
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);
53945456
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 }
57575822
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_ref6222 if (!hit_namespace) {
6155 // This *might* be capturable depending on if it is comptime known6223 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 break6234 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 };
83968460
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 Block8471 /// 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 };
84148487
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 };
84348507
8435 const Defer = struct {8508 const Defer = struct {