| ... | @@ -319,7 +319,7 @@ fn reachableExpr( | ... | @@ -319,7 +319,7 @@ fn reachableExpr( |
| 319 | ) InnerError!Zir.Inst.Ref { | 319 | ) InnerError!Zir.Inst.Ref { |
| 320 | const result_inst = try expr(gz, scope, rl, node); | 320 | const result_inst = try expr(gz, scope, rl, node); |
| 321 | if (gz.refIsNoReturn(result_inst)) { | 321 | if (gz.refIsNoReturn(result_inst)) { |
| 322 | return gz.astgen.failNodeNotes(reachable_node, "unreachable code", .{}, &[_]u32{ | 322 | try gz.astgen.appendErrorNodeNotes(reachable_node, "unreachable code", .{}, &[_]u32{ |
| 323 | try gz.astgen.errNoteNode(node, "control flow is diverted here", .{}), | 323 | try gz.astgen.errNoteNode(node, "control flow is diverted here", .{}), |
| 324 | }); | 324 | }); |
| 325 | } | 325 | } |
| ... | @@ -1011,7 +1011,7 @@ fn nosuspendExpr( | ... | @@ -1011,7 +1011,7 @@ fn nosuspendExpr( |
| 1011 | const body_node = node_datas[node].lhs; | 1011 | const body_node = node_datas[node].lhs; |
| 1012 | assert(body_node != 0); | 1012 | assert(body_node != 0); |
| 1013 | if (gz.nosuspend_node != 0) { | 1013 | if (gz.nosuspend_node != 0) { |
| 1014 | return astgen.failNodeNotes(node, "redundant nosuspend block", .{}, &[_]u32{ | 1014 | try astgen.appendErrorNodeNotes(node, "redundant nosuspend block", .{}, &[_]u32{ |
| 1015 | try astgen.errNoteNode(gz.nosuspend_node, "other nosuspend block here", .{}), | 1015 | try astgen.errNoteNode(gz.nosuspend_node, "other nosuspend block here", .{}), |
| 1016 | }); | 1016 | }); |
| 1017 | } | 1017 | } |
| ... | @@ -1923,7 +1923,7 @@ fn labeledBlockExpr( | ... | @@ -1923,7 +1923,7 @@ fn labeledBlockExpr( |
| 1923 | try blockExprStmts(&block_scope, &block_scope.base, statements); | 1923 | try blockExprStmts(&block_scope, &block_scope.base, statements); |
| 1924 | | 1924 | |
| 1925 | if (!block_scope.label.?.used) { | 1925 | if (!block_scope.label.?.used) { |
| 1926 | return astgen.failTok(label_token, "unused block label", .{}); | 1926 | try astgen.appendErrorTok(label_token, "unused block label", .{}); |
| 1927 | } | 1927 | } |
| 1928 | | 1928 | |
| 1929 | const zir_tags = gz.astgen.instructions.items(.tag); | 1929 | const zir_tags = gz.astgen.instructions.items(.tag); |
| ... | @@ -1975,7 +1975,7 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod | ... | @@ -1975,7 +1975,7 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod |
| 1975 | var scope = parent_scope; | 1975 | var scope = parent_scope; |
| 1976 | for (statements) |statement| { | 1976 | for (statements) |statement| { |
| 1977 | if (noreturn_src_node != 0) { | 1977 | if (noreturn_src_node != 0) { |
| 1978 | return astgen.failNodeNotes( | 1978 | try astgen.appendErrorNodeNotes( |
| 1979 | statement, | 1979 | statement, |
| 1980 | "unreachable code", | 1980 | "unreachable code", |
| 1981 | .{}, | 1981 | .{}, |
| ... | @@ -2469,14 +2469,14 @@ fn checkUsed( | ... | @@ -2469,14 +2469,14 @@ fn checkUsed( |
| 2469 | .local_val => { | 2469 | .local_val => { |
| 2470 | const s = scope.cast(Scope.LocalVal).?; | 2470 | const s = scope.cast(Scope.LocalVal).?; |
| 2471 | if (!s.used) { | 2471 | if (!s.used) { |
| 2472 | return astgen.failTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)}); | 2472 | try astgen.appendErrorTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)}); |
| 2473 | } | 2473 | } |
| 2474 | scope = s.parent; | 2474 | scope = s.parent; |
| 2475 | }, | 2475 | }, |
| 2476 | .local_ptr => { | 2476 | .local_ptr => { |
| 2477 | const s = scope.cast(Scope.LocalPtr).?; | 2477 | const s = scope.cast(Scope.LocalPtr).?; |
| 2478 | if (!s.used) { | 2478 | if (!s.used) { |
| 2479 | return astgen.failTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)}); | 2479 | try astgen.appendErrorTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)}); |
| 2480 | } | 2480 | } |
| 2481 | scope = s.parent; | 2481 | scope = s.parent; |
| 2482 | }, | 2482 | }, |
| ... | @@ -2555,7 +2555,7 @@ fn varDecl( | ... | @@ -2555,7 +2555,7 @@ fn varDecl( |
| 2555 | switch (token_tags[var_decl.ast.mut_token]) { | 2555 | switch (token_tags[var_decl.ast.mut_token]) { |
| 2556 | .keyword_const => { | 2556 | .keyword_const => { |
| 2557 | if (var_decl.comptime_token) |comptime_token| { | 2557 | if (var_decl.comptime_token) |comptime_token| { |
| 2558 | return astgen.failTok(comptime_token, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{}); | 2558 | try astgen.appendErrorTok(comptime_token, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{}); |
| 2559 | } | 2559 | } |
| 2560 | | 2560 | |
| 2561 | // Depending on the type of AST the initialization expression is, we may need an lvalue | 2561 | // Depending on the type of AST the initialization expression is, we may need an lvalue |
| ... | @@ -4183,10 +4183,10 @@ fn containerDecl( | ... | @@ -4183,10 +4183,10 @@ fn containerDecl( |
| 4183 | // One can construct an enum with no tags, and it functions the same as `noreturn`. But | 4183 | // One can construct an enum with no tags, and it functions the same as `noreturn`. But |
| 4184 | // this is only useful for generic code; when explicitly using `enum {}` syntax, there | 4184 | // this is only useful for generic code; when explicitly using `enum {}` syntax, there |
| 4185 | // must be at least one tag. | 4185 | // must be at least one tag. |
| 4186 | return astgen.failNode(node, "enum declarations must have at least one tag", .{}); | 4186 | try astgen.appendErrorNode(node, "enum declarations must have at least one tag", .{}); |
| 4187 | } | 4187 | } |
| 4188 | if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) { | 4188 | if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) { |
| 4189 | return astgen.failNodeNotes( | 4189 | try astgen.appendErrorNodeNotes( |
| 4190 | node, | 4190 | node, |
| 4191 | "non-exhaustive enum missing integer tag type", | 4191 | "non-exhaustive enum missing integer tag type", |
| 4192 | .{}, | 4192 | .{}, |
| ... | @@ -5338,7 +5338,7 @@ fn whileExpr( | ... | @@ -5338,7 +5338,7 @@ fn whileExpr( |
| 5338 | | 5338 | |
| 5339 | if (loop_scope.label) |some| { | 5339 | if (loop_scope.label) |some| { |
| 5340 | if (!some.used) { | 5340 | if (!some.used) { |
| 5341 | return astgen.failTok(some.token, "unused while loop label", .{}); | 5341 | try astgen.appendErrorTok(some.token, "unused while loop label", .{}); |
| 5342 | } | 5342 | } |
| 5343 | } | 5343 | } |
| 5344 | const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; | 5344 | const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; |
| ... | @@ -5526,7 +5526,7 @@ fn forExpr( | ... | @@ -5526,7 +5526,7 @@ fn forExpr( |
| 5526 | | 5526 | |
| 5527 | if (loop_scope.label) |some| { | 5527 | if (loop_scope.label) |some| { |
| 5528 | if (!some.used) { | 5528 | if (!some.used) { |
| 5529 | return astgen.failTok(some.token, "unused for loop label", .{}); | 5529 | try astgen.appendErrorTok(some.token, "unused for loop label", .{}); |
| 5530 | } | 5530 | } |
| 5531 | } | 5531 | } |
| 5532 | const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; | 5532 | const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; |
| ... | @@ -8521,13 +8521,22 @@ fn failNode( | ... | @@ -8521,13 +8521,22 @@ fn failNode( |
| 8521 | return astgen.failNodeNotes(node, format, args, &[0]u32{}); | 8521 | return astgen.failNodeNotes(node, format, args, &[0]u32{}); |
| 8522 | } | 8522 | } |
| 8523 | | 8523 | |
| 8524 | fn failNodeNotes( | 8524 | fn appendErrorNode( |
| | 8525 | astgen: *AstGen, |
| | 8526 | node: Ast.Node.Index, |
| | 8527 | comptime format: []const u8, |
| | 8528 | args: anytype, |
| | 8529 | ) Allocator.Error!void { |
| | 8530 | try astgen.appendErrorNodeNotes(node, format, args, &[0]u32{}); |
| | 8531 | } |
| | 8532 | |
| | 8533 | fn appendErrorNodeNotes( |
| 8525 | astgen: *AstGen, | 8534 | astgen: *AstGen, |
| 8526 | node: Ast.Node.Index, | 8535 | node: Ast.Node.Index, |
| 8527 | comptime format: []const u8, | 8536 | comptime format: []const u8, |
| 8528 | args: anytype, | 8537 | args: anytype, |
| 8529 | notes: []const u32, | 8538 | notes: []const u32, |
| 8530 | ) InnerError { | 8539 | ) Allocator.Error!void { |
| 8531 | @setCold(true); | 8540 | @setCold(true); |
| 8532 | const string_bytes = &astgen.string_bytes; | 8541 | const string_bytes = &astgen.string_bytes; |
| 8533 | const msg = @intCast(u32, string_bytes.items.len); | 8542 | const msg = @intCast(u32, string_bytes.items.len); |
| ... | @@ -8546,6 +8555,16 @@ fn failNodeNotes( | ... | @@ -8546,6 +8555,16 @@ fn failNodeNotes( |
| 8546 | .byte_offset = 0, | 8555 | .byte_offset = 0, |
| 8547 | .notes = notes_index, | 8556 | .notes = notes_index, |
| 8548 | }); | 8557 | }); |
| | 8558 | } |
| | 8559 | |
| | 8560 | fn failNodeNotes( |
| | 8561 | astgen: *AstGen, |
| | 8562 | node: Ast.Node.Index, |
| | 8563 | comptime format: []const u8, |
| | 8564 | args: anytype, |
| | 8565 | notes: []const u32, |
| | 8566 | ) InnerError { |
| | 8567 | try appendErrorNodeNotes(astgen, node, format, args, notes); |
| 8549 | return error.AnalysisFail; | 8568 | return error.AnalysisFail; |
| 8550 | } | 8569 | } |
| 8551 | | 8570 | |
| ... | @@ -8558,6 +8577,15 @@ fn failTok( | ... | @@ -8558,6 +8577,15 @@ fn failTok( |
| 8558 | return astgen.failTokNotes(token, format, args, &[0]u32{}); | 8577 | return astgen.failTokNotes(token, format, args, &[0]u32{}); |
| 8559 | } | 8578 | } |
| 8560 | | 8579 | |
| | 8580 | fn appendErrorTok( |
| | 8581 | astgen: *AstGen, |
| | 8582 | token: Ast.TokenIndex, |
| | 8583 | comptime format: []const u8, |
| | 8584 | args: anytype, |
| | 8585 | ) !void { |
| | 8586 | try astgen.appendErrorTokNotes(token, format, args, &[0]u32{}); |
| | 8587 | } |
| | 8588 | |
| 8561 | fn failTokNotes( | 8589 | fn failTokNotes( |
| 8562 | astgen: *AstGen, | 8590 | astgen: *AstGen, |
| 8563 | token: Ast.TokenIndex, | 8591 | token: Ast.TokenIndex, |
| ... | @@ -8565,6 +8593,17 @@ fn failTokNotes( | ... | @@ -8565,6 +8593,17 @@ fn failTokNotes( |
| 8565 | args: anytype, | 8593 | args: anytype, |
| 8566 | notes: []const u32, | 8594 | notes: []const u32, |
| 8567 | ) InnerError { | 8595 | ) InnerError { |
| | 8596 | try appendErrorTokNotes(astgen, token, format, args, notes); |
| | 8597 | return error.AnalysisFail; |
| | 8598 | } |
| | 8599 | |
| | 8600 | fn appendErrorTokNotes( |
| | 8601 | astgen: *AstGen, |
| | 8602 | token: Ast.TokenIndex, |
| | 8603 | comptime format: []const u8, |
| | 8604 | args: anytype, |
| | 8605 | notes: []const u32, |
| | 8606 | ) !void { |
| 8568 | @setCold(true); | 8607 | @setCold(true); |
| 8569 | const string_bytes = &astgen.string_bytes; | 8608 | const string_bytes = &astgen.string_bytes; |
| 8570 | const msg = @intCast(u32, string_bytes.items.len); | 8609 | const msg = @intCast(u32, string_bytes.items.len); |
| ... | @@ -8583,7 +8622,6 @@ fn failTokNotes( | ... | @@ -8583,7 +8622,6 @@ fn failTokNotes( |
| 8583 | .byte_offset = 0, | 8622 | .byte_offset = 0, |
| 8584 | .notes = notes_index, | 8623 | .notes = notes_index, |
| 8585 | }); | 8624 | }); |
| 8586 | return error.AnalysisFail; | | |
| 8587 | } | 8625 | } |
| 8588 | | 8626 | |
| 8589 | /// Same as `fail`, except given an absolute byte offset. | 8627 | /// Same as `fail`, except given an absolute byte offset. |
| ... | @@ -8594,6 +8632,17 @@ fn failOff( | ... | @@ -8594,6 +8632,17 @@ fn failOff( |
| 8594 | comptime format: []const u8, | 8632 | comptime format: []const u8, |
| 8595 | args: anytype, | 8633 | args: anytype, |
| 8596 | ) InnerError { | 8634 | ) InnerError { |
| | 8635 | try appendErrorOff(astgen, token, byte_offset, format, args); |
| | 8636 | return error.AnalysisFail; |
| | 8637 | } |
| | 8638 | |
| | 8639 | fn appendErrorOff( |
| | 8640 | astgen: *AstGen, |
| | 8641 | token: Ast.TokenIndex, |
| | 8642 | byte_offset: u32, |
| | 8643 | comptime format: []const u8, |
| | 8644 | args: anytype, |
| | 8645 | ) Allocator.Error!void { |
| 8597 | @setCold(true); | 8646 | @setCold(true); |
| 8598 | const string_bytes = &astgen.string_bytes; | 8647 | const string_bytes = &astgen.string_bytes; |
| 8599 | const msg = @intCast(u32, string_bytes.items.len); | 8648 | const msg = @intCast(u32, string_bytes.items.len); |
| ... | @@ -8605,7 +8654,6 @@ fn failOff( | ... | @@ -8605,7 +8654,6 @@ fn failOff( |
| 8605 | .byte_offset = byte_offset, | 8654 | .byte_offset = byte_offset, |
| 8606 | .notes = 0, | 8655 | .notes = 0, |
| 8607 | }); | 8656 | }); |
| 8608 | return error.AnalysisFail; | | |
| 8609 | } | 8657 | } |
| 8610 | | 8658 | |
| 8611 | fn errNoteTok( | 8659 | fn errNoteTok( |