authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-09 20:18:17+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-09 15:51:58-07:00
log6413c1bf213eb18165142e99f49d63c5f713d287
treef1da2ce5cb3e76ce47d7bf53a0013856e03fe446
parent4ae62410d232d36f1ef72532d59d87cc1485ef76

Merge pull request 'AstGen: fix fuzzed bugs' (#35526) from gooncreeper/zig:astgen-fuzzing-2 into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/35526 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

9 files changed, 211 insertions(+), 132 deletions(-)

lib/std/zig/AstGen.zig+81-72
......@@ -1460,6 +1460,7 @@ fn arrayInitExpr(
14601460 mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(array_type.ast.elem_count)), "_"))
14611461 {
14621462 const len_inst = try gz.addInt(array_init.ast.elements.len);
1463 const saved_cursor = astgen.saveSourceCursor();
14631464 const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type);
14641465 if (array_type.ast.sentinel == .none) {
14651466 const array_type_inst = try gz.addPlNode(.array_type, type_expr, Zir.Inst.Bin{
......@@ -1468,6 +1469,7 @@ fn arrayInitExpr(
14681469 });
14691470 break :inst .{ array_type_inst, elem_type };
14701471 } else {
1472 astgen.restoreSourceCursor(saved_cursor);
14711473 const sentinel_node = array_type.ast.sentinel.unwrap().?;
14721474 const sentinel = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = elem_type } }, sentinel_node, .array_sentinel);
14731475 const array_type_inst = try gz.addPlNode(
......@@ -1729,6 +1731,7 @@ fn structInitExpr(
17291731 mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(array_type.ast.elem_count)), "_");
17301732 if (struct_init.ast.fields.len == 0) {
17311733 if (is_inferred_array_len) {
1734 const saved_cursor = astgen.saveSourceCursor();
17321735 const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type);
17331736 const array_type_inst = if (array_type.ast.sentinel == .none) blk: {
17341737 break :blk try gz.addPlNode(.array_type, type_expr, Zir.Inst.Bin{
......@@ -1736,6 +1739,7 @@ fn structInitExpr(
17361739 .rhs = elem_type,
17371740 });
17381741 } else blk: {
1742 astgen.restoreSourceCursor(saved_cursor);
17391743 const sentinel_node = array_type.ast.sentinel.unwrap().?;
17401744 const sentinel = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = elem_type } }, sentinel_node, .array_sentinel);
17411745 break :blk try gz.addPlNode(
......@@ -3135,6 +3139,11 @@ fn varDecl(
31353139 return astgen.failTok(tree.nodeMainToken(section_node), "cannot set section of local variable '{s}'", .{ident_name_raw});
31363140 }
31373141
3142 const type_inst: Zir.Inst.Ref = if (var_decl.ast.type_node.unwrap()) |type_node|
3143 try typeExpr(gz, scope, type_node)
3144 else
3145 .none;
3146
31383147 const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node.unwrap()) |align_node|
31393148 try comptimeExpr(gz, scope, coerced_align_ri, align_node, .@"align")
31403149 else
......@@ -3155,8 +3164,8 @@ fn varDecl(
31553164 if (align_inst == .none and
31563165 !astgen.nodes_need_rl.contains(node))
31573166 {
3158 const result_info: ResultInfo = if (var_decl.ast.type_node.unwrap()) |type_node| .{
3159 .rl = .{ .ty = try typeExpr(gz, scope, type_node) },
3167 const result_info: ResultInfo = if (type_inst != .none) .{
3168 .rl = .{ .ty = type_inst },
31603169 .ctx = .const_init,
31613170 } else .{ .rl = .none, .ctx = .const_init };
31623171 const init_inst: Zir.Inst.Ref = try nameStratExpr(gz, scope, result_info, init_node, .dbg_var) orelse
......@@ -3185,8 +3194,7 @@ fn varDecl(
31853194 const is_comptime = gz.is_comptime or
31863195 tree.nodeTag(init_node) == .@"comptime";
31873196
3188 const init_rl: ResultInfo.Loc = if (var_decl.ast.type_node.unwrap()) |type_node| init_rl: {
3189 const type_inst = try typeExpr(gz, scope, type_node);
3197 const init_rl: ResultInfo.Loc = if (type_inst != .none) init_rl: {
31903198 if (align_inst == .none) {
31913199 break :init_rl .{ .ptr = .{ .inst = try gz.addUnNode(.alloc, type_inst, node) } };
31923200 } else {
......@@ -3254,8 +3262,7 @@ fn varDecl(
32543262 if (var_decl.comptime_token != null and gz.is_comptime)
32553263 return astgen.failTok(var_decl.comptime_token.?, "'comptime var' is redundant in comptime scope", .{});
32563264 const is_comptime = var_decl.comptime_token != null or gz.is_comptime;
3257 const alloc: Zir.Inst.Ref, const resolve_inferred: bool, const result_info: ResultInfo = if (var_decl.ast.type_node.unwrap()) |type_node| a: {
3258 const type_inst = try typeExpr(gz, scope, type_node);
3265 const alloc: Zir.Inst.Ref, const resolve_inferred: bool, const result_info: ResultInfo = if (type_inst != .none) a: {
32593266 const alloc = alloc: {
32603267 if (align_inst == .none) {
32613268 const tag: Zir.Inst.Tag = if (is_comptime)
......@@ -3433,6 +3440,7 @@ fn assignDestructureMaybeDecls(
34333440 const is_comptime = full.comptime_token != null or gz.is_comptime;
34343441 const value_is_comptime = tree.nodeTag(full.ast.value_expr) == .@"comptime";
34353442
3443 const saved_cursor = astgen.saveSourceCursor();
34363444 // When declaring consts via a destructure, we always use a result pointer.
34373445 // This avoids the need to create tuple types, and is also likely easier to
34383446 // optimize, since it's a bit tricky for the optimizer to "split up" the
......@@ -3482,14 +3490,18 @@ fn assignDestructureMaybeDecls(
34823490 // We also mark `const`s as comptime if the RHS is definitely comptime-known.
34833491 const this_variable_comptime = is_comptime or (is_const and value_is_comptime);
34843492
3493 const type_inst = if (full_var_decl.ast.type_node.unwrap()) |type_node|
3494 try typeExpr(gz, scope, type_node)
3495 else
3496 .none;
3497
34853498 const align_inst: Zir.Inst.Ref = if (full_var_decl.ast.align_node.unwrap()) |align_node|
34863499 try comptimeExpr(gz, scope, coerced_align_ri, align_node, .@"align")
34873500 else
34883501 .none;
34893502
3490 if (full_var_decl.ast.type_node.unwrap()) |type_node| {
3503 if (type_inst != .none) {
34913504 // Typed alloc
3492 const type_inst = try typeExpr(gz, scope, type_node);
34933505 const ptr = if (align_inst == .none) ptr: {
34943506 const tag: Zir.Inst.Tag = if (this_variable_comptime)
34953507 .alloc_comptime_mut
......@@ -3556,6 +3568,7 @@ fn assignDestructureMaybeDecls(
35563568 if (any_lvalue_expr) {
35573569 // At least one variable was an lvalue expr. Iterate again in order to
35583570 // evaluate the lvalues from within the possible block_comptime.
3571 astgen.restoreSourceCursor(saved_cursor);
35593572 for (rl_components, full.ast.variables) |*variable_rl, variable_node| {
35603573 if (variable_rl.* != .typed_ptr) continue;
35613574 switch (tree.nodeTag(variable_node)) {
......@@ -3889,7 +3902,9 @@ fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.
38893902 return astgen.failNode(len_node, "unable to infer array size", .{});
38903903 }
38913904 const len = try reachableExprComptime(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, len_node, node, .array_length);
3905 const saved_cursor = astgen.saveSourceCursor();
38923906 const elem_type = try typeExpr(gz, scope, extra.elem_type);
3907 astgen.restoreSourceCursor(saved_cursor);
38933908 const sentinel = try reachableExprComptime(gz, scope, .{ .rl = .{ .coerced_ty = elem_type } }, extra.sentinel, node, .array_sentinel);
38943909
38953910 const result = try gz.addPlNode(.array_type_sentinel, node, Zir.Inst.ArrayTypeSentinel{
......@@ -4061,43 +4076,41 @@ fn fnDecl(
40614076 // We include a function *type*, not a value.
40624077 const type_inst = try fnProtoExprInner(&type_gz, &type_gz.base, .{ .rl = .none }, decl_node, fn_proto, true);
40634078 _ = try type_gz.addBreakWithSrcNode(.break_inline, decl_inst, type_inst, decl_node);
4079 astgen.restoreSourceCursor(saved_cursor);
40644080 }
40654081
40664082 var align_gz = type_gz.makeSubBlock(scope);
40674083 defer align_gz.unstack();
40684084
40694085 if (fn_proto.ast.align_expr.unwrap()) |align_expr| {
4070 astgen.restoreSourceCursor(saved_cursor);
40714086 const inst = try expr(&align_gz, &align_gz.base, coerced_align_ri, align_expr);
40724087 _ = try align_gz.addBreakWithSrcNode(.break_inline, decl_inst, inst, decl_node);
40734088 }
40744089
4075 var linksection_gz = align_gz.makeSubBlock(scope);
4076 defer linksection_gz.unstack();
4077
4078 if (fn_proto.ast.section_expr.unwrap()) |section_expr| {
4079 astgen.restoreSourceCursor(saved_cursor);
4080 const inst = try expr(&linksection_gz, &linksection_gz.base, coerced_linksection_ri, section_expr);
4081 _ = try linksection_gz.addBreakWithSrcNode(.break_inline, decl_inst, inst, decl_node);
4082 }
4083
4084 var addrspace_gz = linksection_gz.makeSubBlock(scope);
4090 var addrspace_gz = align_gz.makeSubBlock(scope);
40854091 defer addrspace_gz.unstack();
40864092
40874093 if (fn_proto.ast.addrspace_expr.unwrap()) |addrspace_expr| {
4088 astgen.restoreSourceCursor(saved_cursor);
40894094 const addrspace_ty = try addrspace_gz.addStdLangValue(addrspace_expr, .address_space);
40904095 const inst = try expr(&addrspace_gz, &addrspace_gz.base, .{ .rl = .{ .coerced_ty = addrspace_ty } }, addrspace_expr);
40914096 _ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, inst, decl_node);
40924097 }
40934098
4094 var value_gz = addrspace_gz.makeSubBlock(scope);
4099 var linksection_gz = addrspace_gz.makeSubBlock(scope);
4100 defer linksection_gz.unstack();
4101
4102 if (fn_proto.ast.section_expr.unwrap()) |section_expr| {
4103 const inst = try expr(&linksection_gz, &linksection_gz.base, coerced_linksection_ri, section_expr);
4104 _ = try linksection_gz.addBreakWithSrcNode(.break_inline, decl_inst, inst, decl_node);
4105 }
4106
4107 var value_gz = linksection_gz.makeSubBlock(scope);
40954108 defer value_gz.unstack();
40964109
40974110 if (!is_extern) {
40984111 // We include a function *value*, not a type.
40994112 astgen.restoreSourceCursor(saved_cursor);
4100 try astgen.fnDeclInner(&value_gz, &value_gz.base, saved_cursor, decl_inst, decl_node, body_node.unwrap().?, fn_proto);
4113 try astgen.fnDeclInner(&value_gz, &value_gz.base, decl_inst, decl_node, body_node.unwrap().?, fn_proto);
41014114 }
41024115
41034116 // *Now* we can incorporate the full source code into the hasher.
......@@ -4119,8 +4132,8 @@ fn fnDecl(
41194132
41204133 .type_gz = &type_gz,
41214134 .align_gz = &align_gz,
4122 .linksection_gz = &linksection_gz,
41234135 .addrspace_gz = &addrspace_gz,
4136 .linksection_gz = &linksection_gz,
41244137 .value_gz = &value_gz,
41254138 });
41264139}
......@@ -4129,7 +4142,6 @@ fn fnDeclInner(
41294142 astgen: *AstGen,
41304143 decl_gz: *GenZir,
41314144 scope: *Scope,
4132 saved_cursor: SourceCursor,
41334145 decl_inst: Zir.Inst.Index,
41344146 decl_node: Ast.Node.Index,
41354147 body_node: Ast.Node.Index,
......@@ -4266,27 +4278,6 @@ fn fnDeclInner(
42664278 // instructions inside the expression blocks for cc and ret_ty to use the function
42674279 // instruction as the body to break from.
42684280
4269 var ret_gz = decl_gz.makeSubBlock(params_scope);
4270 defer ret_gz.unstack();
4271 any_param_used = false; // we will check this later
4272 const ret_ref: Zir.Inst.Ref = inst: {
4273 // Parameters are in scope for the return type, so we use `params_scope` here.
4274 // The calling convention will not have parameters in scope, so we'll just use `scope`.
4275 // See #22263 for a proposal to solve the inconsistency here.
4276 const inst = try fullBodyExpr(&ret_gz, params_scope, coerced_type_ri, fn_proto.ast.return_type.unwrap().?, .normal);
4277 if (ret_gz.instructionsSlice().len == 0) {
4278 // In this case we will send a len=0 body which can be encoded more efficiently.
4279 break :inst inst;
4280 }
4281 _ = try ret_gz.addBreak(.break_inline, @fromBackingInt(@intCast(0)), inst);
4282 break :inst inst;
4283 };
4284 const ret_body_param_refs = try astgen.fetchRemoveRefEntries(param_insts.items);
4285 const ret_ty_is_generic = any_param_used;
4286
4287 // We're jumping back in source, so restore the cursor.
4288 astgen.restoreSourceCursor(saved_cursor);
4289
42904281 var cc_gz = decl_gz.makeSubBlock(scope);
42914282 defer cc_gz.unstack();
42924283 const cc_ref: Zir.Inst.Ref = blk: {
......@@ -4312,6 +4303,24 @@ fn fnDeclInner(
43124303 }
43134304 };
43144305
4306 var ret_gz = decl_gz.makeSubBlock(params_scope);
4307 defer ret_gz.unstack();
4308 any_param_used = false; // we will check this later
4309 const ret_ref: Zir.Inst.Ref = inst: {
4310 // Parameters are in scope for the return type, so we use `params_scope` here.
4311 // The calling convention will not have parameters in scope, so we'll just use `scope`.
4312 // See #22263 for a proposal to solve the inconsistency here.
4313 const inst = try fullBodyExpr(&ret_gz, params_scope, coerced_type_ri, fn_proto.ast.return_type.unwrap().?, .normal);
4314 if (ret_gz.instructionsSlice().len == 0) {
4315 // In this case we will send a len=0 body which can be encoded more efficiently.
4316 break :inst inst;
4317 }
4318 _ = try ret_gz.addBreak(.break_inline, @fromBackingInt(@intCast(0)), inst);
4319 break :inst inst;
4320 };
4321 const ret_body_param_refs = try astgen.fetchRemoveRefEntries(param_insts.items);
4322 const ret_ty_is_generic = any_param_used;
4323
43154324 var body_gz: GenZir = .{
43164325 .is_comptime = false,
43174326 .src_baseline = fn_proto.ast.proto_node,
......@@ -4490,14 +4499,6 @@ fn globalVarDecl(
44904499 _ = try align_gz.addBreakWithSrcNode(.break_inline, decl_inst, align_inst, node);
44914500 }
44924501
4493 var linksection_gz = type_gz.makeSubBlock(scope);
4494 defer linksection_gz.unstack();
4495
4496 if (var_decl.ast.section_node.unwrap()) |section_node| {
4497 const linksection_inst = try expr(&linksection_gz, &linksection_gz.base, coerced_linksection_ri, section_node);
4498 _ = try linksection_gz.addBreakWithSrcNode(.break_inline, decl_inst, linksection_inst, node);
4499 }
4500
45014502 var addrspace_gz = type_gz.makeSubBlock(scope);
45024503 defer addrspace_gz.unstack();
45034504
......@@ -4507,6 +4508,14 @@ fn globalVarDecl(
45074508 _ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, addrspace_inst, node);
45084509 }
45094510
4511 var linksection_gz = type_gz.makeSubBlock(scope);
4512 defer linksection_gz.unstack();
4513
4514 if (var_decl.ast.section_node.unwrap()) |section_node| {
4515 const linksection_inst = try expr(&linksection_gz, &linksection_gz.base, coerced_linksection_ri, section_node);
4516 _ = try linksection_gz.addBreakWithSrcNode(.break_inline, decl_inst, linksection_inst, node);
4517 }
4518
45104519 var init_gz = type_gz.makeSubBlock(scope);
45114520 defer init_gz.unstack();
45124521
......@@ -4536,8 +4545,8 @@ fn globalVarDecl(
45364545
45374546 .type_gz = &type_gz,
45384547 .align_gz = &align_gz,
4539 .linksection_gz = &linksection_gz,
45404548 .addrspace_gz = &addrspace_gz,
4549 .linksection_gz = &linksection_gz,
45414550 .value_gz = &init_gz,
45424551 });
45434552}
......@@ -4599,8 +4608,8 @@ fn comptimeDecl(
45994608 .linkage = .normal,
46004609 .type_gz = &dummy_gz,
46014610 .align_gz = &dummy_gz,
4602 .linksection_gz = &dummy_gz,
46034611 .addrspace_gz = &dummy_gz,
4612 .linksection_gz = &dummy_gz,
46044613 .value_gz = &comptime_gz,
46054614 });
46064615}
......@@ -7734,10 +7743,6 @@ fn switchExpr(
77347743 };
77357744
77367745 if (capture != .none) assert(any_has_payload_capture);
7737 if (is_err_switch) {
7738 assert(!any_payload_is_ref); // should have failed by now
7739 assert(!any_has_tag_capture); // should have failed by now
7740 }
77417746
77427747 prong_body: {
77437748 scratch_scope.instructions_top = parent_gz.instructions.items.len;
......@@ -7844,6 +7849,10 @@ fn switchExpr(
78447849 }
78457850 }
78467851 }
7852 if (is_err_switch) {
7853 assert(!any_payload_is_ref); // should have failed by now
7854 assert(!any_has_tag_capture); // should have failed by now
7855 }
78477856 assert(scalar_case_index + multi_case_index + @intFromBool(has_else) == case_nodes.len);
78487857 assert(multi_items_infos_start + multi_item_offset == bodies_start);
78497858
......@@ -11527,8 +11536,8 @@ const GenZir = struct {
1152711536
1152811537 /// Must be called with the following stack set up:
1152911538 /// * gz (bottom)
11530 /// * ret_gz
1153111539 /// * cc_gz
11540 /// * ret_gz
1153211541 /// * body_gz (top)
1153311542 /// Unstacks all of those except for `gz`.
1153411543 fn addFunc(
......@@ -11575,16 +11584,16 @@ const GenZir = struct {
1157511584 stacked_gz = body_gz;
1157611585 break :body body;
1157711586 } else &.{};
11578 const cc_body: []const Zir.Inst.Index = if (args.cc_gz) |cc_gz| body: {
11579 const cc_body = cc_gz.instructionsSliceUptoOpt(stacked_gz);
11580 stacked_gz = cc_gz;
11581 break :body cc_body;
11582 } else &.{};
1158311587 const ret_body: []const Zir.Inst.Index = if (args.ret_gz) |ret_gz| body: {
1158411588 const ret_body = ret_gz.instructionsSliceUptoOpt(stacked_gz);
1158511589 stacked_gz = ret_gz;
1158611590 break :body ret_body;
1158711591 } else &.{};
11592 const cc_body: []const Zir.Inst.Index = if (args.cc_gz) |cc_gz| body: {
11593 const cc_body = cc_gz.instructionsSliceUptoOpt(stacked_gz);
11594 stacked_gz = cc_gz;
11595 break :body cc_body;
11596 } else &.{};
1158811597 break :bodies .{ body, cc_body, ret_body };
1158911598 };
1159011599
......@@ -11725,8 +11734,8 @@ const GenZir = struct {
1172511734
1172611735 // Order is important when unstacking.
1172711736 if (args.body_gz) |body_gz| body_gz.unstack();
11728 if (args.cc_gz) |cc_gz| cc_gz.unstack();
1172911737 if (args.ret_gz) |ret_gz| ret_gz.unstack();
11738 if (args.cc_gz) |cc_gz| cc_gz.unstack();
1173011739
1173111740 astgen.instructions.appendAssumeCapacity(.{
1173211741 .tag = tag,
......@@ -13502,10 +13511,10 @@ fn setDeclaration(
1350213511 /// Must be stacked on `type_gz`.
1350313512 align_gz: *GenZir,
1350413513 /// Must be stacked on `align_gz`.
13505 linksection_gz: *GenZir,
13506 /// Must be stacked on `linksection_gz`.
1350713514 addrspace_gz: *GenZir,
13508 /// Must be stacked on `addrspace_gz` and have nothing stacked on top of it.
13515 /// Must be stacked on `addrspace_gz`.
13516 linksection_gz: *GenZir,
13517 /// Must be stacked on `linksection_gz` and have nothing stacked on top of it.
1350913518 value_gz: *GenZir,
1351013519 },
1351113520) !void {
......@@ -13513,9 +13522,9 @@ fn setDeclaration(
1351313522 const gpa = astgen.gpa;
1351413523
1351513524 const type_body = args.type_gz.instructionsSliceUpto(args.align_gz);
13516 const align_body = args.align_gz.instructionsSliceUpto(args.linksection_gz);
13517 const linksection_body = args.linksection_gz.instructionsSliceUpto(args.addrspace_gz);
13518 const addrspace_body = args.addrspace_gz.instructionsSliceUpto(args.value_gz);
13525 const align_body = args.align_gz.instructionsSliceUpto(args.addrspace_gz);
13526 const addrspace_body = args.addrspace_gz.instructionsSliceUpto(args.linksection_gz);
13527 const linksection_body = args.linksection_gz.instructionsSliceUpto(args.value_gz);
1351913528 const value_body = args.value_gz.instructionsSlice();
1352013529
1352113530 const has_name = args.name != .empty;
test/cases/array_sentinel_cursor.zig created+14
......@@ -0,0 +1,14 @@
1fn s() usize {
2 return 64;
3}
4
5fn T() type {
6 return u64;
7}
8
9const Array = [64:s()]T();
10const empty = [_:s()]T(){};
11const items = [_:s()]T(){100};
12
13// compile
14// output_mode=Obj
test/cases/compile_errors/error_set_cannot_capture_by_reference.zig deleted-13
......@@ -1,13 +0,0 @@
1export fn entry() void {
2 const err: error{Foo} = error.Foo;
3
4 switch (err) {
5 error.Foo => |*foo| {
6 foo catch {};
7 },
8 }
9}
10
11// error
12//
13// :5:23: error: error set cannot be captured by reference
test/cases/compile_errors/switch_capture_error_by_ref.zig deleted-25
......@@ -1,25 +0,0 @@
1export fn entry1() void {
2 switch (@as(anyerror, error.MyError)) {
3 error.MyError, error.MyOtherError => |*err| _ = err,
4 else => {},
5 }
6}
7
8export fn entry2() void {
9 switch (@as(anyerror, error.MyError)) {
10 inline error.MyError, error.MyOtherError => |*err| _ = err,
11 else => {},
12 }
13}
14
15export fn entry3() void {
16 switch (@as(anyerror, error.MyError)) {
17 else => |*err| _ = err,
18 }
19}
20
21// error
22//
23// :3:47: error: error set cannot be captured by reference
24// :10:54: error: error set cannot be captured by reference
25// :17:18: error: error set cannot be captured by reference
test/cases/compile_errors/switch_on_error_bad_captures_astgen.zig created+37
......@@ -0,0 +1,37 @@
1const Error = error {OutOfMemory, ReadFailed};
2const result: Error!u64 = error.OutOfMemory;
3
4test {
5 _ = result catch |err| switch (err) {
6 error.ReadFailed => 2,
7 error.OutOfMemory => |*val| 1,
8 };
9}
10
11test {
12 _ = result catch |err| switch (err) {
13 error.ReadFailed => 2,
14 error.OutOfMemory => |_, tag| 1,
15 };
16}
17
18test {
19 _ = if (result) |n| n else |err| switch (err) {
20 error.ReadFailed => 2,
21 error.OutOfMemory => |*val| 1,
22 };
23}
24
25test {
26 _ = if (result) |n| n else |err| switch (err) {
27 error.ReadFailed => 2,
28 error.OutOfMemory => |_, tag| 1,
29 };
30}
31
32// error
33//
34// :7:32: error: error set cannot be captured by reference
35// :14:34: error: cannot capture tag of error union
36// :21:32: error: error set cannot be captured by reference
37// :28:34: error: cannot capture tag of error union
test/cases/compile_errors/switch_on_error_bad_captures_sema.zig created+21
......@@ -0,0 +1,21 @@
1const Error = error{ OutOfMemory, ReadFailed };
2const err: Error = error.OutOfMemory;
3
4export fn a() void {
5 _ = switch (err) {
6 error.ReadFailed => 2,
7 error.OutOfMemory => |*val| @intFromError(val.*),
8 };
9}
10
11export fn b() void {
12 _ = switch (err) {
13 error.ReadFailed => 2,
14 error.OutOfMemory => |_, tag| @intFromEnum(tag),
15 };
16}
17
18// error
19//
20// :7:31: error: error set cannot be captured by reference
21// :14:34: error: cannot capture tag of non-union type 'error{OutOfMemory,ReadFailed}'
test/cases/compile_errors/switch_on_error_with_capture_by_reference.zig deleted-22
......@@ -1,22 +0,0 @@
1comptime {
2 const e: error{Foo}!u32 = error.Foo;
3 e catch |err| switch (err) {
4 error.Foo => |*foo| {
5 foo catch {};
6 },
7 };
8}
9
10comptime {
11 const e: error{Foo}!u32 = error.Foo;
12 if (e) {} else |err| switch (err) {
13 error.Foo => |*foo| {
14 foo catch {};
15 },
16 }
17}
18
19// error
20//
21// :4:24: error: error set cannot be captured by reference
22// :13:24: error: error set cannot be captured by reference
test/cases/decl_qualifier_cursor.zig created+45
......@@ -0,0 +1,45 @@
1const lang = @import("std").lang;
2
3fn al() comptime_int {
4 return 16;
5}
6
7fn as() lang.AddressSpace {
8 return .generic;
9}
10
11fn ls() []const u8 {
12 return "text";
13}
14
15fn cc() lang.CallingConvention {
16 return .c;
17}
18
19fn rv() type {
20 return void;
21}
22
23extern var a: u64 align(al()) addrspace(as()) linksection(ls());
24extern fn b() align(al()) addrspace(as()) linksection(ls()) callconv(cc()) rv();
25// Intentionally not `export` so it is never analyzed since the qualifiers are
26// not valid for all targets. The main point of this test is checking that Zir
27// generation is done correctly for these, so the above is not an issue.
28fn c() align(al()) addrspace(as()) linksection(ls()) callconv(cc()) rv() {
29 const v: struct {
30 x: u32,
31 y: u32,
32 } align(al()) = undefined;
33 const ta: u64, const tb: struct {
34 x: u32,
35 y: u32,
36 } align(al()) = .{ 0, .{ .x = 10, .y = 20 } };
37 _ = v;
38 _ = a;
39 _ = b;
40 _ = ta;
41 _ = tb;
42}
43
44// compile
45// output_mode=Obj
test/cases/tuple_assign_cursor.zig created+13
......@@ -0,0 +1,13 @@
1fn T() type {
2 return u64;
3}
4
5test {
6 struct {
7 var a: u64 = 0;
8 }.a, const b: T() = .{ 1, 2 };
9 _ = b;
10}
11
12// compile
13// output_mode=Obj