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(...@@ -1460,6 +1460,7 @@ fn arrayInitExpr(
1460 mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(array_type.ast.elem_count)), "_"))1460 mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(array_type.ast.elem_count)), "_"))
1461 {1461 {
1462 const len_inst = try gz.addInt(array_init.ast.elements.len);1462 const len_inst = try gz.addInt(array_init.ast.elements.len);
1463 const saved_cursor = astgen.saveSourceCursor();
1463 const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type);1464 const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type);
1464 if (array_type.ast.sentinel == .none) {1465 if (array_type.ast.sentinel == .none) {
1465 const array_type_inst = try gz.addPlNode(.array_type, type_expr, Zir.Inst.Bin{1466 const array_type_inst = try gz.addPlNode(.array_type, type_expr, Zir.Inst.Bin{
...@@ -1468,6 +1469,7 @@ fn arrayInitExpr(...@@ -1468,6 +1469,7 @@ fn arrayInitExpr(
1468 });1469 });
1469 break :inst .{ array_type_inst, elem_type };1470 break :inst .{ array_type_inst, elem_type };
1470 } else {1471 } else {
1472 astgen.restoreSourceCursor(saved_cursor);
1471 const sentinel_node = array_type.ast.sentinel.unwrap().?;1473 const sentinel_node = array_type.ast.sentinel.unwrap().?;
1472 const sentinel = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = elem_type } }, sentinel_node, .array_sentinel);1474 const sentinel = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = elem_type } }, sentinel_node, .array_sentinel);
1473 const array_type_inst = try gz.addPlNode(1475 const array_type_inst = try gz.addPlNode(
...@@ -1729,6 +1731,7 @@ fn structInitExpr(...@@ -1729,6 +1731,7 @@ fn structInitExpr(
1729 mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(array_type.ast.elem_count)), "_");1731 mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(array_type.ast.elem_count)), "_");
1730 if (struct_init.ast.fields.len == 0) {1732 if (struct_init.ast.fields.len == 0) {
1731 if (is_inferred_array_len) {1733 if (is_inferred_array_len) {
1734 const saved_cursor = astgen.saveSourceCursor();
1732 const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type);1735 const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type);
1733 const array_type_inst = if (array_type.ast.sentinel == .none) blk: {1736 const array_type_inst = if (array_type.ast.sentinel == .none) blk: {
1734 break :blk try gz.addPlNode(.array_type, type_expr, Zir.Inst.Bin{1737 break :blk try gz.addPlNode(.array_type, type_expr, Zir.Inst.Bin{
...@@ -1736,6 +1739,7 @@ fn structInitExpr(...@@ -1736,6 +1739,7 @@ fn structInitExpr(
1736 .rhs = elem_type,1739 .rhs = elem_type,
1737 });1740 });
1738 } else blk: {1741 } else blk: {
1742 astgen.restoreSourceCursor(saved_cursor);
1739 const sentinel_node = array_type.ast.sentinel.unwrap().?;1743 const sentinel_node = array_type.ast.sentinel.unwrap().?;
1740 const sentinel = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = elem_type } }, sentinel_node, .array_sentinel);1744 const sentinel = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = elem_type } }, sentinel_node, .array_sentinel);
1741 break :blk try gz.addPlNode(1745 break :blk try gz.addPlNode(
...@@ -3135,6 +3139,11 @@ fn varDecl(...@@ -3135,6 +3139,11 @@ fn varDecl(
3135 return astgen.failTok(tree.nodeMainToken(section_node), "cannot set section of local variable '{s}'", .{ident_name_raw});3139 return astgen.failTok(tree.nodeMainToken(section_node), "cannot set section of local variable '{s}'", .{ident_name_raw});
3136 }3140 }
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
3138 const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node.unwrap()) |align_node|3147 const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node.unwrap()) |align_node|
3139 try comptimeExpr(gz, scope, coerced_align_ri, align_node, .@"align")3148 try comptimeExpr(gz, scope, coerced_align_ri, align_node, .@"align")
3140 else3149 else
...@@ -3155,8 +3164,8 @@ fn varDecl(...@@ -3155,8 +3164,8 @@ fn varDecl(
3155 if (align_inst == .none and3164 if (align_inst == .none and
3156 !astgen.nodes_need_rl.contains(node))3165 !astgen.nodes_need_rl.contains(node))
3157 {3166 {
3158 const result_info: ResultInfo = if (var_decl.ast.type_node.unwrap()) |type_node| .{3167 const result_info: ResultInfo = if (type_inst != .none) .{
3159 .rl = .{ .ty = try typeExpr(gz, scope, type_node) },3168 .rl = .{ .ty = type_inst },
3160 .ctx = .const_init,3169 .ctx = .const_init,
3161 } else .{ .rl = .none, .ctx = .const_init };3170 } else .{ .rl = .none, .ctx = .const_init };
3162 const init_inst: Zir.Inst.Ref = try nameStratExpr(gz, scope, result_info, init_node, .dbg_var) orelse3171 const init_inst: Zir.Inst.Ref = try nameStratExpr(gz, scope, result_info, init_node, .dbg_var) orelse
...@@ -3185,8 +3194,7 @@ fn varDecl(...@@ -3185,8 +3194,7 @@ fn varDecl(
3185 const is_comptime = gz.is_comptime or3194 const is_comptime = gz.is_comptime or
3186 tree.nodeTag(init_node) == .@"comptime";3195 tree.nodeTag(init_node) == .@"comptime";
31873196
3188 const init_rl: ResultInfo.Loc = if (var_decl.ast.type_node.unwrap()) |type_node| init_rl: {3197 const init_rl: ResultInfo.Loc = if (type_inst != .none) init_rl: {
3189 const type_inst = try typeExpr(gz, scope, type_node);
3190 if (align_inst == .none) {3198 if (align_inst == .none) {
3191 break :init_rl .{ .ptr = .{ .inst = try gz.addUnNode(.alloc, type_inst, node) } };3199 break :init_rl .{ .ptr = .{ .inst = try gz.addUnNode(.alloc, type_inst, node) } };
3192 } else {3200 } else {
...@@ -3254,8 +3262,7 @@ fn varDecl(...@@ -3254,8 +3262,7 @@ fn varDecl(
3254 if (var_decl.comptime_token != null and gz.is_comptime)3262 if (var_decl.comptime_token != null and gz.is_comptime)
3255 return astgen.failTok(var_decl.comptime_token.?, "'comptime var' is redundant in comptime scope", .{});3263 return astgen.failTok(var_decl.comptime_token.?, "'comptime var' is redundant in comptime scope", .{});
3256 const is_comptime = var_decl.comptime_token != null or gz.is_comptime;3264 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: {3265 const alloc: Zir.Inst.Ref, const resolve_inferred: bool, const result_info: ResultInfo = if (type_inst != .none) a: {
3258 const type_inst = try typeExpr(gz, scope, type_node);
3259 const alloc = alloc: {3266 const alloc = alloc: {
3260 if (align_inst == .none) {3267 if (align_inst == .none) {
3261 const tag: Zir.Inst.Tag = if (is_comptime)3268 const tag: Zir.Inst.Tag = if (is_comptime)
...@@ -3433,6 +3440,7 @@ fn assignDestructureMaybeDecls(...@@ -3433,6 +3440,7 @@ fn assignDestructureMaybeDecls(
3433 const is_comptime = full.comptime_token != null or gz.is_comptime;3440 const is_comptime = full.comptime_token != null or gz.is_comptime;
3434 const value_is_comptime = tree.nodeTag(full.ast.value_expr) == .@"comptime";3441 const value_is_comptime = tree.nodeTag(full.ast.value_expr) == .@"comptime";
34353442
3443 const saved_cursor = astgen.saveSourceCursor();
3436 // When declaring consts via a destructure, we always use a result pointer.3444 // When declaring consts via a destructure, we always use a result pointer.
3437 // This avoids the need to create tuple types, and is also likely easier to3445 // This avoids the need to create tuple types, and is also likely easier to
3438 // optimize, since it's a bit tricky for the optimizer to "split up" the3446 // optimize, since it's a bit tricky for the optimizer to "split up" the
...@@ -3482,14 +3490,18 @@ fn assignDestructureMaybeDecls(...@@ -3482,14 +3490,18 @@ fn assignDestructureMaybeDecls(
3482 // We also mark `const`s as comptime if the RHS is definitely comptime-known.3490 // We also mark `const`s as comptime if the RHS is definitely comptime-known.
3483 const this_variable_comptime = is_comptime or (is_const and value_is_comptime);3491 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
3485 const align_inst: Zir.Inst.Ref = if (full_var_decl.ast.align_node.unwrap()) |align_node|3498 const align_inst: Zir.Inst.Ref = if (full_var_decl.ast.align_node.unwrap()) |align_node|
3486 try comptimeExpr(gz, scope, coerced_align_ri, align_node, .@"align")3499 try comptimeExpr(gz, scope, coerced_align_ri, align_node, .@"align")
3487 else3500 else
3488 .none;3501 .none;
34893502
3490 if (full_var_decl.ast.type_node.unwrap()) |type_node| {3503 if (type_inst != .none) {
3491 // Typed alloc3504 // Typed alloc
3492 const type_inst = try typeExpr(gz, scope, type_node);
3493 const ptr = if (align_inst == .none) ptr: {3505 const ptr = if (align_inst == .none) ptr: {
3494 const tag: Zir.Inst.Tag = if (this_variable_comptime)3506 const tag: Zir.Inst.Tag = if (this_variable_comptime)
3495 .alloc_comptime_mut3507 .alloc_comptime_mut
...@@ -3556,6 +3568,7 @@ fn assignDestructureMaybeDecls(...@@ -3556,6 +3568,7 @@ fn assignDestructureMaybeDecls(
3556 if (any_lvalue_expr) {3568 if (any_lvalue_expr) {
3557 // At least one variable was an lvalue expr. Iterate again in order to3569 // At least one variable was an lvalue expr. Iterate again in order to
3558 // evaluate the lvalues from within the possible block_comptime.3570 // evaluate the lvalues from within the possible block_comptime.
3571 astgen.restoreSourceCursor(saved_cursor);
3559 for (rl_components, full.ast.variables) |*variable_rl, variable_node| {3572 for (rl_components, full.ast.variables) |*variable_rl, variable_node| {
3560 if (variable_rl.* != .typed_ptr) continue;3573 if (variable_rl.* != .typed_ptr) continue;
3561 switch (tree.nodeTag(variable_node)) {3574 switch (tree.nodeTag(variable_node)) {
...@@ -3889,7 +3902,9 @@ fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node....@@ -3889,7 +3902,9 @@ fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.
3889 return astgen.failNode(len_node, "unable to infer array size", .{});3902 return astgen.failNode(len_node, "unable to infer array size", .{});
3890 }3903 }
3891 const len = try reachableExprComptime(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, len_node, node, .array_length);3904 const len = try reachableExprComptime(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, len_node, node, .array_length);
3905 const saved_cursor = astgen.saveSourceCursor();
3892 const elem_type = try typeExpr(gz, scope, extra.elem_type);3906 const elem_type = try typeExpr(gz, scope, extra.elem_type);
3907 astgen.restoreSourceCursor(saved_cursor);
3893 const sentinel = try reachableExprComptime(gz, scope, .{ .rl = .{ .coerced_ty = elem_type } }, extra.sentinel, node, .array_sentinel);3908 const sentinel = try reachableExprComptime(gz, scope, .{ .rl = .{ .coerced_ty = elem_type } }, extra.sentinel, node, .array_sentinel);
38943909
3895 const result = try gz.addPlNode(.array_type_sentinel, node, Zir.Inst.ArrayTypeSentinel{3910 const result = try gz.addPlNode(.array_type_sentinel, node, Zir.Inst.ArrayTypeSentinel{
...@@ -4061,43 +4076,41 @@ fn fnDecl(...@@ -4061,43 +4076,41 @@ fn fnDecl(
4061 // We include a function *type*, not a value.4076 // We include a function *type*, not a value.
4062 const type_inst = try fnProtoExprInner(&type_gz, &type_gz.base, .{ .rl = .none }, decl_node, fn_proto, true);4077 const type_inst = try fnProtoExprInner(&type_gz, &type_gz.base, .{ .rl = .none }, decl_node, fn_proto, true);
4063 _ = try type_gz.addBreakWithSrcNode(.break_inline, decl_inst, type_inst, decl_node);4078 _ = try type_gz.addBreakWithSrcNode(.break_inline, decl_inst, type_inst, decl_node);
4079 astgen.restoreSourceCursor(saved_cursor);
4064 }4080 }
40654081
4066 var align_gz = type_gz.makeSubBlock(scope);4082 var align_gz = type_gz.makeSubBlock(scope);
4067 defer align_gz.unstack();4083 defer align_gz.unstack();
40684084
4069 if (fn_proto.ast.align_expr.unwrap()) |align_expr| {4085 if (fn_proto.ast.align_expr.unwrap()) |align_expr| {
4070 astgen.restoreSourceCursor(saved_cursor);
4071 const inst = try expr(&align_gz, &align_gz.base, coerced_align_ri, align_expr);4086 const inst = try expr(&align_gz, &align_gz.base, coerced_align_ri, align_expr);
4072 _ = try align_gz.addBreakWithSrcNode(.break_inline, decl_inst, inst, decl_node);4087 _ = try align_gz.addBreakWithSrcNode(.break_inline, decl_inst, inst, decl_node);
4073 }4088 }
40744089
4075 var linksection_gz = align_gz.makeSubBlock(scope);4090 var addrspace_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);
4085 defer addrspace_gz.unstack();4091 defer addrspace_gz.unstack();
40864092
4087 if (fn_proto.ast.addrspace_expr.unwrap()) |addrspace_expr| {4093 if (fn_proto.ast.addrspace_expr.unwrap()) |addrspace_expr| {
4088 astgen.restoreSourceCursor(saved_cursor);
4089 const addrspace_ty = try addrspace_gz.addStdLangValue(addrspace_expr, .address_space);4094 const addrspace_ty = try addrspace_gz.addStdLangValue(addrspace_expr, .address_space);
4090 const inst = try expr(&addrspace_gz, &addrspace_gz.base, .{ .rl = .{ .coerced_ty = addrspace_ty } }, addrspace_expr);4095 const inst = try expr(&addrspace_gz, &addrspace_gz.base, .{ .rl = .{ .coerced_ty = addrspace_ty } }, addrspace_expr);
4091 _ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, inst, decl_node);4096 _ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, inst, decl_node);
4092 }4097 }
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);
4095 defer value_gz.unstack();4108 defer value_gz.unstack();
40964109
4097 if (!is_extern) {4110 if (!is_extern) {
4098 // We include a function *value*, not a type.4111 // We include a function *value*, not a type.
4099 astgen.restoreSourceCursor(saved_cursor);4112 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);
4101 }4114 }
41024115
4103 // *Now* we can incorporate the full source code into the hasher.4116 // *Now* we can incorporate the full source code into the hasher.
...@@ -4119,8 +4132,8 @@ fn fnDecl(...@@ -4119,8 +4132,8 @@ fn fnDecl(
41194132
4120 .type_gz = &type_gz,4133 .type_gz = &type_gz,
4121 .align_gz = &align_gz,4134 .align_gz = &align_gz,
4122 .linksection_gz = &linksection_gz,
4123 .addrspace_gz = &addrspace_gz,4135 .addrspace_gz = &addrspace_gz,
4136 .linksection_gz = &linksection_gz,
4124 .value_gz = &value_gz,4137 .value_gz = &value_gz,
4125 });4138 });
4126}4139}
...@@ -4129,7 +4142,6 @@ fn fnDeclInner(...@@ -4129,7 +4142,6 @@ fn fnDeclInner(
4129 astgen: *AstGen,4142 astgen: *AstGen,
4130 decl_gz: *GenZir,4143 decl_gz: *GenZir,
4131 scope: *Scope,4144 scope: *Scope,
4132 saved_cursor: SourceCursor,
4133 decl_inst: Zir.Inst.Index,4145 decl_inst: Zir.Inst.Index,
4134 decl_node: Ast.Node.Index,4146 decl_node: Ast.Node.Index,
4135 body_node: Ast.Node.Index,4147 body_node: Ast.Node.Index,
...@@ -4266,27 +4278,6 @@ fn fnDeclInner(...@@ -4266,27 +4278,6 @@ fn fnDeclInner(
4266 // instructions inside the expression blocks for cc and ret_ty to use the function4278 // instructions inside the expression blocks for cc and ret_ty to use the function
4267 // instruction as the body to break from.4279 // 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
4290 var cc_gz = decl_gz.makeSubBlock(scope);4281 var cc_gz = decl_gz.makeSubBlock(scope);
4291 defer cc_gz.unstack();4282 defer cc_gz.unstack();
4292 const cc_ref: Zir.Inst.Ref = blk: {4283 const cc_ref: Zir.Inst.Ref = blk: {
...@@ -4312,6 +4303,24 @@ fn fnDeclInner(...@@ -4312,6 +4303,24 @@ fn fnDeclInner(
4312 }4303 }
4313 };4304 };
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
4315 var body_gz: GenZir = .{4324 var body_gz: GenZir = .{
4316 .is_comptime = false,4325 .is_comptime = false,
4317 .src_baseline = fn_proto.ast.proto_node,4326 .src_baseline = fn_proto.ast.proto_node,
...@@ -4490,14 +4499,6 @@ fn globalVarDecl(...@@ -4490,14 +4499,6 @@ fn globalVarDecl(
4490 _ = try align_gz.addBreakWithSrcNode(.break_inline, decl_inst, align_inst, node);4499 _ = try align_gz.addBreakWithSrcNode(.break_inline, decl_inst, align_inst, node);
4491 }4500 }
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
4501 var addrspace_gz = type_gz.makeSubBlock(scope);4502 var addrspace_gz = type_gz.makeSubBlock(scope);
4502 defer addrspace_gz.unstack();4503 defer addrspace_gz.unstack();
45034504
...@@ -4507,6 +4508,14 @@ fn globalVarDecl(...@@ -4507,6 +4508,14 @@ fn globalVarDecl(
4507 _ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, addrspace_inst, node);4508 _ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, addrspace_inst, node);
4508 }4509 }
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
4510 var init_gz = type_gz.makeSubBlock(scope);4519 var init_gz = type_gz.makeSubBlock(scope);
4511 defer init_gz.unstack();4520 defer init_gz.unstack();
45124521
...@@ -4536,8 +4545,8 @@ fn globalVarDecl(...@@ -4536,8 +4545,8 @@ fn globalVarDecl(
45364545
4537 .type_gz = &type_gz,4546 .type_gz = &type_gz,
4538 .align_gz = &align_gz,4547 .align_gz = &align_gz,
4539 .linksection_gz = &linksection_gz,
4540 .addrspace_gz = &addrspace_gz,4548 .addrspace_gz = &addrspace_gz,
4549 .linksection_gz = &linksection_gz,
4541 .value_gz = &init_gz,4550 .value_gz = &init_gz,
4542 });4551 });
4543}4552}
...@@ -4599,8 +4608,8 @@ fn comptimeDecl(...@@ -4599,8 +4608,8 @@ fn comptimeDecl(
4599 .linkage = .normal,4608 .linkage = .normal,
4600 .type_gz = &dummy_gz,4609 .type_gz = &dummy_gz,
4601 .align_gz = &dummy_gz,4610 .align_gz = &dummy_gz,
4602 .linksection_gz = &dummy_gz,
4603 .addrspace_gz = &dummy_gz,4611 .addrspace_gz = &dummy_gz,
4612 .linksection_gz = &dummy_gz,
4604 .value_gz = &comptime_gz,4613 .value_gz = &comptime_gz,
4605 });4614 });
4606}4615}
...@@ -7734,10 +7743,6 @@ fn switchExpr(...@@ -7734,10 +7743,6 @@ fn switchExpr(
7734 };7743 };
77357744
7736 if (capture != .none) assert(any_has_payload_capture);7745 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
7742 prong_body: {7747 prong_body: {
7743 scratch_scope.instructions_top = parent_gz.instructions.items.len;7748 scratch_scope.instructions_top = parent_gz.instructions.items.len;
...@@ -7844,6 +7849,10 @@ fn switchExpr(...@@ -7844,6 +7849,10 @@ fn switchExpr(
7844 }7849 }
7845 }7850 }
7846 }7851 }
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 }
7847 assert(scalar_case_index + multi_case_index + @intFromBool(has_else) == case_nodes.len);7856 assert(scalar_case_index + multi_case_index + @intFromBool(has_else) == case_nodes.len);
7848 assert(multi_items_infos_start + multi_item_offset == bodies_start);7857 assert(multi_items_infos_start + multi_item_offset == bodies_start);
78497858
...@@ -11527,8 +11536,8 @@ const GenZir = struct {...@@ -11527,8 +11536,8 @@ const GenZir = struct {
1152711536
11528 /// Must be called with the following stack set up:11537 /// Must be called with the following stack set up:
11529 /// * gz (bottom)11538 /// * gz (bottom)
11530 /// * ret_gz
11531 /// * cc_gz11539 /// * cc_gz
11540 /// * ret_gz
11532 /// * body_gz (top)11541 /// * body_gz (top)
11533 /// Unstacks all of those except for `gz`.11542 /// Unstacks all of those except for `gz`.
11534 fn addFunc(11543 fn addFunc(
...@@ -11575,16 +11584,16 @@ const GenZir = struct {...@@ -11575,16 +11584,16 @@ const GenZir = struct {
11575 stacked_gz = body_gz;11584 stacked_gz = body_gz;
11576 break :body body;11585 break :body body;
11577 } else &.{};11586 } 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 &.{};
11583 const ret_body: []const Zir.Inst.Index = if (args.ret_gz) |ret_gz| body: {11587 const ret_body: []const Zir.Inst.Index = if (args.ret_gz) |ret_gz| body: {
11584 const ret_body = ret_gz.instructionsSliceUptoOpt(stacked_gz);11588 const ret_body = ret_gz.instructionsSliceUptoOpt(stacked_gz);
11585 stacked_gz = ret_gz;11589 stacked_gz = ret_gz;
11586 break :body ret_body;11590 break :body ret_body;
11587 } else &.{};11591 } 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 &.{};
11588 break :bodies .{ body, cc_body, ret_body };11597 break :bodies .{ body, cc_body, ret_body };
11589 };11598 };
1159011599
...@@ -11725,8 +11734,8 @@ const GenZir = struct {...@@ -11725,8 +11734,8 @@ const GenZir = struct {
1172511734
11726 // Order is important when unstacking.11735 // Order is important when unstacking.
11727 if (args.body_gz) |body_gz| body_gz.unstack();11736 if (args.body_gz) |body_gz| body_gz.unstack();
11728 if (args.cc_gz) |cc_gz| cc_gz.unstack();
11729 if (args.ret_gz) |ret_gz| ret_gz.unstack();11737 if (args.ret_gz) |ret_gz| ret_gz.unstack();
11738 if (args.cc_gz) |cc_gz| cc_gz.unstack();
1173011739
11731 astgen.instructions.appendAssumeCapacity(.{11740 astgen.instructions.appendAssumeCapacity(.{
11732 .tag = tag,11741 .tag = tag,
...@@ -13502,10 +13511,10 @@ fn setDeclaration(...@@ -13502,10 +13511,10 @@ fn setDeclaration(
13502 /// Must be stacked on `type_gz`.13511 /// Must be stacked on `type_gz`.
13503 align_gz: *GenZir,13512 align_gz: *GenZir,
13504 /// Must be stacked on `align_gz`.13513 /// Must be stacked on `align_gz`.
13505 linksection_gz: *GenZir,
13506 /// Must be stacked on `linksection_gz`.
13507 addrspace_gz: *GenZir,13514 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.
13509 value_gz: *GenZir,13518 value_gz: *GenZir,
13510 },13519 },
13511) !void {13520) !void {
...@@ -13513,9 +13522,9 @@ fn setDeclaration(...@@ -13513,9 +13522,9 @@ fn setDeclaration(
13513 const gpa = astgen.gpa;13522 const gpa = astgen.gpa;
1351413523
13515 const type_body = args.type_gz.instructionsSliceUpto(args.align_gz);13524 const type_body = args.type_gz.instructionsSliceUpto(args.align_gz);
13516 const align_body = args.align_gz.instructionsSliceUpto(args.linksection_gz);13525 const align_body = args.align_gz.instructionsSliceUpto(args.addrspace_gz);
13517 const linksection_body = args.linksection_gz.instructionsSliceUpto(args.addrspace_gz);13526 const addrspace_body = args.addrspace_gz.instructionsSliceUpto(args.linksection_gz);
13518 const addrspace_body = args.addrspace_gz.instructionsSliceUpto(args.value_gz);13527 const linksection_body = args.linksection_gz.instructionsSliceUpto(args.value_gz);
13519 const value_body = args.value_gz.instructionsSlice();13528 const value_body = args.value_gz.instructionsSlice();
1352013529
13521 const has_name = args.name != .empty;13530 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