authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-01 16:21:38-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-02 13:27:35-07:00
log41336acb0bb89dd23ef9c49b15d91a847f6796bc
tree4823d19caddb3cd25c7a6e5a4b44ca7a2e0d5c03
parentabfee127353cbdadab4282b61056222cdfbec2d4

AstGen: detect redeclaration of function parameters

Also improve redeclaration error message to include the category of variable.

2 files changed, 113 insertions(+), 111 deletions(-)

lib/std/os/uefi/protocols/simple_network_protocol.zig+4-4
......@@ -57,13 +57,13 @@ pub const SimpleNetworkProtocol = extern struct {
5757 }
5858
5959 /// Modifies or resets the current station address, if supported.
60 pub fn stationAddress(self: *const SimpleNetworkProtocol, reset: bool, new: ?*const MacAddress) Status {
61 return self._station_address(self, reset, new);
60 pub fn stationAddress(self: *const SimpleNetworkProtocol, reset_flag: bool, new: ?*const MacAddress) Status {
61 return self._station_address(self, reset_flag, new);
6262 }
6363
6464 /// Resets or collects the statistics on a network interface.
65 pub fn statistics(self: *const SimpleNetworkProtocol, reset_: bool, statistics_size: ?*usize, statistics_table: ?*NetworkStatistics) Status {
66 return self._statistics(self, reset_, statistics_size, statistics_table);
65 pub fn statistics(self: *const SimpleNetworkProtocol, reset_flag: bool, statistics_size: ?*usize, statistics_table: ?*NetworkStatistics) Status {
66 return self._statistics(self, reset_flag, statistics_size, statistics_table);
6767 }
6868
6969 /// Converts a multicast IP address to a multicast HW MAC address.
src/AstGen.zig+109-107
......@@ -2216,25 +2216,15 @@ fn checkUsed(
22162216 .gen_zir => scope = scope.cast(GenZir).?.parent,
22172217 .local_val => {
22182218 const s = scope.cast(Scope.LocalVal).?;
2219 switch (s.used) {
2220 .used => {},
2221 .fn_param => return astgen.failTok(s.token_src, "unused function parameter", .{}),
2222 .constant => return astgen.failTok(s.token_src, "unused local constant", .{}),
2223 .variable => unreachable,
2224 .loop_index => unreachable,
2225 .capture => return astgen.failTok(s.token_src, "unused capture", .{}),
2219 if (!s.used) {
2220 return astgen.failTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)});
22262221 }
22272222 scope = s.parent;
22282223 },
22292224 .local_ptr => {
22302225 const s = scope.cast(Scope.LocalPtr).?;
2231 switch (s.used) {
2232 .used => {},
2233 .fn_param => unreachable,
2234 .constant => return astgen.failTok(s.token_src, "unused local constant", .{}),
2235 .variable => return astgen.failTok(s.token_src, "unused local variable", .{}),
2236 .loop_index => return astgen.failTok(s.token_src, "unused loop index capture", .{}),
2237 .capture => unreachable,
2226 if (!s.used) {
2227 return astgen.failTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)});
22382228 }
22392229 scope = s.parent;
22402230 },
......@@ -2280,63 +2270,7 @@ fn varDecl(
22802270 }
22812271 const ident_name = try astgen.identAsString(name_token);
22822272
2283 // Local variables shadowing detection, including function parameters.
2284 {
2285 var s = scope;
2286 while (true) switch (s.tag) {
2287 .local_val => {
2288 const local_val = s.cast(Scope.LocalVal).?;
2289 if (local_val.name == ident_name) {
2290 const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name)));
2291 defer gpa.free(name);
2292 return astgen.failTokNotes(name_token, "redeclaration of '{s}'", .{
2293 name,
2294 }, &[_]u32{
2295 try astgen.errNoteTok(
2296 local_val.token_src,
2297 "previously declared here",
2298 .{},
2299 ),
2300 });
2301 }
2302 s = local_val.parent;
2303 },
2304 .local_ptr => {
2305 const local_ptr = s.cast(Scope.LocalPtr).?;
2306 if (local_ptr.name == ident_name) {
2307 const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name)));
2308 defer gpa.free(name);
2309 return astgen.failTokNotes(name_token, "redeclaration of '{s}'", .{
2310 name,
2311 }, &[_]u32{
2312 try astgen.errNoteTok(
2313 local_ptr.token_src,
2314 "previously declared here",
2315 .{},
2316 ),
2317 });
2318 }
2319 s = local_ptr.parent;
2320 },
2321 .namespace => {
2322 const ns = s.cast(Scope.Namespace).?;
2323 const decl_node = ns.decls.get(ident_name) orelse {
2324 s = ns.parent;
2325 continue;
2326 };
2327 const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name)));
2328 defer gpa.free(name);
2329 return astgen.failTokNotes(name_token, "local shadows declaration of '{s}'", .{
2330 name,
2331 }, &[_]u32{
2332 try astgen.errNoteNode(decl_node, "declared here", .{}),
2333 });
2334 },
2335 .gen_zir => s = s.cast(GenZir).?.parent,
2336 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
2337 .top => break,
2338 };
2339 }
2273 try astgen.detectLocalShadowing(scope, ident_name, name_token);
23402274
23412275 if (var_decl.ast.init_node == 0) {
23422276 return astgen.failNode(node, "variables must be initialized", .{});
......@@ -2369,7 +2303,7 @@ fn varDecl(
23692303 .name = ident_name,
23702304 .inst = init_inst,
23712305 .token_src = name_token,
2372 .used = .constant,
2306 .id_cat = .@"local constant",
23732307 };
23742308 return &sub_scope.base;
23752309 }
......@@ -2438,7 +2372,7 @@ fn varDecl(
24382372 .name = ident_name,
24392373 .inst = init_inst,
24402374 .token_src = name_token,
2441 .used = .constant,
2375 .id_cat = .@"local constant",
24422376 };
24432377 return &sub_scope.base;
24442378 }
......@@ -2468,7 +2402,7 @@ fn varDecl(
24682402 .ptr = init_scope.rl_ptr,
24692403 .token_src = name_token,
24702404 .maybe_comptime = true,
2471 .used = .constant,
2405 .id_cat = .@"local constant",
24722406 };
24732407 return &sub_scope.base;
24742408 },
......@@ -2525,7 +2459,7 @@ fn varDecl(
25252459 .ptr = var_data.alloc,
25262460 .token_src = name_token,
25272461 .maybe_comptime = is_comptime,
2528 .used = .variable,
2462 .id_cat = .@"local variable",
25292463 };
25302464 return &sub_scope.base;
25312465 },
......@@ -3028,7 +2962,7 @@ fn fnDecl(
30282962 const param_name = try astgen.identAsString(name_token);
30292963 // Create an arg instruction. This is needed to emit a semantic analysis
30302964 // error for shadowing decls.
3031 // TODO emit a compile error here for shadowing locals.
2965 try astgen.detectLocalShadowing(params_scope, param_name, name_token);
30322966 const arg_inst = try fn_gz.addStrTok(.arg, param_name, name_token);
30332967 const sub_scope = try astgen.arena.create(Scope.LocalVal);
30342968 sub_scope.* = .{
......@@ -3037,7 +2971,7 @@ fn fnDecl(
30372971 .name = param_name,
30382972 .inst = arg_inst,
30392973 .token_src = name_token,
3040 .used = .fn_param,
2974 .id_cat = .@"function parameter",
30412975 };
30422976 params_scope = &sub_scope.base;
30432977
......@@ -4701,7 +4635,7 @@ fn orelseCatchExpr(
47014635 .name = err_name,
47024636 .inst = try then_scope.addUnNode(unwrap_code_op, operand, node),
47034637 .token_src = payload,
4704 .used = .capture,
4638 .id_cat = .@"capture",
47054639 };
47064640 break :blk &err_val_scope.base;
47074641 };
......@@ -4993,7 +4927,7 @@ fn ifExpr(
49934927 .name = ident_name,
49944928 .inst = payload_inst,
49954929 .token_src = payload_token,
4996 .used = .capture,
4930 .id_cat = .@"capture",
49974931 };
49984932 break :s &payload_val_scope.base;
49994933 } else {
......@@ -5015,7 +4949,7 @@ fn ifExpr(
50154949 .name = ident_name,
50164950 .inst = payload_inst,
50174951 .token_src = ident_token,
5018 .used = .capture,
4952 .id_cat = .@"capture",
50194953 };
50204954 break :s &payload_val_scope.base;
50214955 } else {
......@@ -5056,7 +4990,7 @@ fn ifExpr(
50564990 .name = ident_name,
50574991 .inst = payload_inst,
50584992 .token_src = error_token,
5059 .used = .capture,
4993 .id_cat = .@"capture",
50604994 };
50614995 break :s &payload_val_scope.base;
50624996 } else {
......@@ -5250,7 +5184,7 @@ fn whileExpr(
52505184 .name = ident_name,
52515185 .inst = payload_inst,
52525186 .token_src = payload_token,
5253 .used = .capture,
5187 .id_cat = .@"capture",
52545188 };
52555189 break :s &payload_val_scope.base;
52565190 } else {
......@@ -5272,7 +5206,7 @@ fn whileExpr(
52725206 .name = ident_name,
52735207 .inst = payload_inst,
52745208 .token_src = ident_token,
5275 .used = .capture,
5209 .id_cat = .@"capture",
52765210 };
52775211 break :s &payload_val_scope.base;
52785212 } else {
......@@ -5329,7 +5263,7 @@ fn whileExpr(
53295263 .name = ident_name,
53305264 .inst = payload_inst,
53315265 .token_src = error_token,
5332 .used = .capture,
5266 .id_cat = .@"capture",
53335267 };
53345268 break :s &payload_val_scope.base;
53355269 } else {
......@@ -5468,7 +5402,7 @@ fn forExpr(
54685402 .name = name_str_index,
54695403 .inst = payload_inst,
54705404 .token_src = ident,
5471 .used = .capture,
5405 .id_cat = .@"capture",
54725406 };
54735407 payload_sub_scope = &payload_val_scope.base;
54745408 } else if (is_ptr) {
......@@ -5492,7 +5426,7 @@ fn forExpr(
54925426 .ptr = index_ptr,
54935427 .token_src = index_token,
54945428 .maybe_comptime = is_inline,
5495 .used = .loop_index,
5429 .id_cat = .@"loop index capture",
54965430 };
54975431 break :blk &index_scope.base;
54985432 };
......@@ -5737,7 +5671,7 @@ fn switchExpr(
57375671 .name = capture_name,
57385672 .inst = capture,
57395673 .token_src = payload_token,
5740 .used = .capture,
5674 .id_cat = .@"capture",
57415675 };
57425676 break :blk &capture_val_scope.base;
57435677 };
......@@ -5831,7 +5765,7 @@ fn switchExpr(
58315765 .name = capture_name,
58325766 .inst = capture,
58335767 .token_src = payload_token,
5834 .used = .capture,
5768 .id_cat = .@"capture",
58355769 };
58365770 break :blk &capture_val_scope.base;
58375771 };
......@@ -6261,7 +6195,7 @@ fn identifier(
62616195 const local_val = s.cast(Scope.LocalVal).?;
62626196
62636197 if (local_val.name == name_str_index) {
6264 local_val.used = .used;
6198 local_val.used = true;
62656199 // Captures of non-locals need to be emitted as decl_val or decl_ref.
62666200 // This *might* be capturable depending on if it is comptime known.
62676201 if (!hit_namespace) {
......@@ -6273,7 +6207,7 @@ fn identifier(
62736207 .local_ptr => {
62746208 const local_ptr = s.cast(Scope.LocalPtr).?;
62756209 if (local_ptr.name == name_str_index) {
6276 local_ptr.used = .used;
6210 local_ptr.used = true;
62776211 if (hit_namespace) {
62786212 if (local_ptr.maybe_comptime)
62796213 break
......@@ -6609,7 +6543,7 @@ fn asmExpr(
66096543 .local_val => {
66106544 const local_val = s.cast(Scope.LocalVal).?;
66116545 if (local_val.name == str_index) {
6612 local_val.used = .used;
6546 local_val.used = true;
66136547 break;
66146548 }
66156549 s = local_val.parent;
......@@ -6617,7 +6551,7 @@ fn asmExpr(
66176551 .local_ptr => {
66186552 const local_ptr = s.cast(Scope.LocalPtr).?;
66196553 if (local_ptr.name == str_index) {
6620 local_ptr.used = .used;
6554 local_ptr.used = true;
66216555 break;
66226556 }
66236557 s = local_ptr.parent;
......@@ -6968,7 +6902,7 @@ fn builtinCall(
69686902 .local_val => {
69696903 const local_val = s.cast(Scope.LocalVal).?;
69706904 if (local_val.name == decl_name) {
6971 local_val.used = .used;
6905 local_val.used = true;
69726906 break;
69736907 }
69746908 s = local_val.parent;
......@@ -6978,7 +6912,7 @@ fn builtinCall(
69786912 if (local_ptr.name == decl_name) {
69796913 if (!local_ptr.maybe_comptime)
69806914 return astgen.failNode(params[0], "unable to export runtime-known value", .{});
6981 local_ptr.used = .used;
6915 local_ptr.used = true;
69826916 break;
69836917 }
69846918 s = local_ptr.parent;
......@@ -8545,15 +8479,15 @@ const Scope = struct {
85458479 top,
85468480 };
85478481
8548 // either .used or the type of the var/constant
8549 const Used = enum {
8550 fn_param,
8551 constant,
8552 variable,
8553 loop_index,
8554 capture,
8555 used,
8482 /// The category of identifier. These tag names are user-visible in compile errors.
8483 const IdCat = enum {
8484 @"function parameter",
8485 @"local constant",
8486 @"local variable",
8487 @"loop index capture",
8488 @"capture",
85568489 };
8490
85578491 /// This is always a `const` local and importantly the `inst` is a value type, not a pointer.
85588492 /// This structure lives as long as the AST generation of the Block
85598493 /// node that contains the variable.
......@@ -8568,8 +8502,9 @@ const Scope = struct {
85688502 token_src: ast.TokenIndex,
85698503 /// String table index.
85708504 name: u32,
8571 /// has this variable been referenced?
8572 used: Used,
8505 id_cat: IdCat,
8506 /// Track whether the name has been referenced.
8507 used: bool = false,
85738508 };
85748509
85758510 /// This could be a `const` or `var` local. It has a pointer instead of a value.
......@@ -8586,10 +8521,12 @@ const Scope = struct {
85868521 token_src: ast.TokenIndex,
85878522 /// String table index.
85888523 name: u32,
8589 /// 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.
8524 id_cat: IdCat,
8525 /// true means we find out during Sema whether the value is comptime.
8526 /// false means it is already known at AstGen the value is runtime-known.
85908527 maybe_comptime: bool,
8591 /// has this variable been referenced?
8592 used: Used,
8528 /// Track whether the name has been referenced.
8529 used: bool = false,
85938530 };
85948531
85958532 const Defer = struct {
......@@ -9680,6 +9617,71 @@ fn declareNewName(
96809617 }
96819618}
96829619
9620/// Local variables shadowing detection, including function parameters.
9621fn detectLocalShadowing(
9622 astgen: *AstGen,
9623 scope: *Scope,
9624 ident_name: u32,
9625 name_token: ast.TokenIndex,
9626) !void {
9627 const gpa = astgen.gpa;
9628
9629 var s = scope;
9630 while (true) switch (s.tag) {
9631 .local_val => {
9632 const local_val = s.cast(Scope.LocalVal).?;
9633 if (local_val.name == ident_name) {
9634 const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name)));
9635 defer gpa.free(name);
9636 return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{
9637 @tagName(local_val.id_cat), name,
9638 }, &[_]u32{
9639 try astgen.errNoteTok(
9640 local_val.token_src,
9641 "previously declared here",
9642 .{},
9643 ),
9644 });
9645 }
9646 s = local_val.parent;
9647 },
9648 .local_ptr => {
9649 const local_ptr = s.cast(Scope.LocalPtr).?;
9650 if (local_ptr.name == ident_name) {
9651 const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name)));
9652 defer gpa.free(name);
9653 return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{
9654 @tagName(local_ptr.id_cat), name,
9655 }, &[_]u32{
9656 try astgen.errNoteTok(
9657 local_ptr.token_src,
9658 "previously declared here",
9659 .{},
9660 ),
9661 });
9662 }
9663 s = local_ptr.parent;
9664 },
9665 .namespace => {
9666 const ns = s.cast(Scope.Namespace).?;
9667 const decl_node = ns.decls.get(ident_name) orelse {
9668 s = ns.parent;
9669 continue;
9670 };
9671 const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name)));
9672 defer gpa.free(name);
9673 return astgen.failTokNotes(name_token, "local shadows declaration of '{s}'", .{
9674 name,
9675 }, &[_]u32{
9676 try astgen.errNoteNode(decl_node, "declared here", .{}),
9677 });
9678 },
9679 .gen_zir => s = s.cast(GenZir).?.parent,
9680 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
9681 .top => break,
9682 };
9683}
9684
96839685fn advanceSourceCursor(astgen: *AstGen, source: []const u8, end: usize) void {
96849686 var i = astgen.source_offset;
96859687 var line = astgen.source_line;