| ... | ... | @@ -172,9 +172,9 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir { |
| 172 | 172 | }; |
| 173 | 173 | defer gz_instructions.deinit(gpa); |
| 174 | 174 | |
| 175 | | // The AST -> ZIR lowering process assumes an AST that does not have any |
| 176 | | // parse errors. |
| 177 | | if (tree.errors.len == 0) { |
| 175 | // The AST -> ZIR lowering process assumes an AST that does not have any parse errors. |
| 176 | // Parse errors, or AstGen errors in the root struct, are considered "fatal", so we emit no ZIR. |
| 177 | const fatal = if (tree.errors.len == 0) fatal: { |
| 178 | 178 | if (AstGen.structDeclInner( |
| 179 | 179 | &gen_scope, |
| 180 | 180 | &gen_scope.base, |
| ... | ... | @@ -184,13 +184,15 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir { |
| 184 | 184 | 0, |
| 185 | 185 | )) |struct_decl_ref| { |
| 186 | 186 | assert(struct_decl_ref.toIndex().? == .main_struct_inst); |
| 187 | break :fatal false; |
| 187 | 188 | } else |err| switch (err) { |
| 188 | 189 | error.OutOfMemory => return error.OutOfMemory, |
| 189 | | error.AnalysisFail => {}, // Handled via compile_errors below. |
| 190 | error.AnalysisFail => break :fatal true, // Handled via compile_errors below. |
| 190 | 191 | } |
| 191 | | } else { |
| 192 | } else fatal: { |
| 192 | 193 | try lowerAstErrors(&astgen); |
| 193 | | } |
| 194 | break :fatal true; |
| 195 | }; |
| 194 | 196 | |
| 195 | 197 | const err_index = @intFromEnum(Zir.ExtraIndex.compile_errors); |
| 196 | 198 | if (astgen.compile_errors.items.len == 0) { |
| ... | ... | @@ -228,8 +230,8 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir { |
| 228 | 230 | } |
| 229 | 231 | } |
| 230 | 232 | |
| 231 | | return Zir{ |
| 232 | | .instructions = astgen.instructions.toOwnedSlice(), |
| 233 | return .{ |
| 234 | .instructions = if (fatal) .empty else astgen.instructions.toOwnedSlice(), |
| 233 | 235 | .string_bytes = try astgen.string_bytes.toOwnedSlice(gpa), |
| 234 | 236 | .extra = try astgen.extra.toOwnedSlice(gpa), |
| 235 | 237 | }; |
| ... | ... | @@ -2101,7 +2103,7 @@ fn comptimeExprAst( |
| 2101 | 2103 | ) InnerError!Zir.Inst.Ref { |
| 2102 | 2104 | const astgen = gz.astgen; |
| 2103 | 2105 | if (gz.is_comptime) { |
| 2104 | | return astgen.failNode(node, "redundant comptime keyword in already comptime scope", .{}); |
| 2106 | try astgen.appendErrorNode(node, "redundant comptime keyword in already comptime scope", .{}); |
| 2105 | 2107 | } |
| 2106 | 2108 | const tree = astgen.tree; |
| 2107 | 2109 | const node_datas = tree.nodes.items(.data); |
| ... | ... | @@ -3275,6 +3277,9 @@ fn varDecl( |
| 3275 | 3277 | try astgen.appendErrorTok(comptime_token, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{}); |
| 3276 | 3278 | } |
| 3277 | 3279 | |
| 3280 | // `comptime const` is a non-fatal error; treat it like the init was marked `comptime`. |
| 3281 | const force_comptime = var_decl.comptime_token != null; |
| 3282 | |
| 3278 | 3283 | // Depending on the type of AST the initialization expression is, we may need an lvalue |
| 3279 | 3284 | // or an rvalue as a result location. If it is an rvalue, we can use the instruction as |
| 3280 | 3285 | // the variable, no memory location needed. |
| ... | ... | @@ -3288,7 +3293,7 @@ fn varDecl( |
| 3288 | 3293 | } else .{ .rl = .none, .ctx = .const_init }; |
| 3289 | 3294 | const prev_anon_name_strategy = gz.anon_name_strategy; |
| 3290 | 3295 | gz.anon_name_strategy = .dbg_var; |
| 3291 | | const init_inst = try reachableExpr(gz, scope, result_info, var_decl.ast.init_node, node); |
| 3296 | const init_inst = try reachableExprComptime(gz, scope, result_info, var_decl.ast.init_node, node, force_comptime); |
| 3292 | 3297 | gz.anon_name_strategy = prev_anon_name_strategy; |
| 3293 | 3298 | |
| 3294 | 3299 | try gz.addDbgVar(.dbg_var_val, ident_name, init_inst); |
| ... | ... | @@ -3358,7 +3363,7 @@ fn varDecl( |
| 3358 | 3363 | const prev_anon_name_strategy = gz.anon_name_strategy; |
| 3359 | 3364 | gz.anon_name_strategy = .dbg_var; |
| 3360 | 3365 | defer gz.anon_name_strategy = prev_anon_name_strategy; |
| 3361 | | const init_inst = try reachableExpr(gz, scope, init_result_info, var_decl.ast.init_node, node); |
| 3366 | const init_inst = try reachableExprComptime(gz, scope, init_result_info, var_decl.ast.init_node, node, force_comptime); |
| 3362 | 3367 | |
| 3363 | 3368 | // The const init expression may have modified the error return trace, so signal |
| 3364 | 3369 | // to Sema that it should save the new index for restoring later. |
| ... | ... | @@ -3503,7 +3508,7 @@ fn assignDestructure(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerErro |
| 3503 | 3508 | |
| 3504 | 3509 | const full = tree.assignDestructure(node); |
| 3505 | 3510 | if (full.comptime_token != null and gz.is_comptime) { |
| 3506 | | return astgen.failNode(node, "redundant comptime keyword in already comptime scope", .{}); |
| 3511 | return astgen.appendErrorNode(node, "redundant comptime keyword in already comptime scope", .{}); |
| 3507 | 3512 | } |
| 3508 | 3513 | |
| 3509 | 3514 | // If this expression is marked comptime, we must wrap the whole thing in a comptime block. |
| ... | ... | @@ -3562,7 +3567,7 @@ fn assignDestructureMaybeDecls( |
| 3562 | 3567 | |
| 3563 | 3568 | const full = tree.assignDestructure(node); |
| 3564 | 3569 | if (full.comptime_token != null and gz.is_comptime) { |
| 3565 | | return astgen.failNode(node, "redundant comptime keyword in already comptime scope", .{}); |
| 3570 | try astgen.appendErrorNode(node, "redundant comptime keyword in already comptime scope", .{}); |
| 3566 | 3571 | } |
| 3567 | 3572 | |
| 3568 | 3573 | const is_comptime = full.comptime_token != null or gz.is_comptime; |
| ... | ... | @@ -3676,6 +3681,7 @@ fn assignDestructureMaybeDecls( |
| 3676 | 3681 | |
| 3677 | 3682 | if (full.comptime_token != null and !any_non_const_variables) { |
| 3678 | 3683 | try astgen.appendErrorTok(full.comptime_token.?, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{}); |
| 3684 | // Note that this is non-fatal; we will still evaluate at comptime. |
| 3679 | 3685 | } |
| 3680 | 3686 | |
| 3681 | 3687 | // If this expression is marked comptime, we must wrap it in a comptime block. |
| ... | ... | @@ -4125,8 +4131,8 @@ fn fnDecl( |
| 4125 | 4131 | // The source slice is added towards the *end* of this function. |
| 4126 | 4132 | astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column)); |
| 4127 | 4133 | |
| 4128 | | // missing function name already happened in scanContainer() |
| 4129 | | const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail; |
| 4134 | // missing function name already checked in scanContainer() |
| 4135 | const fn_name_token = fn_proto.name_token.?; |
| 4130 | 4136 | |
| 4131 | 4137 | // We insert this at the beginning so that its instruction index marks the |
| 4132 | 4138 | // start of the top level declaration. |
| ... | ... | @@ -5167,8 +5173,7 @@ fn structDeclInner( |
| 5167 | 5173 | |
| 5168 | 5174 | if (is_comptime) { |
| 5169 | 5175 | switch (layout) { |
| 5170 | | .@"packed" => return astgen.failTok(member.comptime_token.?, "packed struct fields cannot be marked comptime", .{}), |
| 5171 | | .@"extern" => return astgen.failTok(member.comptime_token.?, "extern struct fields cannot be marked comptime", .{}), |
| 5176 | .@"packed", .@"extern" => return astgen.failTok(member.comptime_token.?, "{s} struct fields cannot be marked comptime", .{@tagName(layout)}), |
| 5172 | 5177 | .auto => any_comptime_fields = true, |
| 5173 | 5178 | } |
| 5174 | 5179 | } else { |
| ... | ... | @@ -5195,7 +5200,7 @@ fn structDeclInner( |
| 5195 | 5200 | |
| 5196 | 5201 | if (have_align) { |
| 5197 | 5202 | if (layout == .@"packed") { |
| 5198 | | try astgen.appendErrorNode(member.ast.align_expr, "unable to override alignment of packed struct fields", .{}); |
| 5203 | return astgen.failNode(member.ast.align_expr, "unable to override alignment of packed struct fields", .{}); |
| 5199 | 5204 | } |
| 5200 | 5205 | any_aligned_fields = true; |
| 5201 | 5206 | const align_ref = try expr(&block_scope, &namespace.base, coerced_align_ri, member.ast.align_expr); |
| ... | ... | @@ -5289,8 +5294,7 @@ fn tupleDecl( |
| 5289 | 5294 | |
| 5290 | 5295 | switch (layout) { |
| 5291 | 5296 | .auto => {}, |
| 5292 | | .@"extern" => return astgen.failNode(node, "extern tuples are not supported", .{}), |
| 5293 | | .@"packed" => return astgen.failNode(node, "packed tuples are not supported", .{}), |
| 5297 | .@"extern", .@"packed" => return astgen.failNode(node, "{s} tuples are not supported", .{@tagName(layout)}), |
| 5294 | 5298 | } |
| 5295 | 5299 | |
| 5296 | 5300 | if (backing_int_node != 0) { |
| ... | ... | @@ -5673,7 +5677,7 @@ fn containerDecl( |
| 5673 | 5677 | }; |
| 5674 | 5678 | }; |
| 5675 | 5679 | if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) { |
| 5676 | | try astgen.appendErrorNodeNotes( |
| 5680 | return astgen.failNodeNotes( |
| 5677 | 5681 | node, |
| 5678 | 5682 | "non-exhaustive enum missing integer tag type", |
| 5679 | 5683 | .{}, |
| ... | ... | @@ -5896,9 +5900,19 @@ fn containerMember( |
| 5896 | 5900 | const full = tree.fullFnProto(&buf, member_node).?; |
| 5897 | 5901 | const body = if (node_tags[member_node] == .fn_decl) node_datas[member_node].rhs else 0; |
| 5898 | 5902 | |
| 5903 | const prev_decl_index = wip_members.decl_index; |
| 5899 | 5904 | astgen.fnDecl(gz, scope, wip_members, member_node, body, full) catch |err| switch (err) { |
| 5900 | 5905 | error.OutOfMemory => return error.OutOfMemory, |
| 5901 | | error.AnalysisFail => {}, |
| 5906 | error.AnalysisFail => { |
| 5907 | wip_members.decl_index = prev_decl_index; |
| 5908 | try addFailedDeclaration( |
| 5909 | wip_members, |
| 5910 | gz, |
| 5911 | .{ .named = full.name_token.? }, |
| 5912 | full.ast.proto_node, |
| 5913 | full.visib_token != null, |
| 5914 | ); |
| 5915 | }, |
| 5902 | 5916 | }; |
| 5903 | 5917 | }, |
| 5904 | 5918 | |
| ... | ... | @@ -5907,28 +5921,77 @@ fn containerMember( |
| 5907 | 5921 | .simple_var_decl, |
| 5908 | 5922 | .aligned_var_decl, |
| 5909 | 5923 | => { |
| 5910 | | astgen.globalVarDecl(gz, scope, wip_members, member_node, tree.fullVarDecl(member_node).?) catch |err| switch (err) { |
| 5924 | const full = tree.fullVarDecl(member_node).?; |
| 5925 | const prev_decl_index = wip_members.decl_index; |
| 5926 | astgen.globalVarDecl(gz, scope, wip_members, member_node, full) catch |err| switch (err) { |
| 5911 | 5927 | error.OutOfMemory => return error.OutOfMemory, |
| 5912 | | error.AnalysisFail => {}, |
| 5928 | error.AnalysisFail => { |
| 5929 | wip_members.decl_index = prev_decl_index; |
| 5930 | try addFailedDeclaration( |
| 5931 | wip_members, |
| 5932 | gz, |
| 5933 | .{ .named = full.ast.mut_token + 1 }, |
| 5934 | member_node, |
| 5935 | full.visib_token != null, |
| 5936 | ); |
| 5937 | }, |
| 5913 | 5938 | }; |
| 5914 | 5939 | }, |
| 5915 | 5940 | |
| 5916 | 5941 | .@"comptime" => { |
| 5942 | const prev_decl_index = wip_members.decl_index; |
| 5917 | 5943 | astgen.comptimeDecl(gz, scope, wip_members, member_node) catch |err| switch (err) { |
| 5918 | 5944 | error.OutOfMemory => return error.OutOfMemory, |
| 5919 | | error.AnalysisFail => {}, |
| 5945 | error.AnalysisFail => { |
| 5946 | wip_members.decl_index = prev_decl_index; |
| 5947 | try addFailedDeclaration( |
| 5948 | wip_members, |
| 5949 | gz, |
| 5950 | .@"comptime", |
| 5951 | member_node, |
| 5952 | false, |
| 5953 | ); |
| 5954 | }, |
| 5920 | 5955 | }; |
| 5921 | 5956 | }, |
| 5922 | 5957 | .@"usingnamespace" => { |
| 5958 | const prev_decl_index = wip_members.decl_index; |
| 5923 | 5959 | astgen.usingnamespaceDecl(gz, scope, wip_members, member_node) catch |err| switch (err) { |
| 5924 | 5960 | error.OutOfMemory => return error.OutOfMemory, |
| 5925 | | error.AnalysisFail => {}, |
| 5961 | error.AnalysisFail => { |
| 5962 | wip_members.decl_index = prev_decl_index; |
| 5963 | try addFailedDeclaration( |
| 5964 | wip_members, |
| 5965 | gz, |
| 5966 | .@"usingnamespace", |
| 5967 | member_node, |
| 5968 | is_pub: { |
| 5969 | const main_tokens = tree.nodes.items(.main_token); |
| 5970 | const token_tags = tree.tokens.items(.tag); |
| 5971 | const main_token = main_tokens[member_node]; |
| 5972 | break :is_pub main_token > 0 and token_tags[main_token - 1] == .keyword_pub; |
| 5973 | }, |
| 5974 | ); |
| 5975 | }, |
| 5926 | 5976 | }; |
| 5927 | 5977 | }, |
| 5928 | 5978 | .test_decl => { |
| 5979 | const prev_decl_index = wip_members.decl_index; |
| 5980 | // We need to have *some* decl here so that the decl count matches what's expected. |
| 5981 | // Since it doesn't strictly matter *what* this is, let's save ourselves the trouble |
| 5982 | // of duplicating the test name logic, and just assume this is an unnamed test. |
| 5929 | 5983 | astgen.testDecl(gz, scope, wip_members, member_node) catch |err| switch (err) { |
| 5930 | 5984 | error.OutOfMemory => return error.OutOfMemory, |
| 5931 | | error.AnalysisFail => {}, |
| 5985 | error.AnalysisFail => { |
| 5986 | wip_members.decl_index = prev_decl_index; |
| 5987 | try addFailedDeclaration( |
| 5988 | wip_members, |
| 5989 | gz, |
| 5990 | .unnamed_test, |
| 5991 | member_node, |
| 5992 | false, |
| 5993 | ); |
| 5994 | }, |
| 5932 | 5995 | }; |
| 5933 | 5996 | }, |
| 5934 | 5997 | else => unreachable, |
| ... | ... | @@ -6140,7 +6203,7 @@ fn orelseCatchExpr( |
| 6140 | 6203 | const payload = payload_token orelse break :blk &else_scope.base; |
| 6141 | 6204 | const err_str = tree.tokenSlice(payload); |
| 6142 | 6205 | if (mem.eql(u8, err_str, "_")) { |
| 6143 | | return astgen.failTok(payload, "discard of error capture; omit it instead", .{}); |
| 6206 | try astgen.appendErrorTok(payload, "discard of error capture; omit it instead", .{}); |
| 6144 | 6207 | } |
| 6145 | 6208 | const err_name = try astgen.identAsString(payload); |
| 6146 | 6209 | |
| ... | ... | @@ -6599,7 +6662,7 @@ fn whileExpr( |
| 6599 | 6662 | |
| 6600 | 6663 | const is_inline = while_full.inline_token != null; |
| 6601 | 6664 | if (parent_gz.is_comptime and is_inline) { |
| 6602 | | return astgen.failTok(while_full.inline_token.?, "redundant inline keyword in comptime scope", .{}); |
| 6665 | try astgen.appendErrorTok(while_full.inline_token.?, "redundant inline keyword in comptime scope", .{}); |
| 6603 | 6666 | } |
| 6604 | 6667 | const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop; |
| 6605 | 6668 | const loop_block = try parent_gz.makeBlockInst(loop_tag, node); |
| ... | ... | @@ -6889,7 +6952,7 @@ fn forExpr( |
| 6889 | 6952 | |
| 6890 | 6953 | const is_inline = for_full.inline_token != null; |
| 6891 | 6954 | if (parent_gz.is_comptime and is_inline) { |
| 6892 | | return astgen.failTok(for_full.inline_token.?, "redundant inline keyword in comptime scope", .{}); |
| 6955 | try astgen.appendErrorTok(for_full.inline_token.?, "redundant inline keyword in comptime scope", .{}); |
| 6893 | 6956 | } |
| 6894 | 6957 | const tree = astgen.tree; |
| 6895 | 6958 | const token_tags = tree.tokens.items(.tag); |
| ... | ... | @@ -6950,7 +7013,7 @@ fn forExpr( |
| 6950 | 7013 | .none; |
| 6951 | 7014 | |
| 6952 | 7015 | if (end_val == .none and is_discard) { |
| 6953 | | return astgen.failTok(ident_tok, "discard of unbounded counter", .{}); |
| 7016 | try astgen.appendErrorTok(ident_tok, "discard of unbounded counter", .{}); |
| 6954 | 7017 | } |
| 6955 | 7018 | |
| 6956 | 7019 | const start_is_zero = nodeIsTriviallyZero(tree, start_node); |
| ... | ... | @@ -7467,6 +7530,7 @@ fn switchExprErrUnion( |
| 7467 | 7530 | const err_name = blk: { |
| 7468 | 7531 | const err_str = tree.tokenSlice(error_payload); |
| 7469 | 7532 | if (mem.eql(u8, err_str, "_")) { |
| 7533 | // This is fatal because we already know we're switching on the captured error. |
| 7470 | 7534 | return astgen.failTok(error_payload, "discard of error capture; omit it instead", .{}); |
| 7471 | 7535 | } |
| 7472 | 7536 | const err_name = try astgen.identAsString(error_payload); |
| ... | ... | @@ -7521,7 +7585,7 @@ fn switchExprErrUnion( |
| 7521 | 7585 | |
| 7522 | 7586 | const capture_slice = tree.tokenSlice(capture_token); |
| 7523 | 7587 | if (mem.eql(u8, capture_slice, "_")) { |
| 7524 | | return astgen.failTok(capture_token, "discard of error capture; omit it instead", .{}); |
| 7588 | try astgen.appendErrorTok(capture_token, "discard of error capture; omit it instead", .{}); |
| 7525 | 7589 | } |
| 7526 | 7590 | const tag_name = try astgen.identAsString(capture_token); |
| 7527 | 7591 | try astgen.detectLocalShadowing(&case_scope.base, tag_name, capture_token, capture_slice, .capture); |
| ... | ... | @@ -8018,7 +8082,7 @@ fn switchExpr( |
| 8018 | 8082 | break :blk payload_sub_scope; |
| 8019 | 8083 | const tag_slice = tree.tokenSlice(tag_token); |
| 8020 | 8084 | if (mem.eql(u8, tag_slice, "_")) { |
| 8021 | | return astgen.failTok(tag_token, "discard of tag capture; omit it instead", .{}); |
| 8085 | try astgen.appendErrorTok(tag_token, "discard of tag capture; omit it instead", .{}); |
| 8022 | 8086 | } else if (case.inline_token == null) { |
| 8023 | 8087 | return astgen.failTok(tag_token, "tag capture on non-inline prong", .{}); |
| 8024 | 8088 | } |
| ... | ... | @@ -13699,6 +13763,8 @@ fn scanContainer( |
| 13699 | 13763 | const main_tokens = tree.nodes.items(.main_token); |
| 13700 | 13764 | const token_tags = tree.tokens.items(.tag); |
| 13701 | 13765 | |
| 13766 | var any_invalid_declarations = false; |
| 13767 | |
| 13702 | 13768 | // This type forms a linked list of source tokens declaring the same name. |
| 13703 | 13769 | const NameEntry = struct { |
| 13704 | 13770 | tok: Ast.TokenIndex, |
| ... | ... | @@ -13758,6 +13824,7 @@ fn scanContainer( |
| 13758 | 13824 | const ident = main_tokens[member_node] + 1; |
| 13759 | 13825 | if (token_tags[ident] != .identifier) { |
| 13760 | 13826 | try astgen.appendErrorNode(member_node, "missing function name", .{}); |
| 13827 | any_invalid_declarations = true; |
| 13761 | 13828 | continue; |
| 13762 | 13829 | } |
| 13763 | 13830 | break :blk .{ .decl, ident }; |
| ... | ... | @@ -13853,6 +13920,7 @@ fn scanContainer( |
| 13853 | 13920 | token_bytes, |
| 13854 | 13921 | }), |
| 13855 | 13922 | }); |
| 13923 | any_invalid_declarations = true; |
| 13856 | 13924 | continue; |
| 13857 | 13925 | } |
| 13858 | 13926 | |
| ... | ... | @@ -13870,6 +13938,7 @@ fn scanContainer( |
| 13870 | 13938 | .{}, |
| 13871 | 13939 | ), |
| 13872 | 13940 | }); |
| 13941 | any_invalid_declarations = true; |
| 13873 | 13942 | break; |
| 13874 | 13943 | } |
| 13875 | 13944 | s = local_val.parent; |
| ... | ... | @@ -13886,6 +13955,7 @@ fn scanContainer( |
| 13886 | 13955 | .{}, |
| 13887 | 13956 | ), |
| 13888 | 13957 | }); |
| 13958 | any_invalid_declarations = true; |
| 13889 | 13959 | break; |
| 13890 | 13960 | } |
| 13891 | 13961 | s = local_ptr.parent; |
| ... | ... | @@ -13897,7 +13967,10 @@ fn scanContainer( |
| 13897 | 13967 | }; |
| 13898 | 13968 | } |
| 13899 | 13969 | |
| 13900 | | if (!any_duplicates) return decl_count; |
| 13970 | if (!any_duplicates) { |
| 13971 | if (any_invalid_declarations) return error.AnalysisFail; |
| 13972 | return decl_count; |
| 13973 | } |
| 13901 | 13974 | |
| 13902 | 13975 | for (names.keys(), names.values()) |name, first| { |
| 13903 | 13976 | if (first.next == null) continue; |
| ... | ... | @@ -13909,6 +13982,7 @@ fn scanContainer( |
| 13909 | 13982 | try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)})); |
| 13910 | 13983 | const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name))); |
| 13911 | 13984 | try astgen.appendErrorTokNotes(first.tok, "duplicate {s} member name '{s}'", .{ @tagName(container_kind), name_duped }, notes.items); |
| 13985 | any_invalid_declarations = true; |
| 13912 | 13986 | } |
| 13913 | 13987 | |
| 13914 | 13988 | for (test_names.keys(), test_names.values()) |name, first| { |
| ... | ... | @@ -13921,6 +13995,7 @@ fn scanContainer( |
| 13921 | 13995 | try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)})); |
| 13922 | 13996 | const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name))); |
| 13923 | 13997 | try astgen.appendErrorTokNotes(first.tok, "duplicate test name '{s}'", .{name_duped}, notes.items); |
| 13998 | any_invalid_declarations = true; |
| 13924 | 13999 | } |
| 13925 | 14000 | |
| 13926 | 14001 | for (decltest_names.keys(), decltest_names.values()) |name, first| { |
| ... | ... | @@ -13933,9 +14008,11 @@ fn scanContainer( |
| 13933 | 14008 | try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)})); |
| 13934 | 14009 | const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name))); |
| 13935 | 14010 | try astgen.appendErrorTokNotes(first.tok, "duplicate decltest '{s}'", .{name_duped}, notes.items); |
| 14011 | any_invalid_declarations = true; |
| 13936 | 14012 | } |
| 13937 | 14013 | |
| 13938 | | return decl_count; |
| 14014 | assert(any_invalid_declarations); |
| 14015 | return error.AnalysisFail; |
| 13939 | 14016 | } |
| 13940 | 14017 | |
| 13941 | 14018 | fn isInferred(astgen: *AstGen, ref: Zir.Inst.Ref) bool { |
| ... | ... | @@ -14083,6 +14160,37 @@ const DeclarationName = union(enum) { |
| 14083 | 14160 | @"usingnamespace", |
| 14084 | 14161 | }; |
| 14085 | 14162 | |
| 14163 | fn addFailedDeclaration( |
| 14164 | wip_members: *WipMembers, |
| 14165 | gz: *GenZir, |
| 14166 | name: DeclarationName, |
| 14167 | src_node: Ast.Node.Index, |
| 14168 | is_pub: bool, |
| 14169 | ) !void { |
| 14170 | const decl_inst = try gz.makeDeclaration(src_node); |
| 14171 | wip_members.nextDecl(decl_inst); |
| 14172 | var decl_gz = gz.makeSubBlock(&gz.base); // scope doesn't matter here |
| 14173 | _ = try decl_gz.add(.{ |
| 14174 | .tag = .extended, |
| 14175 | .data = .{ .extended = .{ |
| 14176 | .opcode = .astgen_error, |
| 14177 | .small = undefined, |
| 14178 | .operand = undefined, |
| 14179 | } }, |
| 14180 | }); |
| 14181 | try setDeclaration( |
| 14182 | decl_inst, |
| 14183 | @splat(0), // use a fixed hash to represent an AstGen failure; we don't care about source changes if AstGen still failed! |
| 14184 | name, |
| 14185 | gz.astgen.source_line, |
| 14186 | is_pub, |
| 14187 | false, // we don't care about exports since semantic analysis will fail |
| 14188 | .empty, |
| 14189 | &decl_gz, |
| 14190 | null, |
| 14191 | ); |
| 14192 | } |
| 14193 | |
| 14086 | 14194 | /// Sets all extra data for a `declaration` instruction. |
| 14087 | 14195 | /// Unstacks `value_gz`, `align_gz`, `linksection_gz`, and `addrspace_gz`. |
| 14088 | 14196 | fn setDeclaration( |