blob a0ff7a0e (446120B) - Raw
1 //! Ingests an AST and produces ZIR code. 2 const AstGen = @This(); 3 4 const std = @import("std"); 5 const Ast = std.zig.Ast; 6 const mem = std.mem; 7 const Allocator = std.mem.Allocator; 8 const assert = std.debug.assert; 9 const ArrayListUnmanaged = std.ArrayListUnmanaged; 10 const StringIndexAdapter = std.hash_map.StringIndexAdapter; 11 const StringIndexContext = std.hash_map.StringIndexContext; 12 13 const Zir = @import("Zir.zig"); 14 const refToIndex = Zir.refToIndex; 15 const indexToRef = Zir.indexToRef; 16 const trace = @import("tracy.zig").trace; 17 const BuiltinFn = @import("BuiltinFn.zig"); 18 19 gpa: Allocator, 20 tree: *const Ast, 21 instructions: std.MultiArrayList(Zir.Inst) = .{}, 22 extra: ArrayListUnmanaged(u32) = .{}, 23 string_bytes: ArrayListUnmanaged(u8) = .{}, 24 /// Tracks the current byte offset within the source file. 25 /// Used to populate line deltas in the ZIR. AstGen maintains 26 /// this "cursor" throughout the entire AST lowering process in order 27 /// to avoid starting over the line/column scan for every declaration, which 28 /// would be O(N^2). 29 source_offset: u32 = 0, 30 /// Tracks the corresponding line of `source_offset`. 31 /// This value is absolute. 32 source_line: u32 = 0, 33 /// Tracks the corresponding column of `source_offset`. 34 /// This value is absolute. 35 source_column: u32 = 0, 36 /// Used for temporary allocations; freed after AstGen is complete. 37 /// The resulting ZIR code has no references to anything in this arena. 38 arena: Allocator, 39 string_table: std.HashMapUnmanaged(u32, void, StringIndexContext, std.hash_map.default_max_load_percentage) = .{}, 40 compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{}, 41 /// The topmost block of the current function. 42 fn_block: ?*GenZir = null, 43 /// Maps string table indexes to the first `@import` ZIR instruction 44 /// that uses this string as the operand. 45 imports: std.AutoArrayHashMapUnmanaged(u32, Ast.TokenIndex) = .{}, 46 /// Used for temporary storage when building payloads. 47 scratch: std.ArrayListUnmanaged(u32) = .{}, 48 /// Whenever a `ref` instruction is needed, it is created and saved in this 49 /// table instead of being immediately appended to the current block body. 50 /// Then, when the instruction is being added to the parent block (typically from 51 /// setBlockBody), if it has a ref_table entry, then the ref instruction is added 52 /// there. This makes sure two properties are upheld: 53 /// 1. All pointers to the same locals return the same address. This is required 54 /// to be compliant with the language specification. 55 /// 2. `ref` instructions will dominate their uses. This is a required property 56 /// of ZIR. 57 /// The key is the ref operand; the value is the ref instruction. 58 ref_table: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}, 59 60 const InnerError = error{ OutOfMemory, AnalysisFail }; 61 62 fn addExtra(astgen: *AstGen, extra: anytype) Allocator.Error!u32 { 63 const fields = std.meta.fields(@TypeOf(extra)); 64 try astgen.extra.ensureUnusedCapacity(astgen.gpa, fields.len); 65 return addExtraAssumeCapacity(astgen, extra); 66 } 67 68 fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 { 69 const fields = std.meta.fields(@TypeOf(extra)); 70 const result = @intCast(u32, astgen.extra.items.len); 71 astgen.extra.items.len += fields.len; 72 setExtra(astgen, result, extra); 73 return result; 74 } 75 76 fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void { 77 const fields = std.meta.fields(@TypeOf(extra)); 78 var i = index; 79 inline for (fields) |field| { 80 astgen.extra.items[i] = switch (field.field_type) { 81 u32 => @field(extra, field.name), 82 Zir.Inst.Ref => @enumToInt(@field(extra, field.name)), 83 i32 => @bitCast(u32, @field(extra, field.name)), 84 Zir.Inst.Call.Flags => @bitCast(u32, @field(extra, field.name)), 85 Zir.Inst.BuiltinCall.Flags => @bitCast(u32, @field(extra, field.name)), 86 Zir.Inst.SwitchBlock.Bits => @bitCast(u32, @field(extra, field.name)), 87 Zir.Inst.FuncFancy.Bits => @bitCast(u32, @field(extra, field.name)), 88 else => @compileError("bad field type"), 89 }; 90 i += 1; 91 } 92 } 93 94 fn reserveExtra(astgen: *AstGen, size: usize) Allocator.Error!u32 { 95 const result = @intCast(u32, astgen.extra.items.len); 96 try astgen.extra.resize(astgen.gpa, result + size); 97 return result; 98 } 99 100 fn appendRefs(astgen: *AstGen, refs: []const Zir.Inst.Ref) !void { 101 const coerced = @ptrCast([]const u32, refs); 102 return astgen.extra.appendSlice(astgen.gpa, coerced); 103 } 104 105 fn appendRefsAssumeCapacity(astgen: *AstGen, refs: []const Zir.Inst.Ref) void { 106 const coerced = @ptrCast([]const u32, refs); 107 astgen.extra.appendSliceAssumeCapacity(coerced); 108 } 109 110 pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir { 111 var arena = std.heap.ArenaAllocator.init(gpa); 112 defer arena.deinit(); 113 114 var astgen: AstGen = .{ 115 .gpa = gpa, 116 .arena = arena.allocator(), 117 .tree = &tree, 118 }; 119 defer astgen.deinit(gpa); 120 121 // String table indexes 0, 1, 2 are reserved for special meaning. 122 try astgen.string_bytes.appendSlice(gpa, &[_]u8{ 0, 0, 0 }); 123 124 // We expect at least as many ZIR instructions and extra data items 125 // as AST nodes. 126 try astgen.instructions.ensureTotalCapacity(gpa, tree.nodes.len); 127 128 // First few indexes of extra are reserved and set at the end. 129 const reserved_count = @typeInfo(Zir.ExtraIndex).Enum.fields.len; 130 try astgen.extra.ensureTotalCapacity(gpa, tree.nodes.len + reserved_count); 131 astgen.extra.items.len += reserved_count; 132 133 var top_scope: Scope.Top = .{}; 134 135 var gz_instructions: std.ArrayListUnmanaged(Zir.Inst.Index) = .{}; 136 var gen_scope: GenZir = .{ 137 .force_comptime = true, 138 .in_defer = false, 139 .parent = &top_scope.base, 140 .anon_name_strategy = .parent, 141 .decl_node_index = 0, 142 .decl_line = 0, 143 .astgen = &astgen, 144 .instructions = &gz_instructions, 145 .instructions_top = 0, 146 }; 147 defer gz_instructions.deinit(gpa); 148 149 if (AstGen.structDeclInner( 150 &gen_scope, 151 &gen_scope.base, 152 0, 153 tree.containerDeclRoot(), 154 .Auto, 155 )) |struct_decl_ref| { 156 assert(refToIndex(struct_decl_ref).? == 0); 157 } else |err| switch (err) { 158 error.OutOfMemory => return error.OutOfMemory, 159 error.AnalysisFail => {}, // Handled via compile_errors below. 160 } 161 162 const err_index = @enumToInt(Zir.ExtraIndex.compile_errors); 163 if (astgen.compile_errors.items.len == 0) { 164 astgen.extra.items[err_index] = 0; 165 } else { 166 try astgen.extra.ensureUnusedCapacity(gpa, 1 + astgen.compile_errors.items.len * 167 @typeInfo(Zir.Inst.CompileErrors.Item).Struct.fields.len); 168 169 astgen.extra.items[err_index] = astgen.addExtraAssumeCapacity(Zir.Inst.CompileErrors{ 170 .items_len = @intCast(u32, astgen.compile_errors.items.len), 171 }); 172 173 for (astgen.compile_errors.items) |item| { 174 _ = astgen.addExtraAssumeCapacity(item); 175 } 176 } 177 178 const imports_index = @enumToInt(Zir.ExtraIndex.imports); 179 if (astgen.imports.count() == 0) { 180 astgen.extra.items[imports_index] = 0; 181 } else { 182 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Imports).Struct.fields.len + 183 astgen.imports.count() * @typeInfo(Zir.Inst.Imports.Item).Struct.fields.len); 184 185 astgen.extra.items[imports_index] = astgen.addExtraAssumeCapacity(Zir.Inst.Imports{ 186 .imports_len = @intCast(u32, astgen.imports.count()), 187 }); 188 189 var it = astgen.imports.iterator(); 190 while (it.next()) |entry| { 191 _ = astgen.addExtraAssumeCapacity(Zir.Inst.Imports.Item{ 192 .name = entry.key_ptr.*, 193 .token = entry.value_ptr.*, 194 }); 195 } 196 } 197 198 return Zir{ 199 .instructions = astgen.instructions.toOwnedSlice(), 200 .string_bytes = astgen.string_bytes.toOwnedSlice(gpa), 201 .extra = astgen.extra.toOwnedSlice(gpa), 202 }; 203 } 204 205 pub fn deinit(astgen: *AstGen, gpa: Allocator) void { 206 astgen.instructions.deinit(gpa); 207 astgen.extra.deinit(gpa); 208 astgen.string_table.deinit(gpa); 209 astgen.string_bytes.deinit(gpa); 210 astgen.compile_errors.deinit(gpa); 211 astgen.imports.deinit(gpa); 212 astgen.scratch.deinit(gpa); 213 astgen.ref_table.deinit(gpa); 214 } 215 216 pub const ResultLoc = union(enum) { 217 /// The expression is the right-hand side of assignment to `_`. Only the side-effects of the 218 /// expression should be generated. The result instruction from the expression must 219 /// be ignored. 220 discard, 221 /// The expression has an inferred type, and it will be evaluated as an rvalue. 222 none, 223 /// The expression must generate a pointer rather than a value. For example, the left hand side 224 /// of an assignment uses this kind of result location. 225 ref, 226 /// The expression will be coerced into this type, but it will be evaluated as an rvalue. 227 ty: Zir.Inst.Ref, 228 /// Same as `ty` but it is guaranteed that Sema will additionally perform the coercion, 229 /// so no `as` instruction needs to be emitted. 230 coerced_ty: Zir.Inst.Ref, 231 /// The expression must store its result into this typed pointer. The result instruction 232 /// from the expression must be ignored. 233 ptr: Zir.Inst.Ref, 234 /// The expression must store its result into this allocation, which has an inferred type. 235 /// The result instruction from the expression must be ignored. 236 /// Always an instruction with tag `alloc_inferred`. 237 inferred_ptr: Zir.Inst.Ref, 238 /// There is a pointer for the expression to store its result into, however, its type 239 /// is inferred based on peer type resolution for a `Zir.Inst.Block`. 240 /// The result instruction from the expression must be ignored. 241 block_ptr: *GenZir, 242 243 pub const Strategy = struct { 244 elide_store_to_block_ptr_instructions: bool, 245 tag: Tag, 246 247 pub const Tag = enum { 248 /// Both branches will use break_void; result location is used to communicate the 249 /// result instruction. 250 break_void, 251 /// Use break statements to pass the block result value, and call rvalue() at 252 /// the end depending on rl. Also elide the store_to_block_ptr instructions 253 /// depending on rl. 254 break_operand, 255 }; 256 }; 257 258 fn strategy(rl: ResultLoc, block_scope: *GenZir) Strategy { 259 switch (rl) { 260 // In this branch there will not be any store_to_block_ptr instructions. 261 .none, .ty, .coerced_ty, .ref => return .{ 262 .tag = .break_operand, 263 .elide_store_to_block_ptr_instructions = false, 264 }, 265 .discard => return .{ 266 .tag = .break_void, 267 .elide_store_to_block_ptr_instructions = false, 268 }, 269 // The pointer got passed through to the sub-expressions, so we will use 270 // break_void here. 271 // In this branch there will not be any store_to_block_ptr instructions. 272 .ptr => return .{ 273 .tag = .break_void, 274 .elide_store_to_block_ptr_instructions = false, 275 }, 276 .inferred_ptr, .block_ptr => { 277 if (block_scope.rvalue_rl_count == block_scope.break_count) { 278 // Neither prong of the if consumed the result location, so we can 279 // use break instructions to create an rvalue. 280 return .{ 281 .tag = .break_operand, 282 .elide_store_to_block_ptr_instructions = true, 283 }; 284 } else { 285 // Allow the store_to_block_ptr instructions to remain so that 286 // semantic analysis can turn them into bitcasts. 287 return .{ 288 .tag = .break_void, 289 .elide_store_to_block_ptr_instructions = false, 290 }; 291 } 292 }, 293 } 294 } 295 296 /// Turns a `coerced_ty` back into a `ty`. Should be called at branch points 297 /// such as if and switch expressions. 298 fn br(rl: ResultLoc) ResultLoc { 299 return switch (rl) { 300 .coerced_ty => |ty| .{ .ty = ty }, 301 else => rl, 302 }; 303 } 304 }; 305 306 pub const align_rl: ResultLoc = .{ .ty = .u29_type }; 307 pub const coerced_align_rl: ResultLoc = .{ .coerced_ty = .u29_type }; 308 pub const bool_rl: ResultLoc = .{ .ty = .bool_type }; 309 pub const type_rl: ResultLoc = .{ .ty = .type_type }; 310 pub const coerced_type_rl: ResultLoc = .{ .coerced_ty = .type_type }; 311 312 fn typeExpr(gz: *GenZir, scope: *Scope, type_node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 313 const prev_force_comptime = gz.force_comptime; 314 gz.force_comptime = true; 315 defer gz.force_comptime = prev_force_comptime; 316 317 return expr(gz, scope, coerced_type_rl, type_node); 318 } 319 320 fn reachableTypeExpr( 321 gz: *GenZir, 322 scope: *Scope, 323 type_node: Ast.Node.Index, 324 reachable_node: Ast.Node.Index, 325 ) InnerError!Zir.Inst.Ref { 326 const prev_force_comptime = gz.force_comptime; 327 gz.force_comptime = true; 328 defer gz.force_comptime = prev_force_comptime; 329 330 return reachableExpr(gz, scope, coerced_type_rl, type_node, reachable_node); 331 } 332 333 /// Same as `expr` but fails with a compile error if the result type is `noreturn`. 334 fn reachableExpr( 335 gz: *GenZir, 336 scope: *Scope, 337 rl: ResultLoc, 338 node: Ast.Node.Index, 339 reachable_node: Ast.Node.Index, 340 ) InnerError!Zir.Inst.Ref { 341 return reachableExprComptime(gz, scope, rl, node, reachable_node, false); 342 } 343 344 fn reachableExprComptime( 345 gz: *GenZir, 346 scope: *Scope, 347 rl: ResultLoc, 348 node: Ast.Node.Index, 349 reachable_node: Ast.Node.Index, 350 force_comptime: bool, 351 ) InnerError!Zir.Inst.Ref { 352 const prev_force_comptime = gz.force_comptime; 353 gz.force_comptime = prev_force_comptime or force_comptime; 354 defer gz.force_comptime = prev_force_comptime; 355 356 const result_inst = try expr(gz, scope, rl, node); 357 if (gz.refIsNoReturn(result_inst)) { 358 try gz.astgen.appendErrorNodeNotes(reachable_node, "unreachable code", .{}, &[_]u32{ 359 try gz.astgen.errNoteNode(node, "control flow is diverted here", .{}), 360 }); 361 } 362 return result_inst; 363 } 364 365 fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 366 const astgen = gz.astgen; 367 const tree = astgen.tree; 368 const node_tags = tree.nodes.items(.tag); 369 const main_tokens = tree.nodes.items(.main_token); 370 switch (node_tags[node]) { 371 .root => unreachable, 372 .@"usingnamespace" => unreachable, 373 .test_decl => unreachable, 374 .global_var_decl => unreachable, 375 .local_var_decl => unreachable, 376 .simple_var_decl => unreachable, 377 .aligned_var_decl => unreachable, 378 .switch_case => unreachable, 379 .switch_case_one => unreachable, 380 .container_field_init => unreachable, 381 .container_field_align => unreachable, 382 .container_field => unreachable, 383 .asm_output => unreachable, 384 .asm_input => unreachable, 385 386 .assign, 387 .assign_bit_and, 388 .assign_bit_or, 389 .assign_shl, 390 .assign_shl_sat, 391 .assign_shr, 392 .assign_bit_xor, 393 .assign_div, 394 .assign_sub, 395 .assign_sub_wrap, 396 .assign_sub_sat, 397 .assign_mod, 398 .assign_add, 399 .assign_add_wrap, 400 .assign_add_sat, 401 .assign_mul, 402 .assign_mul_wrap, 403 .assign_mul_sat, 404 .add, 405 .add_wrap, 406 .add_sat, 407 .sub, 408 .sub_wrap, 409 .sub_sat, 410 .mul, 411 .mul_wrap, 412 .mul_sat, 413 .div, 414 .mod, 415 .bit_and, 416 .bit_or, 417 .shl, 418 .shl_sat, 419 .shr, 420 .bit_xor, 421 .bang_equal, 422 .equal_equal, 423 .greater_than, 424 .greater_or_equal, 425 .less_than, 426 .less_or_equal, 427 .array_cat, 428 .array_mult, 429 .bool_and, 430 .bool_or, 431 .@"asm", 432 .asm_simple, 433 .string_literal, 434 .integer_literal, 435 .call, 436 .call_comma, 437 .async_call, 438 .async_call_comma, 439 .call_one, 440 .call_one_comma, 441 .async_call_one, 442 .async_call_one_comma, 443 .unreachable_literal, 444 .@"return", 445 .@"if", 446 .if_simple, 447 .@"while", 448 .while_simple, 449 .while_cont, 450 .bool_not, 451 .address_of, 452 .float_literal, 453 .optional_type, 454 .block, 455 .block_semicolon, 456 .block_two, 457 .block_two_semicolon, 458 .@"break", 459 .ptr_type_aligned, 460 .ptr_type_sentinel, 461 .ptr_type, 462 .ptr_type_bit_range, 463 .array_type, 464 .array_type_sentinel, 465 .enum_literal, 466 .multiline_string_literal, 467 .char_literal, 468 .@"defer", 469 .@"errdefer", 470 .@"catch", 471 .error_union, 472 .merge_error_sets, 473 .switch_range, 474 .@"await", 475 .bit_not, 476 .negation, 477 .negation_wrap, 478 .@"resume", 479 .@"try", 480 .slice, 481 .slice_open, 482 .slice_sentinel, 483 .array_init_one, 484 .array_init_one_comma, 485 .array_init_dot_two, 486 .array_init_dot_two_comma, 487 .array_init_dot, 488 .array_init_dot_comma, 489 .array_init, 490 .array_init_comma, 491 .struct_init_one, 492 .struct_init_one_comma, 493 .struct_init_dot_two, 494 .struct_init_dot_two_comma, 495 .struct_init_dot, 496 .struct_init_dot_comma, 497 .struct_init, 498 .struct_init_comma, 499 .@"switch", 500 .switch_comma, 501 .@"for", 502 .for_simple, 503 .@"suspend", 504 .@"continue", 505 .fn_proto_simple, 506 .fn_proto_multi, 507 .fn_proto_one, 508 .fn_proto, 509 .fn_decl, 510 .anyframe_type, 511 .anyframe_literal, 512 .error_set_decl, 513 .container_decl, 514 .container_decl_trailing, 515 .container_decl_two, 516 .container_decl_two_trailing, 517 .container_decl_arg, 518 .container_decl_arg_trailing, 519 .tagged_union, 520 .tagged_union_trailing, 521 .tagged_union_two, 522 .tagged_union_two_trailing, 523 .tagged_union_enum_tag, 524 .tagged_union_enum_tag_trailing, 525 .@"comptime", 526 .@"nosuspend", 527 .error_value, 528 => return astgen.failNode(node, "invalid left-hand side to assignment", .{}), 529 530 .builtin_call, 531 .builtin_call_comma, 532 .builtin_call_two, 533 .builtin_call_two_comma, 534 => { 535 const builtin_token = main_tokens[node]; 536 const builtin_name = tree.tokenSlice(builtin_token); 537 // If the builtin is an invalid name, we don't cause an error here; instead 538 // let it pass, and the error will be "invalid builtin function" later. 539 if (BuiltinFn.list.get(builtin_name)) |info| { 540 if (!info.allows_lvalue) { 541 return astgen.failNode(node, "invalid left-hand side to assignment", .{}); 542 } 543 } 544 }, 545 546 // These can be assigned to. 547 .unwrap_optional, 548 .deref, 549 .field_access, 550 .array_access, 551 .identifier, 552 .grouped_expression, 553 .@"orelse", 554 => {}, 555 } 556 return expr(gz, scope, .ref, node); 557 } 558 559 /// Turn Zig AST into untyped ZIR instructions. 560 /// When `rl` is discard, ptr, inferred_ptr, or inferred_ptr, the 561 /// result instruction can be used to inspect whether it is isNoReturn() but that is it, 562 /// it must otherwise not be used. 563 fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 564 const astgen = gz.astgen; 565 const tree = astgen.tree; 566 const main_tokens = tree.nodes.items(.main_token); 567 const token_tags = tree.tokens.items(.tag); 568 const node_datas = tree.nodes.items(.data); 569 const node_tags = tree.nodes.items(.tag); 570 571 switch (node_tags[node]) { 572 .root => unreachable, // Top-level declaration. 573 .@"usingnamespace" => unreachable, // Top-level declaration. 574 .test_decl => unreachable, // Top-level declaration. 575 .container_field_init => unreachable, // Top-level declaration. 576 .container_field_align => unreachable, // Top-level declaration. 577 .container_field => unreachable, // Top-level declaration. 578 .fn_decl => unreachable, // Top-level declaration. 579 580 .global_var_decl => unreachable, // Handled in `blockExpr`. 581 .local_var_decl => unreachable, // Handled in `blockExpr`. 582 .simple_var_decl => unreachable, // Handled in `blockExpr`. 583 .aligned_var_decl => unreachable, // Handled in `blockExpr`. 584 .@"defer" => unreachable, // Handled in `blockExpr`. 585 .@"errdefer" => unreachable, // Handled in `blockExpr`. 586 587 .switch_case => unreachable, // Handled in `switchExpr`. 588 .switch_case_one => unreachable, // Handled in `switchExpr`. 589 .switch_range => unreachable, // Handled in `switchExpr`. 590 591 .asm_output => unreachable, // Handled in `asmExpr`. 592 .asm_input => unreachable, // Handled in `asmExpr`. 593 594 .assign => { 595 try assign(gz, scope, node); 596 return rvalue(gz, rl, .void_value, node); 597 }, 598 599 .assign_shl => { 600 try assignShift(gz, scope, node, .shl); 601 return rvalue(gz, rl, .void_value, node); 602 }, 603 .assign_shl_sat => { 604 try assignShiftSat(gz, scope, node); 605 return rvalue(gz, rl, .void_value, node); 606 }, 607 .assign_shr => { 608 try assignShift(gz, scope, node, .shr); 609 return rvalue(gz, rl, .void_value, node); 610 }, 611 612 .assign_bit_and => { 613 try assignOp(gz, scope, node, .bit_and); 614 return rvalue(gz, rl, .void_value, node); 615 }, 616 .assign_bit_or => { 617 try assignOp(gz, scope, node, .bit_or); 618 return rvalue(gz, rl, .void_value, node); 619 }, 620 .assign_bit_xor => { 621 try assignOp(gz, scope, node, .xor); 622 return rvalue(gz, rl, .void_value, node); 623 }, 624 .assign_div => { 625 try assignOp(gz, scope, node, .div); 626 return rvalue(gz, rl, .void_value, node); 627 }, 628 .assign_sub => { 629 try assignOp(gz, scope, node, .sub); 630 return rvalue(gz, rl, .void_value, node); 631 }, 632 .assign_sub_wrap => { 633 try assignOp(gz, scope, node, .subwrap); 634 return rvalue(gz, rl, .void_value, node); 635 }, 636 .assign_sub_sat => { 637 try assignOp(gz, scope, node, .sub_sat); 638 return rvalue(gz, rl, .void_value, node); 639 }, 640 .assign_mod => { 641 try assignOp(gz, scope, node, .mod_rem); 642 return rvalue(gz, rl, .void_value, node); 643 }, 644 .assign_add => { 645 try assignOp(gz, scope, node, .add); 646 return rvalue(gz, rl, .void_value, node); 647 }, 648 .assign_add_wrap => { 649 try assignOp(gz, scope, node, .addwrap); 650 return rvalue(gz, rl, .void_value, node); 651 }, 652 .assign_add_sat => { 653 try assignOp(gz, scope, node, .add_sat); 654 return rvalue(gz, rl, .void_value, node); 655 }, 656 .assign_mul => { 657 try assignOp(gz, scope, node, .mul); 658 return rvalue(gz, rl, .void_value, node); 659 }, 660 .assign_mul_wrap => { 661 try assignOp(gz, scope, node, .mulwrap); 662 return rvalue(gz, rl, .void_value, node); 663 }, 664 .assign_mul_sat => { 665 try assignOp(gz, scope, node, .mul_sat); 666 return rvalue(gz, rl, .void_value, node); 667 }, 668 669 // zig fmt: off 670 .shl => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shl), 671 .shr => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shr), 672 673 .add => return simpleBinOp(gz, scope, rl, node, .add), 674 .add_wrap => return simpleBinOp(gz, scope, rl, node, .addwrap), 675 .add_sat => return simpleBinOp(gz, scope, rl, node, .add_sat), 676 .sub => return simpleBinOp(gz, scope, rl, node, .sub), 677 .sub_wrap => return simpleBinOp(gz, scope, rl, node, .subwrap), 678 .sub_sat => return simpleBinOp(gz, scope, rl, node, .sub_sat), 679 .mul => return simpleBinOp(gz, scope, rl, node, .mul), 680 .mul_wrap => return simpleBinOp(gz, scope, rl, node, .mulwrap), 681 .mul_sat => return simpleBinOp(gz, scope, rl, node, .mul_sat), 682 .div => return simpleBinOp(gz, scope, rl, node, .div), 683 .mod => return simpleBinOp(gz, scope, rl, node, .mod_rem), 684 .shl_sat => return simpleBinOp(gz, scope, rl, node, .shl_sat), 685 686 .bit_and => return simpleBinOp(gz, scope, rl, node, .bit_and), 687 .bit_or => return simpleBinOp(gz, scope, rl, node, .bit_or), 688 .bit_xor => return simpleBinOp(gz, scope, rl, node, .xor), 689 .bang_equal => return simpleBinOp(gz, scope, rl, node, .cmp_neq), 690 .equal_equal => return simpleBinOp(gz, scope, rl, node, .cmp_eq), 691 .greater_than => return simpleBinOp(gz, scope, rl, node, .cmp_gt), 692 .greater_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_gte), 693 .less_than => return simpleBinOp(gz, scope, rl, node, .cmp_lt), 694 .less_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_lte), 695 .array_cat => return simpleBinOp(gz, scope, rl, node, .array_cat), 696 697 .array_mult => { 698 const result = try gz.addPlNode(.array_mul, node, Zir.Inst.Bin{ 699 .lhs = try expr(gz, scope, .none, node_datas[node].lhs), 700 .rhs = try comptimeExpr(gz, scope, .{ .coerced_ty = .usize_type }, node_datas[node].rhs), 701 }); 702 return rvalue(gz, rl, result, node); 703 }, 704 705 .error_union => return simpleBinOp(gz, scope, rl, node, .error_union_type), 706 .merge_error_sets => return simpleBinOp(gz, scope, rl, node, .merge_error_sets), 707 708 .bool_and => return boolBinOp(gz, scope, rl, node, .bool_br_and), 709 .bool_or => return boolBinOp(gz, scope, rl, node, .bool_br_or), 710 711 .bool_not => return simpleUnOp(gz, scope, rl, node, bool_rl, node_datas[node].lhs, .bool_not), 712 .bit_not => return simpleUnOp(gz, scope, rl, node, .none, node_datas[node].lhs, .bit_not), 713 714 .negation => return negation(gz, scope, rl, node), 715 .negation_wrap => return simpleUnOp(gz, scope, rl, node, .none, node_datas[node].lhs, .negate_wrap), 716 717 .identifier => return identifier(gz, scope, rl, node), 718 719 .asm_simple => return asmExpr(gz, scope, rl, node, tree.asmSimple(node)), 720 .@"asm" => return asmExpr(gz, scope, rl, node, tree.asmFull(node)), 721 722 .string_literal => return stringLiteral(gz, rl, node), 723 .multiline_string_literal => return multilineStringLiteral(gz, rl, node), 724 725 .integer_literal => return integerLiteral(gz, rl, node), 726 // zig fmt: on 727 728 .builtin_call_two, .builtin_call_two_comma => { 729 if (node_datas[node].lhs == 0) { 730 const params = [_]Ast.Node.Index{}; 731 return builtinCall(gz, scope, rl, node, ¶ms); 732 } else if (node_datas[node].rhs == 0) { 733 const params = [_]Ast.Node.Index{node_datas[node].lhs}; 734 return builtinCall(gz, scope, rl, node, ¶ms); 735 } else { 736 const params = [_]Ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs }; 737 return builtinCall(gz, scope, rl, node, ¶ms); 738 } 739 }, 740 .builtin_call, .builtin_call_comma => { 741 const params = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs]; 742 return builtinCall(gz, scope, rl, node, params); 743 }, 744 745 .call_one, .call_one_comma, .async_call_one, .async_call_one_comma => { 746 var params: [1]Ast.Node.Index = undefined; 747 return callExpr(gz, scope, rl, node, tree.callOne(¶ms, node)); 748 }, 749 .call, .call_comma, .async_call, .async_call_comma => { 750 return callExpr(gz, scope, rl, node, tree.callFull(node)); 751 }, 752 753 .unreachable_literal => { 754 _ = try gz.addAsIndex(.{ 755 .tag = .@"unreachable", 756 .data = .{ .@"unreachable" = .{ 757 .force_comptime = gz.force_comptime, 758 .src_node = gz.nodeIndexToRelative(node), 759 } }, 760 }); 761 return Zir.Inst.Ref.unreachable_value; 762 }, 763 .@"return" => return ret(gz, scope, node), 764 .field_access => return fieldAccess(gz, scope, rl, node), 765 .float_literal => return floatLiteral(gz, rl, node, .positive), 766 767 .if_simple => return ifExpr(gz, scope, rl.br(), node, tree.ifSimple(node)), 768 .@"if" => return ifExpr(gz, scope, rl.br(), node, tree.ifFull(node)), 769 770 .while_simple => return whileExpr(gz, scope, rl.br(), node, tree.whileSimple(node)), 771 .while_cont => return whileExpr(gz, scope, rl.br(), node, tree.whileCont(node)), 772 .@"while" => return whileExpr(gz, scope, rl.br(), node, tree.whileFull(node)), 773 774 .for_simple => return forExpr(gz, scope, rl.br(), node, tree.forSimple(node)), 775 .@"for" => return forExpr(gz, scope, rl.br(), node, tree.forFull(node)), 776 777 .slice_open => { 778 const lhs = try expr(gz, scope, .ref, node_datas[node].lhs); 779 const start = try expr(gz, scope, .{ .coerced_ty = .usize_type }, node_datas[node].rhs); 780 const result = try gz.addPlNode(.slice_start, node, Zir.Inst.SliceStart{ 781 .lhs = lhs, 782 .start = start, 783 }); 784 return rvalue(gz, rl, result, node); 785 }, 786 .slice => { 787 const lhs = try expr(gz, scope, .ref, node_datas[node].lhs); 788 const extra = tree.extraData(node_datas[node].rhs, Ast.Node.Slice); 789 const start = try expr(gz, scope, .{ .coerced_ty = .usize_type }, extra.start); 790 const end = try expr(gz, scope, .{ .coerced_ty = .usize_type }, extra.end); 791 const result = try gz.addPlNode(.slice_end, node, Zir.Inst.SliceEnd{ 792 .lhs = lhs, 793 .start = start, 794 .end = end, 795 }); 796 return rvalue(gz, rl, result, node); 797 }, 798 .slice_sentinel => { 799 const lhs = try expr(gz, scope, .ref, node_datas[node].lhs); 800 const extra = tree.extraData(node_datas[node].rhs, Ast.Node.SliceSentinel); 801 const start = try expr(gz, scope, .{ .coerced_ty = .usize_type }, extra.start); 802 const end = if (extra.end != 0) try expr(gz, scope, .{ .coerced_ty = .usize_type }, extra.end) else .none; 803 const sentinel = try expr(gz, scope, .none, extra.sentinel); 804 const result = try gz.addPlNode(.slice_sentinel, node, Zir.Inst.SliceSentinel{ 805 .lhs = lhs, 806 .start = start, 807 .end = end, 808 .sentinel = sentinel, 809 }); 810 return rvalue(gz, rl, result, node); 811 }, 812 813 .deref => { 814 const lhs = try expr(gz, scope, .none, node_datas[node].lhs); 815 _ = try gz.addUnTok(.validate_deref, lhs, main_tokens[node]); 816 switch (rl) { 817 .ref => return lhs, 818 else => { 819 const result = try gz.addUnNode(.load, lhs, node); 820 return rvalue(gz, rl, result, node); 821 }, 822 } 823 }, 824 .address_of => { 825 const result = try expr(gz, scope, .ref, node_datas[node].lhs); 826 return rvalue(gz, rl, result, node); 827 }, 828 .optional_type => { 829 const operand = try typeExpr(gz, scope, node_datas[node].lhs); 830 const result = try gz.addUnNode(.optional_type, operand, node); 831 return rvalue(gz, rl, result, node); 832 }, 833 .unwrap_optional => switch (rl) { 834 .ref => return gz.addUnNode( 835 .optional_payload_safe_ptr, 836 try expr(gz, scope, .ref, node_datas[node].lhs), 837 node, 838 ), 839 else => return rvalue(gz, rl, try gz.addUnNode( 840 .optional_payload_safe, 841 try expr(gz, scope, .none, node_datas[node].lhs), 842 node, 843 ), node), 844 }, 845 .block_two, .block_two_semicolon => { 846 const statements = [2]Ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs }; 847 if (node_datas[node].lhs == 0) { 848 return blockExpr(gz, scope, rl, node, statements[0..0]); 849 } else if (node_datas[node].rhs == 0) { 850 return blockExpr(gz, scope, rl, node, statements[0..1]); 851 } else { 852 return blockExpr(gz, scope, rl, node, statements[0..2]); 853 } 854 }, 855 .block, .block_semicolon => { 856 const statements = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs]; 857 return blockExpr(gz, scope, rl, node, statements); 858 }, 859 .enum_literal => return simpleStrTok(gz, rl, main_tokens[node], node, .enum_literal), 860 .error_value => return simpleStrTok(gz, rl, node_datas[node].rhs, node, .error_value), 861 .anyframe_literal => return rvalue(gz, rl, .anyframe_type, node), 862 .anyframe_type => { 863 const return_type = try typeExpr(gz, scope, node_datas[node].rhs); 864 const result = try gz.addUnNode(.anyframe_type, return_type, node); 865 return rvalue(gz, rl, result, node); 866 }, 867 .@"catch" => { 868 const catch_token = main_tokens[node]; 869 const payload_token: ?Ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe) 870 catch_token + 2 871 else 872 null; 873 874 var rhs = node_datas[node].rhs; 875 while (true) switch (node_tags[rhs]) { 876 .grouped_expression => rhs = node_datas[rhs].lhs, 877 .unreachable_literal => { 878 if (payload_token != null and mem.eql(u8, tree.tokenSlice(payload_token.?), "_")) { 879 return astgen.failTok(payload_token.?, "discard of error capture; omit it instead", .{}); 880 } else if (payload_token != null) { 881 return astgen.failTok(payload_token.?, "unused capture", .{}); 882 } 883 const lhs = node_datas[node].lhs; 884 885 const operand = try reachableExpr(gz, scope, switch (rl) { 886 .ref => .ref, 887 else => .none, 888 }, lhs, lhs); 889 const result = try gz.addUnNode(switch (rl) { 890 .ref => .err_union_payload_safe_ptr, 891 else => .err_union_payload_safe, 892 }, operand, node); 893 switch (rl) { 894 .none, .coerced_ty, .discard, .ref => return result, 895 else => return rvalue(gz, rl, result, lhs), 896 } 897 }, 898 else => break, 899 }; 900 switch (rl) { 901 .ref => return orelseCatchExpr( 902 gz, 903 scope, 904 rl, 905 node, 906 node_datas[node].lhs, 907 .is_non_err_ptr, 908 .err_union_payload_unsafe_ptr, 909 .err_union_code_ptr, 910 node_datas[node].rhs, 911 payload_token, 912 ), 913 else => return orelseCatchExpr( 914 gz, 915 scope, 916 rl, 917 node, 918 node_datas[node].lhs, 919 .is_non_err, 920 .err_union_payload_unsafe, 921 .err_union_code, 922 node_datas[node].rhs, 923 payload_token, 924 ), 925 } 926 }, 927 .@"orelse" => switch (rl) { 928 .ref => return orelseCatchExpr( 929 gz, 930 scope, 931 rl, 932 node, 933 node_datas[node].lhs, 934 .is_non_null_ptr, 935 .optional_payload_unsafe_ptr, 936 undefined, 937 node_datas[node].rhs, 938 null, 939 ), 940 else => return orelseCatchExpr( 941 gz, 942 scope, 943 rl, 944 node, 945 node_datas[node].lhs, 946 .is_non_null, 947 .optional_payload_unsafe, 948 undefined, 949 node_datas[node].rhs, 950 null, 951 ), 952 }, 953 954 .ptr_type_aligned => return ptrType(gz, scope, rl, node, tree.ptrTypeAligned(node)), 955 .ptr_type_sentinel => return ptrType(gz, scope, rl, node, tree.ptrTypeSentinel(node)), 956 .ptr_type => return ptrType(gz, scope, rl, node, tree.ptrType(node)), 957 .ptr_type_bit_range => return ptrType(gz, scope, rl, node, tree.ptrTypeBitRange(node)), 958 959 .container_decl, 960 .container_decl_trailing, 961 => return containerDecl(gz, scope, rl, node, tree.containerDecl(node)), 962 .container_decl_two, .container_decl_two_trailing => { 963 var buffer: [2]Ast.Node.Index = undefined; 964 return containerDecl(gz, scope, rl, node, tree.containerDeclTwo(&buffer, node)); 965 }, 966 .container_decl_arg, 967 .container_decl_arg_trailing, 968 => return containerDecl(gz, scope, rl, node, tree.containerDeclArg(node)), 969 970 .tagged_union, 971 .tagged_union_trailing, 972 => return containerDecl(gz, scope, rl, node, tree.taggedUnion(node)), 973 .tagged_union_two, .tagged_union_two_trailing => { 974 var buffer: [2]Ast.Node.Index = undefined; 975 return containerDecl(gz, scope, rl, node, tree.taggedUnionTwo(&buffer, node)); 976 }, 977 .tagged_union_enum_tag, 978 .tagged_union_enum_tag_trailing, 979 => return containerDecl(gz, scope, rl, node, tree.taggedUnionEnumTag(node)), 980 981 .@"break" => return breakExpr(gz, scope, node), 982 .@"continue" => return continueExpr(gz, scope, node), 983 .grouped_expression => return expr(gz, scope, rl, node_datas[node].lhs), 984 .array_type => return arrayType(gz, scope, rl, node), 985 .array_type_sentinel => return arrayTypeSentinel(gz, scope, rl, node), 986 .char_literal => return charLiteral(gz, rl, node), 987 .error_set_decl => return errorSetDecl(gz, rl, node), 988 .array_access => return arrayAccess(gz, scope, rl, node), 989 .@"comptime" => return comptimeExprAst(gz, scope, rl, node), 990 .@"switch", .switch_comma => return switchExpr(gz, scope, rl.br(), node), 991 992 .@"nosuspend" => return nosuspendExpr(gz, scope, rl, node), 993 .@"suspend" => return suspendExpr(gz, scope, node), 994 .@"await" => return awaitExpr(gz, scope, rl, node), 995 .@"resume" => return resumeExpr(gz, scope, rl, node), 996 997 .@"try" => return tryExpr(gz, scope, rl, node, node_datas[node].lhs), 998 999 .array_init_one, .array_init_one_comma => { 1000 var elements: [1]Ast.Node.Index = undefined; 1001 return arrayInitExpr(gz, scope, rl, node, tree.arrayInitOne(&elements, node)); 1002 }, 1003 .array_init_dot_two, .array_init_dot_two_comma => { 1004 var elements: [2]Ast.Node.Index = undefined; 1005 return arrayInitExpr(gz, scope, rl, node, tree.arrayInitDotTwo(&elements, node)); 1006 }, 1007 .array_init_dot, 1008 .array_init_dot_comma, 1009 => return arrayInitExpr(gz, scope, rl, node, tree.arrayInitDot(node)), 1010 .array_init, 1011 .array_init_comma, 1012 => return arrayInitExpr(gz, scope, rl, node, tree.arrayInit(node)), 1013 1014 .struct_init_one, .struct_init_one_comma => { 1015 var fields: [1]Ast.Node.Index = undefined; 1016 return structInitExpr(gz, scope, rl, node, tree.structInitOne(&fields, node)); 1017 }, 1018 .struct_init_dot_two, .struct_init_dot_two_comma => { 1019 var fields: [2]Ast.Node.Index = undefined; 1020 return structInitExpr(gz, scope, rl, node, tree.structInitDotTwo(&fields, node)); 1021 }, 1022 .struct_init_dot, 1023 .struct_init_dot_comma, 1024 => return structInitExpr(gz, scope, rl, node, tree.structInitDot(node)), 1025 .struct_init, 1026 .struct_init_comma, 1027 => return structInitExpr(gz, scope, rl, node, tree.structInit(node)), 1028 1029 .fn_proto_simple => { 1030 var params: [1]Ast.Node.Index = undefined; 1031 return fnProtoExpr(gz, scope, rl, node, tree.fnProtoSimple(¶ms, node)); 1032 }, 1033 .fn_proto_multi => { 1034 return fnProtoExpr(gz, scope, rl, node, tree.fnProtoMulti(node)); 1035 }, 1036 .fn_proto_one => { 1037 var params: [1]Ast.Node.Index = undefined; 1038 return fnProtoExpr(gz, scope, rl, node, tree.fnProtoOne(¶ms, node)); 1039 }, 1040 .fn_proto => { 1041 return fnProtoExpr(gz, scope, rl, node, tree.fnProto(node)); 1042 }, 1043 } 1044 } 1045 1046 fn nosuspendExpr( 1047 gz: *GenZir, 1048 scope: *Scope, 1049 rl: ResultLoc, 1050 node: Ast.Node.Index, 1051 ) InnerError!Zir.Inst.Ref { 1052 const astgen = gz.astgen; 1053 const tree = astgen.tree; 1054 const node_datas = tree.nodes.items(.data); 1055 const body_node = node_datas[node].lhs; 1056 assert(body_node != 0); 1057 if (gz.nosuspend_node != 0) { 1058 try astgen.appendErrorNodeNotes(node, "redundant nosuspend block", .{}, &[_]u32{ 1059 try astgen.errNoteNode(gz.nosuspend_node, "other nosuspend block here", .{}), 1060 }); 1061 } 1062 gz.nosuspend_node = node; 1063 defer gz.nosuspend_node = 0; 1064 return expr(gz, scope, rl, body_node); 1065 } 1066 1067 fn suspendExpr( 1068 gz: *GenZir, 1069 scope: *Scope, 1070 node: Ast.Node.Index, 1071 ) InnerError!Zir.Inst.Ref { 1072 const astgen = gz.astgen; 1073 const gpa = astgen.gpa; 1074 const tree = astgen.tree; 1075 const node_datas = tree.nodes.items(.data); 1076 const body_node = node_datas[node].lhs; 1077 1078 if (gz.nosuspend_node != 0) { 1079 return astgen.failNodeNotes(node, "suspend inside nosuspend block", .{}, &[_]u32{ 1080 try astgen.errNoteNode(gz.nosuspend_node, "nosuspend block here", .{}), 1081 }); 1082 } 1083 if (gz.suspend_node != 0) { 1084 return astgen.failNodeNotes(node, "cannot suspend inside suspend block", .{}, &[_]u32{ 1085 try astgen.errNoteNode(gz.suspend_node, "other suspend block here", .{}), 1086 }); 1087 } 1088 assert(body_node != 0); 1089 1090 const suspend_inst = try gz.makeBlockInst(.suspend_block, node); 1091 try gz.instructions.append(gpa, suspend_inst); 1092 1093 var suspend_scope = gz.makeSubBlock(scope); 1094 suspend_scope.suspend_node = node; 1095 defer suspend_scope.unstack(); 1096 1097 const body_result = try expr(&suspend_scope, &suspend_scope.base, .none, body_node); 1098 if (!gz.refIsNoReturn(body_result)) { 1099 _ = try suspend_scope.addBreak(.break_inline, suspend_inst, .void_value); 1100 } 1101 try suspend_scope.setBlockBody(suspend_inst); 1102 1103 return indexToRef(suspend_inst); 1104 } 1105 1106 fn awaitExpr( 1107 gz: *GenZir, 1108 scope: *Scope, 1109 rl: ResultLoc, 1110 node: Ast.Node.Index, 1111 ) InnerError!Zir.Inst.Ref { 1112 const astgen = gz.astgen; 1113 const tree = astgen.tree; 1114 const node_datas = tree.nodes.items(.data); 1115 const rhs_node = node_datas[node].lhs; 1116 1117 if (gz.suspend_node != 0) { 1118 return astgen.failNodeNotes(node, "cannot await inside suspend block", .{}, &[_]u32{ 1119 try astgen.errNoteNode(gz.suspend_node, "suspend block here", .{}), 1120 }); 1121 } 1122 const operand = try expr(gz, scope, .none, rhs_node); 1123 const result = if (gz.nosuspend_node != 0) 1124 try gz.addExtendedPayload(.await_nosuspend, Zir.Inst.UnNode{ 1125 .node = gz.nodeIndexToRelative(node), 1126 .operand = operand, 1127 }) 1128 else 1129 try gz.addUnNode(.@"await", operand, node); 1130 1131 return rvalue(gz, rl, result, node); 1132 } 1133 1134 fn resumeExpr( 1135 gz: *GenZir, 1136 scope: *Scope, 1137 rl: ResultLoc, 1138 node: Ast.Node.Index, 1139 ) InnerError!Zir.Inst.Ref { 1140 const astgen = gz.astgen; 1141 const tree = astgen.tree; 1142 const node_datas = tree.nodes.items(.data); 1143 const rhs_node = node_datas[node].lhs; 1144 const operand = try expr(gz, scope, .none, rhs_node); 1145 const result = try gz.addUnNode(.@"resume", operand, node); 1146 return rvalue(gz, rl, result, node); 1147 } 1148 1149 fn fnProtoExpr( 1150 gz: *GenZir, 1151 scope: *Scope, 1152 rl: ResultLoc, 1153 node: Ast.Node.Index, 1154 fn_proto: Ast.full.FnProto, 1155 ) InnerError!Zir.Inst.Ref { 1156 const astgen = gz.astgen; 1157 const tree = astgen.tree; 1158 const token_tags = tree.tokens.items(.tag); 1159 1160 const is_extern = blk: { 1161 const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false; 1162 break :blk token_tags[maybe_extern_token] == .keyword_extern; 1163 }; 1164 assert(!is_extern); 1165 1166 var block_scope = gz.makeSubBlock(scope); 1167 defer block_scope.unstack(); 1168 1169 const block_inst = try gz.makeBlockInst(.block_inline, node); 1170 1171 var noalias_bits: u32 = 0; 1172 const is_var_args = is_var_args: { 1173 var param_type_i: usize = 0; 1174 var it = fn_proto.iterate(tree); 1175 while (it.next()) |param| : (param_type_i += 1) { 1176 const is_comptime = if (param.comptime_noalias) |token| switch (token_tags[token]) { 1177 .keyword_noalias => is_comptime: { 1178 noalias_bits |= @as(u32, 1) << (std.math.cast(u5, param_type_i) orelse 1179 return astgen.failTok(token, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{})); 1180 break :is_comptime false; 1181 }, 1182 .keyword_comptime => true, 1183 else => false, 1184 } else false; 1185 1186 const is_anytype = if (param.anytype_ellipsis3) |token| blk: { 1187 switch (token_tags[token]) { 1188 .keyword_anytype => break :blk true, 1189 .ellipsis3 => break :is_var_args true, 1190 else => unreachable, 1191 } 1192 } else false; 1193 1194 const param_name: u32 = if (param.name_token) |name_token| blk: { 1195 if (mem.eql(u8, "_", tree.tokenSlice(name_token))) 1196 break :blk 0; 1197 1198 break :blk try astgen.identAsString(name_token); 1199 } else 0; 1200 1201 if (is_anytype) { 1202 const name_token = param.name_token orelse param.anytype_ellipsis3.?; 1203 1204 const tag: Zir.Inst.Tag = if (is_comptime) 1205 .param_anytype_comptime 1206 else 1207 .param_anytype; 1208 _ = try block_scope.addStrTok(tag, param_name, name_token); 1209 } else { 1210 const param_type_node = param.type_expr; 1211 assert(param_type_node != 0); 1212 var param_gz = block_scope.makeSubBlock(scope); 1213 defer param_gz.unstack(); 1214 const param_type = try expr(¶m_gz, scope, coerced_type_rl, param_type_node); 1215 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1); 1216 _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type); 1217 const main_tokens = tree.nodes.items(.main_token); 1218 const name_token = param.name_token orelse main_tokens[param_type_node]; 1219 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param; 1220 const param_inst = try block_scope.addParam(¶m_gz, tag, name_token, param_name, param.first_doc_comment); 1221 assert(param_inst_expected == param_inst); 1222 } 1223 } 1224 break :is_var_args false; 1225 }; 1226 1227 const align_ref: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: { 1228 break :inst try expr(&block_scope, scope, align_rl, fn_proto.ast.align_expr); 1229 }; 1230 1231 if (fn_proto.ast.addrspace_expr != 0) { 1232 return astgen.failNode(fn_proto.ast.addrspace_expr, "addrspace not allowed on function prototypes", .{}); 1233 } 1234 1235 if (fn_proto.ast.section_expr != 0) { 1236 return astgen.failNode(fn_proto.ast.section_expr, "linksection not allowed on function prototypes", .{}); 1237 } 1238 1239 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0) 1240 try expr( 1241 &block_scope, 1242 scope, 1243 .{ .ty = .calling_convention_type }, 1244 fn_proto.ast.callconv_expr, 1245 ) 1246 else 1247 Zir.Inst.Ref.none; 1248 1249 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; 1250 const is_inferred_error = token_tags[maybe_bang] == .bang; 1251 if (is_inferred_error) { 1252 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{}); 1253 } 1254 const ret_ty = try expr(&block_scope, scope, coerced_type_rl, fn_proto.ast.return_type); 1255 1256 const result = try block_scope.addFunc(.{ 1257 .src_node = fn_proto.ast.proto_node, 1258 1259 .cc_ref = cc, 1260 .cc_gz = null, 1261 .align_ref = align_ref, 1262 .align_gz = null, 1263 .ret_ref = ret_ty, 1264 .ret_gz = null, 1265 .section_ref = .none, 1266 .section_gz = null, 1267 .addrspace_ref = .none, 1268 .addrspace_gz = null, 1269 1270 .param_block = block_inst, 1271 .body_gz = null, 1272 .lib_name = 0, 1273 .is_var_args = is_var_args, 1274 .is_inferred_error = false, 1275 .is_test = false, 1276 .is_extern = false, 1277 .noalias_bits = noalias_bits, 1278 }); 1279 1280 _ = try block_scope.addBreak(.break_inline, block_inst, result); 1281 try block_scope.setBlockBody(block_inst); 1282 try gz.instructions.append(astgen.gpa, block_inst); 1283 1284 return rvalue(gz, rl, indexToRef(block_inst), fn_proto.ast.proto_node); 1285 } 1286 1287 fn arrayInitExpr( 1288 gz: *GenZir, 1289 scope: *Scope, 1290 rl: ResultLoc, 1291 node: Ast.Node.Index, 1292 array_init: Ast.full.ArrayInit, 1293 ) InnerError!Zir.Inst.Ref { 1294 const astgen = gz.astgen; 1295 const tree = astgen.tree; 1296 const node_tags = tree.nodes.items(.tag); 1297 const main_tokens = tree.nodes.items(.main_token); 1298 1299 assert(array_init.ast.elements.len != 0); // Otherwise it would be struct init. 1300 1301 const types: struct { 1302 array: Zir.Inst.Ref, 1303 elem: Zir.Inst.Ref, 1304 } = inst: { 1305 if (array_init.ast.type_expr == 0) break :inst .{ 1306 .array = .none, 1307 .elem = .none, 1308 }; 1309 1310 infer: { 1311 const array_type: Ast.full.ArrayType = switch (node_tags[array_init.ast.type_expr]) { 1312 .array_type => tree.arrayType(array_init.ast.type_expr), 1313 .array_type_sentinel => tree.arrayTypeSentinel(array_init.ast.type_expr), 1314 else => break :infer, 1315 }; 1316 // This intentionally does not support `@"_"` syntax. 1317 if (node_tags[array_type.ast.elem_count] == .identifier and 1318 mem.eql(u8, tree.tokenSlice(main_tokens[array_type.ast.elem_count]), "_")) 1319 { 1320 const len_inst = try gz.addInt(array_init.ast.elements.len); 1321 const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type); 1322 if (array_type.ast.sentinel == 0) { 1323 const array_type_inst = try gz.addBin(.array_type, len_inst, elem_type); 1324 break :inst .{ 1325 .array = array_type_inst, 1326 .elem = elem_type, 1327 }; 1328 } else { 1329 const sentinel = try comptimeExpr(gz, scope, .{ .ty = elem_type }, array_type.ast.sentinel); 1330 const array_type_inst = try gz.addPlNode( 1331 .array_type_sentinel, 1332 array_init.ast.type_expr, 1333 Zir.Inst.ArrayTypeSentinel{ 1334 .len = len_inst, 1335 .elem_type = elem_type, 1336 .sentinel = sentinel, 1337 }, 1338 ); 1339 break :inst .{ 1340 .array = array_type_inst, 1341 .elem = elem_type, 1342 }; 1343 } 1344 } 1345 } 1346 const array_type_inst = try typeExpr(gz, scope, array_init.ast.type_expr); 1347 _ = try gz.addUnNode(.validate_array_init_ty, array_type_inst, node); 1348 break :inst .{ 1349 .array = array_type_inst, 1350 .elem = .none, 1351 }; 1352 }; 1353 1354 switch (rl) { 1355 .discard => { 1356 // TODO elements should still be coerced if type is provided 1357 for (array_init.ast.elements) |elem_init| { 1358 _ = try expr(gz, scope, .discard, elem_init); 1359 } 1360 return Zir.Inst.Ref.void_value; 1361 }, 1362 .ref => { 1363 const tag: Zir.Inst.Tag = if (types.array != .none) .array_init_ref else .array_init_anon_ref; 1364 return arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag); 1365 }, 1366 .none => { 1367 const tag: Zir.Inst.Tag = if (types.array != .none) .array_init else .array_init_anon; 1368 return arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag); 1369 }, 1370 .ty, .coerced_ty => { 1371 const tag: Zir.Inst.Tag = if (types.array != .none) .array_init else .array_init_anon; 1372 const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag); 1373 return rvalue(gz, rl, result, node); 1374 }, 1375 .ptr => |ptr_inst| { 1376 return arrayInitExprRlPtr(gz, scope, rl, node, ptr_inst, array_init.ast.elements, types.array); 1377 }, 1378 .inferred_ptr => |ptr_inst| { 1379 if (types.array == .none) { 1380 // We treat this case differently so that we don't get a crash when 1381 // analyzing array_base_ptr against an alloc_inferred_mut. 1382 // See corresponding logic in structInitExpr. 1383 const result = try arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon); 1384 return rvalue(gz, rl, result, node); 1385 } else { 1386 return arrayInitExprRlPtr(gz, scope, rl, node, ptr_inst, array_init.ast.elements, types.array); 1387 } 1388 }, 1389 .block_ptr => |block_gz| { 1390 // This condition is here for the same reason as the above condition in `inferred_ptr`. 1391 // See corresponding logic in structInitExpr. 1392 if (types.array == .none and astgen.isInferred(block_gz.rl_ptr)) { 1393 const result = try arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon); 1394 return rvalue(gz, rl, result, node); 1395 } 1396 return arrayInitExprRlPtr(gz, scope, rl, node, block_gz.rl_ptr, array_init.ast.elements, types.array); 1397 }, 1398 } 1399 } 1400 1401 fn arrayInitExprRlNone( 1402 gz: *GenZir, 1403 scope: *Scope, 1404 node: Ast.Node.Index, 1405 elements: []const Ast.Node.Index, 1406 tag: Zir.Inst.Tag, 1407 ) InnerError!Zir.Inst.Ref { 1408 const astgen = gz.astgen; 1409 1410 const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{ 1411 .operands_len = @intCast(u32, elements.len), 1412 }); 1413 var extra_index = try reserveExtra(astgen, elements.len); 1414 1415 for (elements) |elem_init| { 1416 const elem_ref = try expr(gz, scope, .none, elem_init); 1417 astgen.extra.items[extra_index] = @enumToInt(elem_ref); 1418 extra_index += 1; 1419 } 1420 return try gz.addPlNodePayloadIndex(tag, node, payload_index); 1421 } 1422 1423 fn arrayInitExprInner( 1424 gz: *GenZir, 1425 scope: *Scope, 1426 node: Ast.Node.Index, 1427 elements: []const Ast.Node.Index, 1428 array_ty_inst: Zir.Inst.Ref, 1429 elem_ty: Zir.Inst.Ref, 1430 tag: Zir.Inst.Tag, 1431 ) InnerError!Zir.Inst.Ref { 1432 const astgen = gz.astgen; 1433 1434 const len = elements.len + @boolToInt(array_ty_inst != .none); 1435 const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{ 1436 .operands_len = @intCast(u32, len), 1437 }); 1438 var extra_index = try reserveExtra(astgen, len); 1439 if (array_ty_inst != .none) { 1440 astgen.extra.items[extra_index] = @enumToInt(array_ty_inst); 1441 extra_index += 1; 1442 } 1443 1444 for (elements) |elem_init, i| { 1445 const rl = if (elem_ty != .none) 1446 ResultLoc{ .coerced_ty = elem_ty } 1447 else if (array_ty_inst != .none and nodeMayNeedMemoryLocation(astgen.tree, elem_init, true)) rl: { 1448 const ty_expr = try gz.add(.{ 1449 .tag = .elem_type_index, 1450 .data = .{ .bin = .{ 1451 .lhs = array_ty_inst, 1452 .rhs = @intToEnum(Zir.Inst.Ref, i), 1453 } }, 1454 }); 1455 break :rl ResultLoc{ .coerced_ty = ty_expr }; 1456 } else ResultLoc{ .none = {} }; 1457 1458 const elem_ref = try expr(gz, scope, rl, elem_init); 1459 astgen.extra.items[extra_index] = @enumToInt(elem_ref); 1460 extra_index += 1; 1461 } 1462 1463 return try gz.addPlNodePayloadIndex(tag, node, payload_index); 1464 } 1465 1466 fn arrayInitExprRlPtr( 1467 gz: *GenZir, 1468 scope: *Scope, 1469 rl: ResultLoc, 1470 node: Ast.Node.Index, 1471 result_ptr: Zir.Inst.Ref, 1472 elements: []const Ast.Node.Index, 1473 array_ty: Zir.Inst.Ref, 1474 ) InnerError!Zir.Inst.Ref { 1475 if (array_ty == .none) { 1476 const base_ptr = try gz.addUnNode(.array_base_ptr, result_ptr, node); 1477 return arrayInitExprRlPtrInner(gz, scope, node, base_ptr, elements); 1478 } 1479 1480 var as_scope = try gz.makeCoercionScope(scope, array_ty, result_ptr, node); 1481 defer as_scope.unstack(); 1482 1483 const result = try arrayInitExprRlPtrInner(&as_scope, scope, node, as_scope.rl_ptr, elements); 1484 return as_scope.finishCoercion(gz, rl, node, result, array_ty); 1485 } 1486 1487 fn arrayInitExprRlPtrInner( 1488 gz: *GenZir, 1489 scope: *Scope, 1490 node: Ast.Node.Index, 1491 result_ptr: Zir.Inst.Ref, 1492 elements: []const Ast.Node.Index, 1493 ) InnerError!Zir.Inst.Ref { 1494 const astgen = gz.astgen; 1495 1496 const payload_index = try addExtra(astgen, Zir.Inst.Block{ 1497 .body_len = @intCast(u32, elements.len), 1498 }); 1499 var extra_index = try reserveExtra(astgen, elements.len); 1500 1501 for (elements) |elem_init, i| { 1502 const elem_ptr = try gz.addPlNode(.elem_ptr_imm, elem_init, Zir.Inst.ElemPtrImm{ 1503 .ptr = result_ptr, 1504 .index = @intCast(u32, i), 1505 }); 1506 astgen.extra.items[extra_index] = refToIndex(elem_ptr).?; 1507 extra_index += 1; 1508 _ = try expr(gz, scope, .{ .ptr = elem_ptr }, elem_init); 1509 } 1510 1511 const tag: Zir.Inst.Tag = if (gz.force_comptime) 1512 .validate_array_init_comptime 1513 else 1514 .validate_array_init; 1515 1516 _ = try gz.addPlNodePayloadIndex(tag, node, payload_index); 1517 return .void_value; 1518 } 1519 1520 fn structInitExpr( 1521 gz: *GenZir, 1522 scope: *Scope, 1523 rl: ResultLoc, 1524 node: Ast.Node.Index, 1525 struct_init: Ast.full.StructInit, 1526 ) InnerError!Zir.Inst.Ref { 1527 const astgen = gz.astgen; 1528 const tree = astgen.tree; 1529 1530 if (struct_init.ast.type_expr == 0) { 1531 if (struct_init.ast.fields.len == 0) { 1532 return rvalue(gz, rl, .empty_struct, node); 1533 } 1534 } else array: { 1535 const node_tags = tree.nodes.items(.tag); 1536 const main_tokens = tree.nodes.items(.main_token); 1537 const array_type: Ast.full.ArrayType = switch (node_tags[struct_init.ast.type_expr]) { 1538 .array_type => tree.arrayType(struct_init.ast.type_expr), 1539 .array_type_sentinel => tree.arrayTypeSentinel(struct_init.ast.type_expr), 1540 else => { 1541 if (struct_init.ast.fields.len == 0) { 1542 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1543 const result = try gz.addUnNode(.struct_init_empty, ty_inst, node); 1544 return rvalue(gz, rl, result, node); 1545 } 1546 break :array; 1547 }, 1548 }; 1549 const is_inferred_array_len = node_tags[array_type.ast.elem_count] == .identifier and 1550 // This intentionally does not support `@"_"` syntax. 1551 mem.eql(u8, tree.tokenSlice(main_tokens[array_type.ast.elem_count]), "_"); 1552 if (struct_init.ast.fields.len == 0) { 1553 if (is_inferred_array_len) { 1554 const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type); 1555 const array_type_inst = if (array_type.ast.sentinel == 0) blk: { 1556 break :blk try gz.addBin(.array_type, .zero_usize, elem_type); 1557 } else blk: { 1558 const sentinel = try comptimeExpr(gz, scope, .{ .ty = elem_type }, array_type.ast.sentinel); 1559 break :blk try gz.addPlNode( 1560 .array_type_sentinel, 1561 struct_init.ast.type_expr, 1562 Zir.Inst.ArrayTypeSentinel{ 1563 .len = .zero_usize, 1564 .elem_type = elem_type, 1565 .sentinel = sentinel, 1566 }, 1567 ); 1568 }; 1569 const result = try gz.addUnNode(.struct_init_empty, array_type_inst, node); 1570 return rvalue(gz, rl, result, node); 1571 } 1572 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1573 const result = try gz.addUnNode(.struct_init_empty, ty_inst, node); 1574 return rvalue(gz, rl, result, node); 1575 } else { 1576 return astgen.failNode( 1577 struct_init.ast.type_expr, 1578 "initializing array with struct syntax", 1579 .{}, 1580 ); 1581 } 1582 } 1583 1584 switch (rl) { 1585 .discard => { 1586 // TODO if a type expr is given the fields should be validated for that type 1587 if (struct_init.ast.type_expr != 0) { 1588 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1589 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); 1590 } 1591 for (struct_init.ast.fields) |field_init| { 1592 _ = try expr(gz, scope, .discard, field_init); 1593 } 1594 return Zir.Inst.Ref.void_value; 1595 }, 1596 .ref => { 1597 if (struct_init.ast.type_expr != 0) { 1598 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1599 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); 1600 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init_ref); 1601 } else { 1602 return structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon_ref); 1603 } 1604 }, 1605 .none => { 1606 if (struct_init.ast.type_expr != 0) { 1607 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1608 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); 1609 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init); 1610 } else { 1611 return structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon); 1612 } 1613 }, 1614 .ty, .coerced_ty => |ty_inst| { 1615 if (struct_init.ast.type_expr == 0) { 1616 const result = try structInitExprRlNone(gz, scope, node, struct_init, ty_inst, .struct_init_anon); 1617 return rvalue(gz, rl, result, node); 1618 } 1619 const inner_ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1620 _ = try gz.addUnNode(.validate_struct_init_ty, inner_ty_inst, node); 1621 const result = try structInitExprRlTy(gz, scope, node, struct_init, inner_ty_inst, .struct_init); 1622 return rvalue(gz, rl, result, node); 1623 }, 1624 .ptr => |ptr_inst| return structInitExprRlPtr(gz, scope, rl, node, struct_init, ptr_inst), 1625 .inferred_ptr => |ptr_inst| { 1626 if (struct_init.ast.type_expr == 0) { 1627 // We treat this case differently so that we don't get a crash when 1628 // analyzing field_base_ptr against an alloc_inferred_mut. 1629 // See corresponding logic in arrayInitExpr. 1630 const result = try structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon); 1631 return rvalue(gz, rl, result, node); 1632 } else { 1633 return structInitExprRlPtr(gz, scope, rl, node, struct_init, ptr_inst); 1634 } 1635 }, 1636 .block_ptr => |block_gz| { 1637 // This condition is here for the same reason as the above condition in `inferred_ptr`. 1638 // See corresponding logic in arrayInitExpr. 1639 if (struct_init.ast.type_expr == 0 and astgen.isInferred(block_gz.rl_ptr)) { 1640 const result = try structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon); 1641 return rvalue(gz, rl, result, node); 1642 } 1643 1644 return structInitExprRlPtr(gz, scope, rl, node, struct_init, block_gz.rl_ptr); 1645 }, 1646 } 1647 } 1648 1649 fn structInitExprRlNone( 1650 gz: *GenZir, 1651 scope: *Scope, 1652 node: Ast.Node.Index, 1653 struct_init: Ast.full.StructInit, 1654 ty_inst: Zir.Inst.Ref, 1655 tag: Zir.Inst.Tag, 1656 ) InnerError!Zir.Inst.Ref { 1657 const astgen = gz.astgen; 1658 const tree = astgen.tree; 1659 1660 const payload_index = try addExtra(astgen, Zir.Inst.StructInitAnon{ 1661 .fields_len = @intCast(u32, struct_init.ast.fields.len), 1662 }); 1663 const field_size = @typeInfo(Zir.Inst.StructInitAnon.Item).Struct.fields.len; 1664 var extra_index: usize = try reserveExtra(astgen, struct_init.ast.fields.len * field_size); 1665 1666 for (struct_init.ast.fields) |field_init| { 1667 const name_token = tree.firstToken(field_init) - 2; 1668 const str_index = try astgen.identAsString(name_token); 1669 const sub_rl: ResultLoc = if (ty_inst != .none) 1670 ResultLoc{ .ty = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{ 1671 .container_type = ty_inst, 1672 .name_start = str_index, 1673 }) } 1674 else 1675 .none; 1676 setExtra(astgen, extra_index, Zir.Inst.StructInitAnon.Item{ 1677 .field_name = str_index, 1678 .init = try expr(gz, scope, sub_rl, field_init), 1679 }); 1680 extra_index += field_size; 1681 } 1682 1683 return try gz.addPlNodePayloadIndex(tag, node, payload_index); 1684 } 1685 1686 fn structInitExprRlPtr( 1687 gz: *GenZir, 1688 scope: *Scope, 1689 rl: ResultLoc, 1690 node: Ast.Node.Index, 1691 struct_init: Ast.full.StructInit, 1692 result_ptr: Zir.Inst.Ref, 1693 ) InnerError!Zir.Inst.Ref { 1694 if (struct_init.ast.type_expr == 0) { 1695 const base_ptr = try gz.addUnNode(.field_base_ptr, result_ptr, node); 1696 return structInitExprRlPtrInner(gz, scope, node, struct_init, base_ptr); 1697 } 1698 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1699 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); 1700 1701 var as_scope = try gz.makeCoercionScope(scope, ty_inst, result_ptr, node); 1702 defer as_scope.unstack(); 1703 1704 const result = try structInitExprRlPtrInner(&as_scope, scope, node, struct_init, as_scope.rl_ptr); 1705 return as_scope.finishCoercion(gz, rl, node, result, ty_inst); 1706 } 1707 1708 fn structInitExprRlPtrInner( 1709 gz: *GenZir, 1710 scope: *Scope, 1711 node: Ast.Node.Index, 1712 struct_init: Ast.full.StructInit, 1713 result_ptr: Zir.Inst.Ref, 1714 ) InnerError!Zir.Inst.Ref { 1715 const astgen = gz.astgen; 1716 const tree = astgen.tree; 1717 1718 const payload_index = try addExtra(astgen, Zir.Inst.Block{ 1719 .body_len = @intCast(u32, struct_init.ast.fields.len), 1720 }); 1721 var extra_index = try reserveExtra(astgen, struct_init.ast.fields.len); 1722 1723 for (struct_init.ast.fields) |field_init| { 1724 const name_token = tree.firstToken(field_init) - 2; 1725 const str_index = try astgen.identAsString(name_token); 1726 const field_ptr = try gz.addPlNode(.field_ptr, field_init, Zir.Inst.Field{ 1727 .lhs = result_ptr, 1728 .field_name_start = str_index, 1729 }); 1730 astgen.extra.items[extra_index] = refToIndex(field_ptr).?; 1731 extra_index += 1; 1732 _ = try expr(gz, scope, .{ .ptr = field_ptr }, field_init); 1733 } 1734 1735 const tag: Zir.Inst.Tag = if (gz.force_comptime) 1736 .validate_struct_init_comptime 1737 else 1738 .validate_struct_init; 1739 1740 _ = try gz.addPlNodePayloadIndex(tag, node, payload_index); 1741 return Zir.Inst.Ref.void_value; 1742 } 1743 1744 fn structInitExprRlTy( 1745 gz: *GenZir, 1746 scope: *Scope, 1747 node: Ast.Node.Index, 1748 struct_init: Ast.full.StructInit, 1749 ty_inst: Zir.Inst.Ref, 1750 tag: Zir.Inst.Tag, 1751 ) InnerError!Zir.Inst.Ref { 1752 const astgen = gz.astgen; 1753 const tree = astgen.tree; 1754 1755 const payload_index = try addExtra(astgen, Zir.Inst.StructInit{ 1756 .fields_len = @intCast(u32, struct_init.ast.fields.len), 1757 }); 1758 const field_size = @typeInfo(Zir.Inst.StructInit.Item).Struct.fields.len; 1759 var extra_index: usize = try reserveExtra(astgen, struct_init.ast.fields.len * field_size); 1760 1761 for (struct_init.ast.fields) |field_init| { 1762 const name_token = tree.firstToken(field_init) - 2; 1763 const str_index = try astgen.identAsString(name_token); 1764 const field_ty_inst = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{ 1765 .container_type = ty_inst, 1766 .name_start = str_index, 1767 }); 1768 setExtra(astgen, extra_index, Zir.Inst.StructInit.Item{ 1769 .field_type = refToIndex(field_ty_inst).?, 1770 .init = try expr(gz, scope, .{ .ty = field_ty_inst }, field_init), 1771 }); 1772 extra_index += field_size; 1773 } 1774 1775 return try gz.addPlNodePayloadIndex(tag, node, payload_index); 1776 } 1777 1778 /// This calls expr in a comptime scope, and is intended to be called as a helper function. 1779 /// The one that corresponds to `comptime` expression syntax is `comptimeExprAst`. 1780 fn comptimeExpr( 1781 gz: *GenZir, 1782 scope: *Scope, 1783 rl: ResultLoc, 1784 node: Ast.Node.Index, 1785 ) InnerError!Zir.Inst.Ref { 1786 const prev_force_comptime = gz.force_comptime; 1787 gz.force_comptime = true; 1788 defer gz.force_comptime = prev_force_comptime; 1789 1790 return expr(gz, scope, rl, node); 1791 } 1792 1793 /// This one is for an actual `comptime` syntax, and will emit a compile error if 1794 /// the scope already has `force_comptime=true`. 1795 /// See `comptimeExpr` for the helper function for calling expr in a comptime scope. 1796 fn comptimeExprAst( 1797 gz: *GenZir, 1798 scope: *Scope, 1799 rl: ResultLoc, 1800 node: Ast.Node.Index, 1801 ) InnerError!Zir.Inst.Ref { 1802 const astgen = gz.astgen; 1803 if (gz.force_comptime) { 1804 return astgen.failNode(node, "redundant comptime keyword in already comptime scope", .{}); 1805 } 1806 const tree = astgen.tree; 1807 const node_datas = tree.nodes.items(.data); 1808 const body_node = node_datas[node].lhs; 1809 gz.force_comptime = true; 1810 const result = try expr(gz, scope, rl, body_node); 1811 gz.force_comptime = false; 1812 return result; 1813 } 1814 1815 fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 1816 const astgen = parent_gz.astgen; 1817 const tree = astgen.tree; 1818 const node_datas = tree.nodes.items(.data); 1819 const break_label = node_datas[node].lhs; 1820 const rhs = node_datas[node].rhs; 1821 1822 // Look for the label in the scope. 1823 var scope = parent_scope; 1824 while (true) { 1825 switch (scope.tag) { 1826 .gen_zir => { 1827 const block_gz = scope.cast(GenZir).?; 1828 1829 const block_inst = blk: { 1830 if (break_label != 0) { 1831 if (block_gz.label) |*label| { 1832 if (try astgen.tokenIdentEql(label.token, break_label)) { 1833 label.used = true; 1834 break :blk label.block_inst; 1835 } 1836 } 1837 } else if (block_gz.break_block != 0) { 1838 break :blk block_gz.break_block; 1839 } 1840 scope = block_gz.parent; 1841 continue; 1842 }; 1843 1844 const break_tag: Zir.Inst.Tag = if (block_gz.is_inline or block_gz.force_comptime) 1845 .break_inline 1846 else 1847 .@"break"; 1848 1849 if (rhs == 0) { 1850 try genDefers(parent_gz, scope, parent_scope, .normal_only); 1851 1852 _ = try parent_gz.addBreak(break_tag, block_inst, .void_value); 1853 return Zir.Inst.Ref.unreachable_value; 1854 } 1855 block_gz.break_count += 1; 1856 1857 // The loop scope has a mechanism to prevent rvalue() from emitting a 1858 // store to the result location for the loop body (since it is continues 1859 // rather than returning a result from the loop) but here is a `break` 1860 // which needs to override this behavior. 1861 const prev_rvalue_noresult = parent_gz.rvalue_noresult; 1862 parent_gz.rvalue_noresult = .none; 1863 const operand = try reachableExpr(parent_gz, parent_scope, block_gz.break_result_loc, rhs, node); 1864 const search_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 1865 parent_gz.rvalue_noresult = prev_rvalue_noresult; 1866 1867 try genDefers(parent_gz, scope, parent_scope, .normal_only); 1868 1869 switch (block_gz.break_result_loc) { 1870 .block_ptr => { 1871 const br = try parent_gz.addBreak(break_tag, block_inst, operand); 1872 try block_gz.labeled_breaks.append(astgen.gpa, .{ .br = br, .search = search_index }); 1873 }, 1874 .ptr => { 1875 // In this case we don't have any mechanism to intercept it; 1876 // we assume the result location is written, and we break with void. 1877 _ = try parent_gz.addBreak(break_tag, block_inst, .void_value); 1878 }, 1879 .discard => { 1880 _ = try parent_gz.addBreak(break_tag, block_inst, .void_value); 1881 }, 1882 else => { 1883 _ = try parent_gz.addBreak(break_tag, block_inst, operand); 1884 }, 1885 } 1886 return Zir.Inst.Ref.unreachable_value; 1887 }, 1888 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 1889 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 1890 .namespace => break, 1891 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, 1892 .top => unreachable, 1893 } 1894 } 1895 if (break_label != 0) { 1896 const label_name = try astgen.identifierTokenString(break_label); 1897 return astgen.failTok(break_label, "label not found: '{s}'", .{label_name}); 1898 } else { 1899 return astgen.failNode(node, "break expression outside loop", .{}); 1900 } 1901 } 1902 1903 fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 1904 const astgen = parent_gz.astgen; 1905 const tree = astgen.tree; 1906 const node_datas = tree.nodes.items(.data); 1907 const break_label = node_datas[node].lhs; 1908 1909 // Look for the label in the scope. 1910 var scope = parent_scope; 1911 while (true) { 1912 switch (scope.tag) { 1913 .gen_zir => { 1914 const gen_zir = scope.cast(GenZir).?; 1915 const continue_block = gen_zir.continue_block; 1916 if (continue_block == 0) { 1917 scope = gen_zir.parent; 1918 continue; 1919 } 1920 if (break_label != 0) blk: { 1921 if (gen_zir.label) |*label| { 1922 if (try astgen.tokenIdentEql(label.token, break_label)) { 1923 label.used = true; 1924 break :blk; 1925 } 1926 } 1927 // found continue but either it has a different label, or no label 1928 scope = gen_zir.parent; 1929 continue; 1930 } 1931 1932 const break_tag: Zir.Inst.Tag = if (gen_zir.is_inline or gen_zir.force_comptime) 1933 .break_inline 1934 else 1935 .@"break"; 1936 _ = try parent_gz.addBreak(break_tag, continue_block, .void_value); 1937 return Zir.Inst.Ref.unreachable_value; 1938 }, 1939 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 1940 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 1941 .defer_normal => { 1942 const defer_scope = scope.cast(Scope.Defer).?; 1943 scope = defer_scope.parent; 1944 const expr_node = node_datas[defer_scope.defer_node].rhs; 1945 try unusedResultDeferExpr(parent_gz, defer_scope, defer_scope.parent, expr_node); 1946 }, 1947 .defer_error => scope = scope.cast(Scope.Defer).?.parent, 1948 .namespace => break, 1949 .top => unreachable, 1950 } 1951 } 1952 if (break_label != 0) { 1953 const label_name = try astgen.identifierTokenString(break_label); 1954 return astgen.failTok(break_label, "label not found: '{s}'", .{label_name}); 1955 } else { 1956 return astgen.failNode(node, "continue expression outside loop", .{}); 1957 } 1958 } 1959 1960 fn blockExpr( 1961 gz: *GenZir, 1962 scope: *Scope, 1963 rl: ResultLoc, 1964 block_node: Ast.Node.Index, 1965 statements: []const Ast.Node.Index, 1966 ) InnerError!Zir.Inst.Ref { 1967 const tracy = trace(@src()); 1968 defer tracy.end(); 1969 1970 const astgen = gz.astgen; 1971 const tree = astgen.tree; 1972 const main_tokens = tree.nodes.items(.main_token); 1973 const token_tags = tree.tokens.items(.tag); 1974 1975 const lbrace = main_tokens[block_node]; 1976 if (token_tags[lbrace - 1] == .colon and 1977 token_tags[lbrace - 2] == .identifier) 1978 { 1979 return labeledBlockExpr(gz, scope, rl, block_node, statements); 1980 } 1981 1982 try blockExprStmts(gz, scope, statements); 1983 return rvalue(gz, rl, .void_value, block_node); 1984 } 1985 1986 fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: Ast.TokenIndex) !void { 1987 // Look for the label in the scope. 1988 var scope = parent_scope; 1989 while (true) { 1990 switch (scope.tag) { 1991 .gen_zir => { 1992 const gen_zir = scope.cast(GenZir).?; 1993 if (gen_zir.label) |prev_label| { 1994 if (try astgen.tokenIdentEql(label, prev_label.token)) { 1995 const label_name = try astgen.identifierTokenString(label); 1996 return astgen.failTokNotes(label, "redefinition of label '{s}'", .{ 1997 label_name, 1998 }, &[_]u32{ 1999 try astgen.errNoteTok( 2000 prev_label.token, 2001 "previous definition here", 2002 .{}, 2003 ), 2004 }); 2005 } 2006 } 2007 scope = gen_zir.parent; 2008 }, 2009 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 2010 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 2011 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, 2012 .namespace => break, 2013 .top => unreachable, 2014 } 2015 } 2016 } 2017 2018 fn labeledBlockExpr( 2019 gz: *GenZir, 2020 parent_scope: *Scope, 2021 rl: ResultLoc, 2022 block_node: Ast.Node.Index, 2023 statements: []const Ast.Node.Index, 2024 ) InnerError!Zir.Inst.Ref { 2025 const tracy = trace(@src()); 2026 defer tracy.end(); 2027 2028 const astgen = gz.astgen; 2029 const tree = astgen.tree; 2030 const main_tokens = tree.nodes.items(.main_token); 2031 const token_tags = tree.tokens.items(.tag); 2032 2033 const lbrace = main_tokens[block_node]; 2034 const label_token = lbrace - 2; 2035 assert(token_tags[label_token] == .identifier); 2036 2037 try astgen.checkLabelRedefinition(parent_scope, label_token); 2038 2039 // Reserve the Block ZIR instruction index so that we can put it into the GenZir struct 2040 // so that break statements can reference it. 2041 const block_tag: Zir.Inst.Tag = if (gz.force_comptime) .block_inline else .block; 2042 const block_inst = try gz.makeBlockInst(block_tag, block_node); 2043 try gz.instructions.append(astgen.gpa, block_inst); 2044 2045 var block_scope = gz.makeSubBlock(parent_scope); 2046 block_scope.label = GenZir.Label{ 2047 .token = label_token, 2048 .block_inst = block_inst, 2049 }; 2050 block_scope.setBreakResultLoc(rl); 2051 defer block_scope.unstack(); 2052 defer block_scope.labeled_breaks.deinit(astgen.gpa); 2053 2054 try blockExprStmts(&block_scope, &block_scope.base, statements); 2055 if (!block_scope.endsWithNoReturn()) { 2056 const break_tag: Zir.Inst.Tag = if (block_scope.force_comptime) .break_inline else .@"break"; 2057 _ = try block_scope.addBreak(break_tag, block_inst, .void_value); 2058 } 2059 2060 if (!block_scope.label.?.used) { 2061 try astgen.appendErrorTok(label_token, "unused block label", .{}); 2062 } 2063 2064 const zir_datas = gz.astgen.instructions.items(.data); 2065 const zir_tags = gz.astgen.instructions.items(.tag); 2066 const strat = rl.strategy(&block_scope); 2067 switch (strat.tag) { 2068 .break_void => { 2069 // The code took advantage of the result location as a pointer. 2070 // Turn the break instruction operands into void. 2071 for (block_scope.labeled_breaks.items) |br| { 2072 zir_datas[br.br].@"break".operand = .void_value; 2073 } 2074 try block_scope.setBlockBody(block_inst); 2075 2076 return indexToRef(block_inst); 2077 }, 2078 .break_operand => { 2079 // All break operands are values that did not use the result location pointer. 2080 // The break instructions need to have their operands coerced if the 2081 // block's result location is a `ty`. In this case we overwrite the 2082 // `store_to_block_ptr` instruction with an `as` instruction and repurpose 2083 // it as the break operand. 2084 // This corresponds to similar code in `setCondBrPayloadElideBlockStorePtr`. 2085 if (block_scope.rl_ty_inst != .none) { 2086 for (block_scope.labeled_breaks.items) |br| { 2087 // We expect the `store_to_block_ptr` to be created between 1-3 instructions 2088 // prior to the break. 2089 var search_index = br.search -| 3; 2090 while (search_index < br.search) : (search_index += 1) { 2091 if (zir_tags[search_index] == .store_to_block_ptr and 2092 zir_datas[search_index].bin.lhs == block_scope.rl_ptr) 2093 { 2094 zir_tags[search_index] = .as; 2095 zir_datas[search_index].bin = .{ 2096 .lhs = block_scope.rl_ty_inst, 2097 .rhs = zir_datas[br.br].@"break".operand, 2098 }; 2099 zir_datas[br.br].@"break".operand = indexToRef(search_index); 2100 break; 2101 } 2102 } else unreachable; 2103 } 2104 } 2105 try block_scope.setBlockBody(block_inst); 2106 const block_ref = indexToRef(block_inst); 2107 switch (rl) { 2108 .ref => return block_ref, 2109 else => return rvalue(gz, rl, block_ref, block_node), 2110 } 2111 }, 2112 } 2113 } 2114 2115 fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Node.Index) !void { 2116 const astgen = gz.astgen; 2117 const tree = astgen.tree; 2118 const node_tags = tree.nodes.items(.tag); 2119 2120 if (statements.len == 0) return; 2121 2122 try gz.addDbgBlockBegin(); 2123 2124 var block_arena = std.heap.ArenaAllocator.init(gz.astgen.gpa); 2125 defer block_arena.deinit(); 2126 const block_arena_allocator = block_arena.allocator(); 2127 2128 var noreturn_src_node: Ast.Node.Index = 0; 2129 var scope = parent_scope; 2130 for (statements) |statement| { 2131 if (noreturn_src_node != 0) { 2132 try astgen.appendErrorNodeNotes( 2133 statement, 2134 "unreachable code", 2135 .{}, 2136 &[_]u32{ 2137 try astgen.errNoteNode( 2138 noreturn_src_node, 2139 "control flow is diverted here", 2140 .{}, 2141 ), 2142 }, 2143 ); 2144 } 2145 switch (node_tags[statement]) { 2146 // zig fmt: off 2147 .global_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.globalVarDecl(statement)), 2148 .local_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.localVarDecl(statement)), 2149 .simple_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.simpleVarDecl(statement)), 2150 .aligned_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.alignedVarDecl(statement)), 2151 2152 .@"defer" => scope = try makeDeferScope(gz.astgen, scope, statement, block_arena_allocator, .defer_normal), 2153 .@"errdefer" => scope = try makeDeferScope(gz.astgen, scope, statement, block_arena_allocator, .defer_error), 2154 2155 .assign => try assign(gz, scope, statement), 2156 2157 .assign_shl => try assignShift(gz, scope, statement, .shl), 2158 .assign_shr => try assignShift(gz, scope, statement, .shr), 2159 2160 .assign_bit_and => try assignOp(gz, scope, statement, .bit_and), 2161 .assign_bit_or => try assignOp(gz, scope, statement, .bit_or), 2162 .assign_bit_xor => try assignOp(gz, scope, statement, .xor), 2163 .assign_div => try assignOp(gz, scope, statement, .div), 2164 .assign_sub => try assignOp(gz, scope, statement, .sub), 2165 .assign_sub_wrap => try assignOp(gz, scope, statement, .subwrap), 2166 .assign_mod => try assignOp(gz, scope, statement, .mod_rem), 2167 .assign_add => try assignOp(gz, scope, statement, .add), 2168 .assign_add_wrap => try assignOp(gz, scope, statement, .addwrap), 2169 .assign_mul => try assignOp(gz, scope, statement, .mul), 2170 .assign_mul_wrap => try assignOp(gz, scope, statement, .mulwrap), 2171 2172 else => noreturn_src_node = try unusedResultExpr(gz, scope, statement), 2173 // zig fmt: on 2174 } 2175 } 2176 2177 try gz.addDbgBlockEnd(); 2178 2179 try genDefers(gz, parent_scope, scope, .normal_only); 2180 try checkUsed(gz, parent_scope, scope); 2181 } 2182 2183 fn unusedResultDeferExpr(gz: *GenZir, defer_scope: *Scope.Defer, expr_scope: *Scope, expr_node: Ast.Node.Index) InnerError!void { 2184 const astgen = gz.astgen; 2185 const prev_offset = astgen.source_offset; 2186 const prev_line = astgen.source_line; 2187 const prev_column = astgen.source_column; 2188 defer { 2189 astgen.source_offset = prev_offset; 2190 astgen.source_line = prev_line; 2191 astgen.source_column = prev_column; 2192 } 2193 astgen.source_offset = defer_scope.source_offset; 2194 astgen.source_line = defer_scope.source_line; 2195 astgen.source_column = defer_scope.source_column; 2196 _ = try unusedResultExpr(gz, expr_scope, expr_node); 2197 } 2198 2199 /// Returns AST source node of the thing that is noreturn if the statement is 2200 /// definitely `noreturn`. Otherwise returns 0. 2201 fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) InnerError!Ast.Node.Index { 2202 try emitDbgNode(gz, statement); 2203 // We need to emit an error if the result is not `noreturn` or `void`, but 2204 // we want to avoid adding the ZIR instruction if possible for performance. 2205 const maybe_unused_result = try expr(gz, scope, .none, statement); 2206 var noreturn_src_node: Ast.Node.Index = 0; 2207 const elide_check = if (refToIndex(maybe_unused_result)) |inst| b: { 2208 // Note that this array becomes invalid after appending more items to it 2209 // in the above while loop. 2210 const zir_tags = gz.astgen.instructions.items(.tag); 2211 switch (zir_tags[inst]) { 2212 // For some instructions, modify the zir data 2213 // so we can avoid a separate ensure_result_used instruction. 2214 .call => { 2215 const extra_index = gz.astgen.instructions.items(.data)[inst].pl_node.payload_index; 2216 const slot = &gz.astgen.extra.items[extra_index]; 2217 var flags = @bitCast(Zir.Inst.Call.Flags, slot.*); 2218 flags.ensure_result_used = true; 2219 slot.* = @bitCast(u32, flags); 2220 break :b true; 2221 }, 2222 .builtin_call => { 2223 const extra_index = gz.astgen.instructions.items(.data)[inst].pl_node.payload_index; 2224 const slot = &gz.astgen.extra.items[extra_index]; 2225 var flags = @bitCast(Zir.Inst.BuiltinCall.Flags, slot.*); 2226 flags.ensure_result_used = true; 2227 slot.* = @bitCast(u32, flags); 2228 break :b true; 2229 }, 2230 2231 // ZIR instructions that might be a type other than `noreturn` or `void`. 2232 .add, 2233 .addwrap, 2234 .add_sat, 2235 .param, 2236 .param_comptime, 2237 .param_anytype, 2238 .param_anytype_comptime, 2239 .alloc, 2240 .alloc_mut, 2241 .alloc_comptime_mut, 2242 .alloc_inferred, 2243 .alloc_inferred_mut, 2244 .alloc_inferred_comptime, 2245 .alloc_inferred_comptime_mut, 2246 .make_ptr_const, 2247 .array_cat, 2248 .array_mul, 2249 .array_type, 2250 .array_type_sentinel, 2251 .elem_type_index, 2252 .vector_type, 2253 .indexable_ptr_len, 2254 .anyframe_type, 2255 .as, 2256 .as_node, 2257 .bit_and, 2258 .bitcast, 2259 .bit_or, 2260 .block, 2261 .block_inline, 2262 .suspend_block, 2263 .loop, 2264 .bool_br_and, 2265 .bool_br_or, 2266 .bool_not, 2267 .cmp_lt, 2268 .cmp_lte, 2269 .cmp_eq, 2270 .cmp_gte, 2271 .cmp_gt, 2272 .cmp_neq, 2273 .coerce_result_ptr, 2274 .decl_ref, 2275 .decl_val, 2276 .load, 2277 .div, 2278 .elem_ptr, 2279 .elem_val, 2280 .elem_ptr_node, 2281 .elem_ptr_imm, 2282 .elem_val_node, 2283 .field_ptr, 2284 .field_val, 2285 .field_call_bind, 2286 .field_ptr_named, 2287 .field_val_named, 2288 .func, 2289 .func_inferred, 2290 .func_fancy, 2291 .int, 2292 .int_big, 2293 .float, 2294 .float128, 2295 .int_type, 2296 .is_non_null, 2297 .is_non_null_ptr, 2298 .is_non_err, 2299 .is_non_err_ptr, 2300 .mod_rem, 2301 .mul, 2302 .mulwrap, 2303 .mul_sat, 2304 .ref, 2305 .shl, 2306 .shl_sat, 2307 .shr, 2308 .str, 2309 .sub, 2310 .subwrap, 2311 .sub_sat, 2312 .negate, 2313 .negate_wrap, 2314 .typeof, 2315 .typeof_builtin, 2316 .xor, 2317 .optional_type, 2318 .optional_payload_safe, 2319 .optional_payload_unsafe, 2320 .optional_payload_safe_ptr, 2321 .optional_payload_unsafe_ptr, 2322 .err_union_payload_safe, 2323 .err_union_payload_unsafe, 2324 .err_union_payload_safe_ptr, 2325 .err_union_payload_unsafe_ptr, 2326 .err_union_code, 2327 .err_union_code_ptr, 2328 .ptr_type, 2329 .ptr_type_simple, 2330 .enum_literal, 2331 .merge_error_sets, 2332 .error_union_type, 2333 .bit_not, 2334 .error_value, 2335 .error_to_int, 2336 .int_to_error, 2337 .slice_start, 2338 .slice_end, 2339 .slice_sentinel, 2340 .import, 2341 .switch_block, 2342 .switch_cond, 2343 .switch_cond_ref, 2344 .switch_capture, 2345 .switch_capture_ref, 2346 .switch_capture_multi, 2347 .switch_capture_multi_ref, 2348 .struct_init_empty, 2349 .struct_init, 2350 .struct_init_ref, 2351 .struct_init_anon, 2352 .struct_init_anon_ref, 2353 .array_init, 2354 .array_init_anon, 2355 .array_init_ref, 2356 .array_init_anon_ref, 2357 .union_init, 2358 .field_type, 2359 .field_type_ref, 2360 .error_set_decl, 2361 .error_set_decl_anon, 2362 .error_set_decl_func, 2363 .int_to_enum, 2364 .enum_to_int, 2365 .type_info, 2366 .size_of, 2367 .bit_size_of, 2368 .log2_int_type, 2369 .typeof_log2_int_type, 2370 .ptr_to_int, 2371 .align_of, 2372 .bool_to_int, 2373 .embed_file, 2374 .error_name, 2375 .sqrt, 2376 .sin, 2377 .cos, 2378 .tan, 2379 .exp, 2380 .exp2, 2381 .log, 2382 .log2, 2383 .log10, 2384 .fabs, 2385 .floor, 2386 .ceil, 2387 .trunc, 2388 .round, 2389 .tag_name, 2390 .reify, 2391 .type_name, 2392 .frame_type, 2393 .frame_size, 2394 .float_to_int, 2395 .int_to_float, 2396 .int_to_ptr, 2397 .float_cast, 2398 .int_cast, 2399 .ptr_cast, 2400 .truncate, 2401 .align_cast, 2402 .has_decl, 2403 .has_field, 2404 .clz, 2405 .ctz, 2406 .pop_count, 2407 .byte_swap, 2408 .bit_reverse, 2409 .div_exact, 2410 .div_floor, 2411 .div_trunc, 2412 .mod, 2413 .rem, 2414 .shl_exact, 2415 .shr_exact, 2416 .bit_offset_of, 2417 .offset_of, 2418 .cmpxchg_strong, 2419 .cmpxchg_weak, 2420 .splat, 2421 .reduce, 2422 .shuffle, 2423 .select, 2424 .atomic_load, 2425 .atomic_rmw, 2426 .mul_add, 2427 .field_parent_ptr, 2428 .maximum, 2429 .minimum, 2430 .builtin_async_call, 2431 .c_import, 2432 .@"resume", 2433 .@"await", 2434 .ret_err_value_code, 2435 .closure_get, 2436 .array_base_ptr, 2437 .field_base_ptr, 2438 .param_type, 2439 .ret_ptr, 2440 .ret_type, 2441 .@"try", 2442 .try_ptr, 2443 //.try_inline, 2444 //.try_ptr_inline, 2445 => break :b false, 2446 2447 .extended => switch (gz.astgen.instructions.items(.data)[inst].extended.opcode) { 2448 .breakpoint, 2449 .fence, 2450 .set_align_stack, 2451 .set_float_mode, 2452 => break :b true, 2453 else => break :b false, 2454 }, 2455 2456 // ZIR instructions that are always `noreturn`. 2457 .@"break", 2458 .break_inline, 2459 .condbr, 2460 .condbr_inline, 2461 .compile_error, 2462 .ret_node, 2463 .ret_load, 2464 .ret_tok, 2465 .ret_err_value, 2466 .@"unreachable", 2467 .repeat, 2468 .repeat_inline, 2469 .panic, 2470 => { 2471 noreturn_src_node = statement; 2472 break :b true; 2473 }, 2474 2475 // ZIR instructions that are always `void`. 2476 .dbg_stmt, 2477 .dbg_var_ptr, 2478 .dbg_var_val, 2479 .dbg_block_begin, 2480 .dbg_block_end, 2481 .ensure_result_used, 2482 .ensure_result_non_error, 2483 .@"export", 2484 .export_value, 2485 .set_eval_branch_quota, 2486 .ensure_err_payload_void, 2487 .atomic_store, 2488 .store, 2489 .store_node, 2490 .store_to_block_ptr, 2491 .store_to_inferred_ptr, 2492 .resolve_inferred_alloc, 2493 .validate_struct_init, 2494 .validate_struct_init_comptime, 2495 .validate_array_init, 2496 .validate_array_init_comptime, 2497 .set_cold, 2498 .set_runtime_safety, 2499 .closure_capture, 2500 .memcpy, 2501 .memset, 2502 .validate_array_init_ty, 2503 .validate_struct_init_ty, 2504 .validate_deref, 2505 => break :b true, 2506 } 2507 } else switch (maybe_unused_result) { 2508 .none => unreachable, 2509 2510 .unreachable_value => b: { 2511 noreturn_src_node = statement; 2512 break :b true; 2513 }, 2514 2515 .void_value => true, 2516 2517 else => false, 2518 }; 2519 if (!elide_check) { 2520 _ = try gz.addUnNode(.ensure_result_used, maybe_unused_result, statement); 2521 } 2522 return noreturn_src_node; 2523 } 2524 2525 fn countDefers(astgen: *AstGen, outer_scope: *Scope, inner_scope: *Scope) struct { 2526 have_any: bool, 2527 have_normal: bool, 2528 have_err: bool, 2529 need_err_code: bool, 2530 } { 2531 const tree = astgen.tree; 2532 const node_datas = tree.nodes.items(.data); 2533 2534 var have_normal = false; 2535 var have_err = false; 2536 var need_err_code = false; 2537 var scope = inner_scope; 2538 while (scope != outer_scope) { 2539 switch (scope.tag) { 2540 .gen_zir => scope = scope.cast(GenZir).?.parent, 2541 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 2542 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 2543 .defer_normal => { 2544 const defer_scope = scope.cast(Scope.Defer).?; 2545 scope = defer_scope.parent; 2546 2547 have_normal = true; 2548 }, 2549 .defer_error => { 2550 const defer_scope = scope.cast(Scope.Defer).?; 2551 scope = defer_scope.parent; 2552 2553 have_err = true; 2554 2555 const have_err_payload = node_datas[defer_scope.defer_node].lhs != 0; 2556 need_err_code = need_err_code or have_err_payload; 2557 }, 2558 .namespace => unreachable, 2559 .top => unreachable, 2560 } 2561 } 2562 return .{ 2563 .have_any = have_normal or have_err, 2564 .have_normal = have_normal, 2565 .have_err = have_err, 2566 .need_err_code = need_err_code, 2567 }; 2568 } 2569 2570 const DefersToEmit = union(enum) { 2571 both: Zir.Inst.Ref, // err code 2572 both_sans_err, 2573 normal_only, 2574 }; 2575 2576 fn genDefers( 2577 gz: *GenZir, 2578 outer_scope: *Scope, 2579 inner_scope: *Scope, 2580 which_ones: DefersToEmit, 2581 ) InnerError!void { 2582 const astgen = gz.astgen; 2583 const tree = astgen.tree; 2584 const node_datas = tree.nodes.items(.data); 2585 2586 var scope = inner_scope; 2587 while (scope != outer_scope) { 2588 switch (scope.tag) { 2589 .gen_zir => scope = scope.cast(GenZir).?.parent, 2590 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 2591 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 2592 .defer_normal => { 2593 const defer_scope = scope.cast(Scope.Defer).?; 2594 scope = defer_scope.parent; 2595 const expr_node = node_datas[defer_scope.defer_node].rhs; 2596 const prev_in_defer = gz.in_defer; 2597 gz.in_defer = true; 2598 defer gz.in_defer = prev_in_defer; 2599 try unusedResultDeferExpr(gz, defer_scope, defer_scope.parent, expr_node); 2600 }, 2601 .defer_error => { 2602 const defer_scope = scope.cast(Scope.Defer).?; 2603 scope = defer_scope.parent; 2604 switch (which_ones) { 2605 .both_sans_err => { 2606 const expr_node = node_datas[defer_scope.defer_node].rhs; 2607 const prev_in_defer = gz.in_defer; 2608 gz.in_defer = true; 2609 defer gz.in_defer = prev_in_defer; 2610 try unusedResultDeferExpr(gz, defer_scope, defer_scope.parent, expr_node); 2611 }, 2612 .both => |err_code| { 2613 const expr_node = node_datas[defer_scope.defer_node].rhs; 2614 const payload_token = node_datas[defer_scope.defer_node].lhs; 2615 const prev_in_defer = gz.in_defer; 2616 gz.in_defer = true; 2617 defer gz.in_defer = prev_in_defer; 2618 var local_val_scope: Scope.LocalVal = undefined; 2619 try gz.addDbgBlockBegin(); 2620 const sub_scope = if (payload_token == 0) defer_scope.parent else blk: { 2621 const ident_name = try astgen.identAsString(payload_token); 2622 local_val_scope = .{ 2623 .parent = defer_scope.parent, 2624 .gen_zir = gz, 2625 .name = ident_name, 2626 .inst = err_code, 2627 .token_src = payload_token, 2628 .id_cat = .@"capture", 2629 }; 2630 try gz.addDbgVar(.dbg_var_val, ident_name, err_code); 2631 break :blk &local_val_scope.base; 2632 }; 2633 try unusedResultDeferExpr(gz, defer_scope, sub_scope, expr_node); 2634 try gz.addDbgBlockEnd(); 2635 }, 2636 .normal_only => continue, 2637 } 2638 }, 2639 .namespace => unreachable, 2640 .top => unreachable, 2641 } 2642 } 2643 } 2644 2645 fn checkUsed( 2646 gz: *GenZir, 2647 outer_scope: *Scope, 2648 inner_scope: *Scope, 2649 ) InnerError!void { 2650 const astgen = gz.astgen; 2651 2652 var scope = inner_scope; 2653 while (scope != outer_scope) { 2654 switch (scope.tag) { 2655 .gen_zir => scope = scope.cast(GenZir).?.parent, 2656 .local_val => { 2657 const s = scope.cast(Scope.LocalVal).?; 2658 if (!s.used) { 2659 try astgen.appendErrorTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)}); 2660 } 2661 scope = s.parent; 2662 }, 2663 .local_ptr => { 2664 const s = scope.cast(Scope.LocalPtr).?; 2665 if (!s.used) { 2666 try astgen.appendErrorTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)}); 2667 } 2668 scope = s.parent; 2669 }, 2670 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, 2671 .namespace => unreachable, 2672 .top => unreachable, 2673 } 2674 } 2675 } 2676 2677 fn makeDeferScope( 2678 astgen: *AstGen, 2679 scope: *Scope, 2680 node: Ast.Node.Index, 2681 block_arena: Allocator, 2682 scope_tag: Scope.Tag, 2683 ) InnerError!*Scope { 2684 const tree = astgen.tree; 2685 const node_datas = tree.nodes.items(.data); 2686 const expr_node = node_datas[node].rhs; 2687 const token_starts = tree.tokens.items(.start); 2688 const node_start = token_starts[tree.firstToken(expr_node)]; 2689 const defer_scope = try block_arena.create(Scope.Defer); 2690 astgen.advanceSourceCursor(node_start); 2691 2692 defer_scope.* = .{ 2693 .base = .{ .tag = scope_tag }, 2694 .parent = scope, 2695 .defer_node = node, 2696 .source_offset = astgen.source_offset, 2697 .source_line = astgen.source_line, 2698 .source_column = astgen.source_column, 2699 }; 2700 return &defer_scope.base; 2701 } 2702 2703 fn varDecl( 2704 gz: *GenZir, 2705 scope: *Scope, 2706 node: Ast.Node.Index, 2707 block_arena: Allocator, 2708 var_decl: Ast.full.VarDecl, 2709 ) InnerError!*Scope { 2710 try emitDbgNode(gz, node); 2711 const astgen = gz.astgen; 2712 const tree = astgen.tree; 2713 const token_tags = tree.tokens.items(.tag); 2714 const main_tokens = tree.nodes.items(.main_token); 2715 2716 const name_token = var_decl.ast.mut_token + 1; 2717 const ident_name_raw = tree.tokenSlice(name_token); 2718 if (mem.eql(u8, ident_name_raw, "_")) { 2719 return astgen.failTok(name_token, "'_' used as an identifier without @\"_\" syntax", .{}); 2720 } 2721 const ident_name = try astgen.identAsString(name_token); 2722 2723 try astgen.detectLocalShadowing(scope, ident_name, name_token, ident_name_raw); 2724 2725 if (var_decl.ast.init_node == 0) { 2726 return astgen.failNode(node, "variables must be initialized", .{}); 2727 } 2728 2729 if (var_decl.ast.addrspace_node != 0) { 2730 return astgen.failTok(main_tokens[var_decl.ast.addrspace_node], "cannot set address space of local variable '{s}'", .{ident_name_raw}); 2731 } 2732 2733 if (var_decl.ast.section_node != 0) { 2734 return astgen.failTok(main_tokens[var_decl.ast.section_node], "cannot set section of local variable '{s}'", .{ident_name_raw}); 2735 } 2736 2737 const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node != 0) 2738 try expr(gz, scope, align_rl, var_decl.ast.align_node) 2739 else 2740 .none; 2741 2742 switch (token_tags[var_decl.ast.mut_token]) { 2743 .keyword_const => { 2744 if (var_decl.comptime_token) |comptime_token| { 2745 try astgen.appendErrorTok(comptime_token, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{}); 2746 } 2747 2748 // Depending on the type of AST the initialization expression is, we may need an lvalue 2749 // or an rvalue as a result location. If it is an rvalue, we can use the instruction as 2750 // the variable, no memory location needed. 2751 const type_node = var_decl.ast.type_node; 2752 if (align_inst == .none and 2753 !nodeMayNeedMemoryLocation(tree, var_decl.ast.init_node, type_node != 0)) 2754 { 2755 const result_loc: ResultLoc = if (type_node != 0) .{ 2756 .ty = try typeExpr(gz, scope, type_node), 2757 } else .none; 2758 const prev_anon_name_strategy = gz.anon_name_strategy; 2759 gz.anon_name_strategy = .dbg_var; 2760 const init_inst = try reachableExpr(gz, scope, result_loc, var_decl.ast.init_node, node); 2761 gz.anon_name_strategy = prev_anon_name_strategy; 2762 2763 try gz.addDbgVar(.dbg_var_val, ident_name, init_inst); 2764 2765 const sub_scope = try block_arena.create(Scope.LocalVal); 2766 sub_scope.* = .{ 2767 .parent = scope, 2768 .gen_zir = gz, 2769 .name = ident_name, 2770 .inst = init_inst, 2771 .token_src = name_token, 2772 .id_cat = .@"local constant", 2773 }; 2774 return &sub_scope.base; 2775 } 2776 2777 const is_comptime = gz.force_comptime or 2778 tree.nodes.items(.tag)[var_decl.ast.init_node] == .@"comptime"; 2779 2780 // Detect whether the initialization expression actually uses the 2781 // result location pointer. 2782 var init_scope = gz.makeSubBlock(scope); 2783 // we may add more instructions to gz before stacking init_scope 2784 init_scope.instructions_top = GenZir.unstacked_top; 2785 init_scope.anon_name_strategy = .dbg_var; 2786 defer init_scope.unstack(); 2787 2788 var resolve_inferred_alloc: Zir.Inst.Ref = .none; 2789 var opt_type_inst: Zir.Inst.Ref = .none; 2790 if (type_node != 0) { 2791 const type_inst = try typeExpr(gz, &init_scope.base, type_node); 2792 opt_type_inst = type_inst; 2793 if (align_inst == .none) { 2794 init_scope.instructions_top = gz.instructions.items.len; 2795 init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node); 2796 } else { 2797 init_scope.rl_ptr = try gz.addAllocExtended(.{ 2798 .node = node, 2799 .type_inst = type_inst, 2800 .align_inst = align_inst, 2801 .is_const = true, 2802 .is_comptime = is_comptime, 2803 }); 2804 init_scope.instructions_top = gz.instructions.items.len; 2805 } 2806 init_scope.rl_ty_inst = type_inst; 2807 } else { 2808 const alloc = if (align_inst == .none) alloc: { 2809 init_scope.instructions_top = gz.instructions.items.len; 2810 const tag: Zir.Inst.Tag = if (is_comptime) 2811 .alloc_inferred_comptime 2812 else 2813 .alloc_inferred; 2814 break :alloc try init_scope.addNode(tag, node); 2815 } else alloc: { 2816 const ref = try gz.addAllocExtended(.{ 2817 .node = node, 2818 .type_inst = .none, 2819 .align_inst = align_inst, 2820 .is_const = true, 2821 .is_comptime = is_comptime, 2822 }); 2823 init_scope.instructions_top = gz.instructions.items.len; 2824 break :alloc ref; 2825 }; 2826 resolve_inferred_alloc = alloc; 2827 init_scope.rl_ptr = alloc; 2828 init_scope.rl_ty_inst = .none; 2829 } 2830 const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope }; 2831 const init_inst = try reachableExpr(&init_scope, &init_scope.base, init_result_loc, var_decl.ast.init_node, node); 2832 2833 const zir_tags = astgen.instructions.items(.tag); 2834 const zir_datas = astgen.instructions.items(.data); 2835 2836 if (align_inst == .none and init_scope.rvalue_rl_count == 1) { 2837 // Result location pointer not used. We don't need an alloc for this 2838 // const local, and type inference becomes trivial. 2839 // Implicitly move the init_scope instructions into the parent scope, 2840 // then elide the alloc instruction and the store_to_block_ptr instruction. 2841 var src = init_scope.instructions_top; 2842 var dst = src; 2843 init_scope.instructions_top = GenZir.unstacked_top; 2844 while (src < gz.instructions.items.len) : (src += 1) { 2845 const src_inst = gz.instructions.items[src]; 2846 if (indexToRef(src_inst) == init_scope.rl_ptr) continue; 2847 if (zir_tags[src_inst] == .store_to_block_ptr) { 2848 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) continue; 2849 } 2850 gz.instructions.items[dst] = src_inst; 2851 dst += 1; 2852 } 2853 gz.instructions.items.len = dst; 2854 2855 // In case the result location did not do the coercion 2856 // for us so we must do it here. 2857 const coerced_init = if (opt_type_inst != .none) 2858 try gz.addBin(.as, opt_type_inst, init_inst) 2859 else 2860 init_inst; 2861 2862 try gz.addDbgVar(.dbg_var_val, ident_name, coerced_init); 2863 2864 const sub_scope = try block_arena.create(Scope.LocalVal); 2865 sub_scope.* = .{ 2866 .parent = scope, 2867 .gen_zir = gz, 2868 .name = ident_name, 2869 .inst = coerced_init, 2870 .token_src = name_token, 2871 .id_cat = .@"local constant", 2872 }; 2873 return &sub_scope.base; 2874 } 2875 // The initialization expression took advantage of the result location 2876 // of the const local. In this case we will create an alloc and a LocalPtr for it. 2877 // Implicitly move the init_scope instructions into the parent scope, then swap 2878 // store_to_block_ptr for store_to_inferred_ptr. 2879 2880 var src = init_scope.instructions_top; 2881 init_scope.instructions_top = GenZir.unstacked_top; 2882 while (src < gz.instructions.items.len) : (src += 1) { 2883 const src_inst = gz.instructions.items[src]; 2884 if (zir_tags[src_inst] == .store_to_block_ptr) { 2885 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) { 2886 if (type_node != 0) { 2887 zir_tags[src_inst] = .store; 2888 } else { 2889 zir_tags[src_inst] = .store_to_inferred_ptr; 2890 } 2891 } 2892 } 2893 } 2894 if (resolve_inferred_alloc != .none) { 2895 _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node); 2896 } 2897 const const_ptr = try gz.addUnNode(.make_ptr_const, init_scope.rl_ptr, node); 2898 2899 try gz.addDbgVar(.dbg_var_ptr, ident_name, const_ptr); 2900 2901 const sub_scope = try block_arena.create(Scope.LocalPtr); 2902 sub_scope.* = .{ 2903 .parent = scope, 2904 .gen_zir = gz, 2905 .name = ident_name, 2906 .ptr = const_ptr, 2907 .token_src = name_token, 2908 .maybe_comptime = true, 2909 .id_cat = .@"local constant", 2910 }; 2911 return &sub_scope.base; 2912 }, 2913 .keyword_var => { 2914 const old_rl_ty_inst = gz.rl_ty_inst; 2915 defer gz.rl_ty_inst = old_rl_ty_inst; 2916 2917 const is_comptime = var_decl.comptime_token != null or gz.force_comptime; 2918 var resolve_inferred_alloc: Zir.Inst.Ref = .none; 2919 const var_data: struct { 2920 result_loc: ResultLoc, 2921 alloc: Zir.Inst.Ref, 2922 } = if (var_decl.ast.type_node != 0) a: { 2923 const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node); 2924 const alloc = alloc: { 2925 if (align_inst == .none) { 2926 const tag: Zir.Inst.Tag = if (is_comptime) 2927 .alloc_comptime_mut 2928 else 2929 .alloc_mut; 2930 break :alloc try gz.addUnNode(tag, type_inst, node); 2931 } else { 2932 break :alloc try gz.addAllocExtended(.{ 2933 .node = node, 2934 .type_inst = type_inst, 2935 .align_inst = align_inst, 2936 .is_const = false, 2937 .is_comptime = is_comptime, 2938 }); 2939 } 2940 }; 2941 gz.rl_ty_inst = type_inst; 2942 break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } }; 2943 } else a: { 2944 const alloc = alloc: { 2945 if (align_inst == .none) { 2946 const tag: Zir.Inst.Tag = if (is_comptime) 2947 .alloc_inferred_comptime_mut 2948 else 2949 .alloc_inferred_mut; 2950 break :alloc try gz.addNode(tag, node); 2951 } else { 2952 break :alloc try gz.addAllocExtended(.{ 2953 .node = node, 2954 .type_inst = .none, 2955 .align_inst = align_inst, 2956 .is_const = false, 2957 .is_comptime = is_comptime, 2958 }); 2959 } 2960 }; 2961 gz.rl_ty_inst = .none; 2962 resolve_inferred_alloc = alloc; 2963 break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } }; 2964 }; 2965 const prev_anon_name_strategy = gz.anon_name_strategy; 2966 gz.anon_name_strategy = .dbg_var; 2967 _ = try reachableExprComptime(gz, scope, var_data.result_loc, var_decl.ast.init_node, node, is_comptime); 2968 gz.anon_name_strategy = prev_anon_name_strategy; 2969 if (resolve_inferred_alloc != .none) { 2970 _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node); 2971 } 2972 2973 try gz.addDbgVar(.dbg_var_ptr, ident_name, var_data.alloc); 2974 2975 const sub_scope = try block_arena.create(Scope.LocalPtr); 2976 sub_scope.* = .{ 2977 .parent = scope, 2978 .gen_zir = gz, 2979 .name = ident_name, 2980 .ptr = var_data.alloc, 2981 .token_src = name_token, 2982 .maybe_comptime = is_comptime, 2983 .id_cat = .@"local variable", 2984 }; 2985 return &sub_scope.base; 2986 }, 2987 else => unreachable, 2988 } 2989 } 2990 2991 fn emitDbgNode(gz: *GenZir, node: Ast.Node.Index) !void { 2992 // The instruction emitted here is for debugging runtime code. 2993 // If the current block will be evaluated only during semantic analysis 2994 // then no dbg_stmt ZIR instruction is needed. 2995 if (gz.force_comptime) return; 2996 2997 const astgen = gz.astgen; 2998 astgen.advanceSourceCursorToNode(node); 2999 const line = astgen.source_line - gz.decl_line; 3000 const column = astgen.source_column; 3001 3002 _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{ 3003 .dbg_stmt = .{ 3004 .line = line, 3005 .column = column, 3006 }, 3007 } }); 3008 } 3009 3010 fn assign(gz: *GenZir, scope: *Scope, infix_node: Ast.Node.Index) InnerError!void { 3011 try emitDbgNode(gz, infix_node); 3012 const astgen = gz.astgen; 3013 const tree = astgen.tree; 3014 const node_datas = tree.nodes.items(.data); 3015 const main_tokens = tree.nodes.items(.main_token); 3016 const node_tags = tree.nodes.items(.tag); 3017 3018 const lhs = node_datas[infix_node].lhs; 3019 const rhs = node_datas[infix_node].rhs; 3020 if (node_tags[lhs] == .identifier) { 3021 // This intentionally does not support `@"_"` syntax. 3022 const ident_name = tree.tokenSlice(main_tokens[lhs]); 3023 if (mem.eql(u8, ident_name, "_")) { 3024 _ = try expr(gz, scope, .discard, rhs); 3025 return; 3026 } 3027 } 3028 const lvalue = try lvalExpr(gz, scope, lhs); 3029 _ = try expr(gz, scope, .{ .ptr = lvalue }, rhs); 3030 } 3031 3032 fn assignOp( 3033 gz: *GenZir, 3034 scope: *Scope, 3035 infix_node: Ast.Node.Index, 3036 op_inst_tag: Zir.Inst.Tag, 3037 ) InnerError!void { 3038 try emitDbgNode(gz, infix_node); 3039 const astgen = gz.astgen; 3040 const tree = astgen.tree; 3041 const node_datas = tree.nodes.items(.data); 3042 3043 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs); 3044 const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node); 3045 const lhs_type = try gz.addUnNode(.typeof, lhs, infix_node); 3046 const rhs = try expr(gz, scope, .{ .coerced_ty = lhs_type }, node_datas[infix_node].rhs); 3047 3048 const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{ 3049 .lhs = lhs, 3050 .rhs = rhs, 3051 }); 3052 _ = try gz.addBin(.store, lhs_ptr, result); 3053 } 3054 3055 fn assignShift( 3056 gz: *GenZir, 3057 scope: *Scope, 3058 infix_node: Ast.Node.Index, 3059 op_inst_tag: Zir.Inst.Tag, 3060 ) InnerError!void { 3061 try emitDbgNode(gz, infix_node); 3062 const astgen = gz.astgen; 3063 const tree = astgen.tree; 3064 const node_datas = tree.nodes.items(.data); 3065 3066 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs); 3067 const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node); 3068 const rhs_type = try gz.addUnNode(.typeof_log2_int_type, lhs, infix_node); 3069 const rhs = try expr(gz, scope, .{ .ty = rhs_type }, node_datas[infix_node].rhs); 3070 3071 const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{ 3072 .lhs = lhs, 3073 .rhs = rhs, 3074 }); 3075 _ = try gz.addBin(.store, lhs_ptr, result); 3076 } 3077 3078 fn assignShiftSat(gz: *GenZir, scope: *Scope, infix_node: Ast.Node.Index) InnerError!void { 3079 try emitDbgNode(gz, infix_node); 3080 const astgen = gz.astgen; 3081 const tree = astgen.tree; 3082 const node_datas = tree.nodes.items(.data); 3083 3084 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs); 3085 const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node); 3086 // Saturating shift-left allows any integer type for both the LHS and RHS. 3087 const rhs = try expr(gz, scope, .none, node_datas[infix_node].rhs); 3088 3089 const result = try gz.addPlNode(.shl_sat, infix_node, Zir.Inst.Bin{ 3090 .lhs = lhs, 3091 .rhs = rhs, 3092 }); 3093 _ = try gz.addBin(.store, lhs_ptr, result); 3094 } 3095 3096 fn ptrType( 3097 gz: *GenZir, 3098 scope: *Scope, 3099 rl: ResultLoc, 3100 node: Ast.Node.Index, 3101 ptr_info: Ast.full.PtrType, 3102 ) InnerError!Zir.Inst.Ref { 3103 const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type); 3104 3105 const simple = ptr_info.ast.align_node == 0 and 3106 ptr_info.ast.addrspace_node == 0 and 3107 ptr_info.ast.sentinel == 0 and 3108 ptr_info.ast.bit_range_start == 0; 3109 3110 if (simple) { 3111 const result = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ 3112 .ptr_type_simple = .{ 3113 .is_allowzero = ptr_info.allowzero_token != null, 3114 .is_mutable = ptr_info.const_token == null, 3115 .is_volatile = ptr_info.volatile_token != null, 3116 .size = ptr_info.size, 3117 .elem_type = elem_type, 3118 }, 3119 } }); 3120 return rvalue(gz, rl, result, node); 3121 } 3122 3123 var sentinel_ref: Zir.Inst.Ref = .none; 3124 var align_ref: Zir.Inst.Ref = .none; 3125 var addrspace_ref: Zir.Inst.Ref = .none; 3126 var bit_start_ref: Zir.Inst.Ref = .none; 3127 var bit_end_ref: Zir.Inst.Ref = .none; 3128 var trailing_count: u32 = 0; 3129 3130 if (ptr_info.ast.sentinel != 0) { 3131 sentinel_ref = try expr(gz, scope, .{ .ty = elem_type }, ptr_info.ast.sentinel); 3132 trailing_count += 1; 3133 } 3134 if (ptr_info.ast.align_node != 0) { 3135 align_ref = try expr(gz, scope, coerced_align_rl, ptr_info.ast.align_node); 3136 trailing_count += 1; 3137 } 3138 if (ptr_info.ast.addrspace_node != 0) { 3139 addrspace_ref = try expr(gz, scope, .{ .ty = .address_space_type }, ptr_info.ast.addrspace_node); 3140 trailing_count += 1; 3141 } 3142 if (ptr_info.ast.bit_range_start != 0) { 3143 assert(ptr_info.ast.bit_range_end != 0); 3144 bit_start_ref = try expr(gz, scope, .{ .coerced_ty = .u16_type }, ptr_info.ast.bit_range_start); 3145 bit_end_ref = try expr(gz, scope, .{ .coerced_ty = .u16_type }, ptr_info.ast.bit_range_end); 3146 trailing_count += 2; 3147 } 3148 3149 const gpa = gz.astgen.gpa; 3150 try gz.instructions.ensureUnusedCapacity(gpa, 1); 3151 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 3152 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.PtrType).Struct.fields.len + 3153 trailing_count); 3154 3155 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.PtrType{ .elem_type = elem_type }); 3156 if (sentinel_ref != .none) { 3157 gz.astgen.extra.appendAssumeCapacity(@enumToInt(sentinel_ref)); 3158 } 3159 if (align_ref != .none) { 3160 gz.astgen.extra.appendAssumeCapacity(@enumToInt(align_ref)); 3161 } 3162 if (addrspace_ref != .none) { 3163 gz.astgen.extra.appendAssumeCapacity(@enumToInt(addrspace_ref)); 3164 } 3165 if (bit_start_ref != .none) { 3166 gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_start_ref)); 3167 gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_end_ref)); 3168 } 3169 3170 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 3171 const result = indexToRef(new_index); 3172 gz.astgen.instructions.appendAssumeCapacity(.{ .tag = .ptr_type, .data = .{ 3173 .ptr_type = .{ 3174 .flags = .{ 3175 .is_allowzero = ptr_info.allowzero_token != null, 3176 .is_mutable = ptr_info.const_token == null, 3177 .is_volatile = ptr_info.volatile_token != null, 3178 .has_sentinel = sentinel_ref != .none, 3179 .has_align = align_ref != .none, 3180 .has_addrspace = addrspace_ref != .none, 3181 .has_bit_range = bit_start_ref != .none, 3182 }, 3183 .size = ptr_info.size, 3184 .payload_index = payload_index, 3185 }, 3186 } }); 3187 gz.instructions.appendAssumeCapacity(new_index); 3188 3189 return rvalue(gz, rl, result, node); 3190 } 3191 3192 fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) !Zir.Inst.Ref { 3193 const astgen = gz.astgen; 3194 const tree = astgen.tree; 3195 const node_datas = tree.nodes.items(.data); 3196 const node_tags = tree.nodes.items(.tag); 3197 const main_tokens = tree.nodes.items(.main_token); 3198 3199 const len_node = node_datas[node].lhs; 3200 if (node_tags[len_node] == .identifier and 3201 mem.eql(u8, tree.tokenSlice(main_tokens[len_node]), "_")) 3202 { 3203 return astgen.failNode(len_node, "unable to infer array size", .{}); 3204 } 3205 const len = try expr(gz, scope, .{ .coerced_ty = .usize_type }, len_node); 3206 const elem_type = try typeExpr(gz, scope, node_datas[node].rhs); 3207 3208 const result = try gz.addBin(.array_type, len, elem_type); 3209 return rvalue(gz, rl, result, node); 3210 } 3211 3212 fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) !Zir.Inst.Ref { 3213 const astgen = gz.astgen; 3214 const tree = astgen.tree; 3215 const node_datas = tree.nodes.items(.data); 3216 const node_tags = tree.nodes.items(.tag); 3217 const main_tokens = tree.nodes.items(.main_token); 3218 const extra = tree.extraData(node_datas[node].rhs, Ast.Node.ArrayTypeSentinel); 3219 3220 const len_node = node_datas[node].lhs; 3221 if (node_tags[len_node] == .identifier and 3222 mem.eql(u8, tree.tokenSlice(main_tokens[len_node]), "_")) 3223 { 3224 return astgen.failNode(len_node, "unable to infer array size", .{}); 3225 } 3226 const len = try reachableExpr(gz, scope, .{ .coerced_ty = .usize_type }, len_node, node); 3227 const elem_type = try typeExpr(gz, scope, extra.elem_type); 3228 const sentinel = try reachableExpr(gz, scope, .{ .coerced_ty = elem_type }, extra.sentinel, node); 3229 3230 const result = try gz.addPlNode(.array_type_sentinel, node, Zir.Inst.ArrayTypeSentinel{ 3231 .len = len, 3232 .elem_type = elem_type, 3233 .sentinel = sentinel, 3234 }); 3235 return rvalue(gz, rl, result, node); 3236 } 3237 3238 const WipMembers = struct { 3239 payload: *ArrayListUnmanaged(u32), 3240 payload_top: usize, 3241 decls_start: u32, 3242 decls_end: u32, 3243 field_bits_start: u32, 3244 fields_start: u32, 3245 fields_end: u32, 3246 decl_index: u32 = 0, 3247 field_index: u32 = 0, 3248 3249 const Self = @This(); 3250 /// struct, union, enum, and opaque decls all use same 4 bits per decl 3251 const bits_per_decl = 4; 3252 const decls_per_u32 = 32 / bits_per_decl; 3253 /// struct, union, enum, and opaque decls all have maximum size of 11 u32 slots 3254 /// (4 for src_hash + line + name + value + doc_comment + align + link_section + address_space ) 3255 const max_decl_size = 11; 3256 3257 pub fn init(gpa: Allocator, payload: *ArrayListUnmanaged(u32), decl_count: u32, field_count: u32, comptime bits_per_field: u32, comptime max_field_size: u32) Allocator.Error!Self { 3258 const payload_top = @intCast(u32, payload.items.len); 3259 const decls_start = payload_top + (decl_count + decls_per_u32 - 1) / decls_per_u32; 3260 const field_bits_start = decls_start + decl_count * max_decl_size; 3261 const fields_start = field_bits_start + if (bits_per_field > 0) blk: { 3262 const fields_per_u32 = 32 / bits_per_field; 3263 break :blk (field_count + fields_per_u32 - 1) / fields_per_u32; 3264 } else 0; 3265 const payload_end = fields_start + field_count * max_field_size; 3266 try payload.resize(gpa, payload_end); 3267 return Self{ 3268 .payload = payload, 3269 .payload_top = payload_top, 3270 .decls_start = decls_start, 3271 .field_bits_start = field_bits_start, 3272 .fields_start = fields_start, 3273 .decls_end = decls_start, 3274 .fields_end = fields_start, 3275 }; 3276 } 3277 3278 pub fn nextDecl(self: *Self, is_pub: bool, is_export: bool, has_align: bool, has_section_or_addrspace: bool) void { 3279 const index = self.payload_top + self.decl_index / decls_per_u32; 3280 assert(index < self.decls_start); 3281 const bit_bag: u32 = if (self.decl_index % decls_per_u32 == 0) 0 else self.payload.items[index]; 3282 self.payload.items[index] = (bit_bag >> bits_per_decl) | 3283 (@as(u32, @boolToInt(is_pub)) << 28) | 3284 (@as(u32, @boolToInt(is_export)) << 29) | 3285 (@as(u32, @boolToInt(has_align)) << 30) | 3286 (@as(u32, @boolToInt(has_section_or_addrspace)) << 31); 3287 self.decl_index += 1; 3288 } 3289 3290 pub fn nextField(self: *Self, comptime bits_per_field: u32, bits: [bits_per_field]bool) void { 3291 const fields_per_u32 = 32 / bits_per_field; 3292 const index = self.field_bits_start + self.field_index / fields_per_u32; 3293 assert(index < self.fields_start); 3294 var bit_bag: u32 = if (self.field_index % fields_per_u32 == 0) 0 else self.payload.items[index]; 3295 bit_bag >>= bits_per_field; 3296 comptime var i = 0; 3297 inline while (i < bits_per_field) : (i += 1) { 3298 bit_bag |= @as(u32, @boolToInt(bits[i])) << (32 - bits_per_field + i); 3299 } 3300 self.payload.items[index] = bit_bag; 3301 self.field_index += 1; 3302 } 3303 3304 pub fn appendToDecl(self: *Self, data: u32) void { 3305 assert(self.decls_end < self.field_bits_start); 3306 self.payload.items[self.decls_end] = data; 3307 self.decls_end += 1; 3308 } 3309 3310 pub fn appendToDeclSlice(self: *Self, data: []const u32) void { 3311 assert(self.decls_end + data.len <= self.field_bits_start); 3312 mem.copy(u32, self.payload.items[self.decls_end..], data); 3313 self.decls_end += @intCast(u32, data.len); 3314 } 3315 3316 pub fn appendToField(self: *Self, data: u32) void { 3317 assert(self.fields_end < self.payload.items.len); 3318 self.payload.items[self.fields_end] = data; 3319 self.fields_end += 1; 3320 } 3321 3322 pub fn finishBits(self: *Self, comptime bits_per_field: u32) void { 3323 const empty_decl_slots = decls_per_u32 - (self.decl_index % decls_per_u32); 3324 if (self.decl_index > 0 and empty_decl_slots < decls_per_u32) { 3325 const index = self.payload_top + self.decl_index / decls_per_u32; 3326 self.payload.items[index] >>= @intCast(u5, empty_decl_slots * bits_per_decl); 3327 } 3328 if (bits_per_field > 0) { 3329 const fields_per_u32 = 32 / bits_per_field; 3330 const empty_field_slots = fields_per_u32 - (self.field_index % fields_per_u32); 3331 if (self.field_index > 0 and empty_field_slots < fields_per_u32) { 3332 const index = self.field_bits_start + self.field_index / fields_per_u32; 3333 self.payload.items[index] >>= @intCast(u5, empty_field_slots * bits_per_field); 3334 } 3335 } 3336 } 3337 3338 pub fn declsSlice(self: *Self) []u32 { 3339 return self.payload.items[self.payload_top..self.decls_end]; 3340 } 3341 3342 pub fn fieldsSlice(self: *Self) []u32 { 3343 return self.payload.items[self.field_bits_start..self.fields_end]; 3344 } 3345 3346 pub fn deinit(self: *Self) void { 3347 self.payload.items.len = self.payload_top; 3348 } 3349 }; 3350 3351 fn fnDecl( 3352 astgen: *AstGen, 3353 gz: *GenZir, 3354 scope: *Scope, 3355 wip_members: *WipMembers, 3356 decl_node: Ast.Node.Index, 3357 body_node: Ast.Node.Index, 3358 fn_proto: Ast.full.FnProto, 3359 ) InnerError!void { 3360 const tree = astgen.tree; 3361 const token_tags = tree.tokens.items(.tag); 3362 3363 // missing function name already happened in scanDecls() 3364 const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail; 3365 const fn_name_str_index = try astgen.identAsString(fn_name_token); 3366 3367 // We insert this at the beginning so that its instruction index marks the 3368 // start of the top level declaration. 3369 const block_inst = try gz.makeBlockInst(.block_inline, fn_proto.ast.proto_node); 3370 astgen.advanceSourceCursorToNode(decl_node); 3371 3372 var decl_gz: GenZir = .{ 3373 .force_comptime = true, 3374 .in_defer = false, 3375 .decl_node_index = fn_proto.ast.proto_node, 3376 .decl_line = astgen.source_line, 3377 .parent = scope, 3378 .astgen = astgen, 3379 .instructions = gz.instructions, 3380 .instructions_top = gz.instructions.items.len, 3381 }; 3382 defer decl_gz.unstack(); 3383 3384 var fn_gz: GenZir = .{ 3385 .force_comptime = false, 3386 .in_defer = false, 3387 .decl_node_index = fn_proto.ast.proto_node, 3388 .decl_line = decl_gz.decl_line, 3389 .parent = &decl_gz.base, 3390 .astgen = astgen, 3391 .instructions = gz.instructions, 3392 .instructions_top = GenZir.unstacked_top, 3393 }; 3394 defer fn_gz.unstack(); 3395 3396 // TODO: support noinline 3397 const is_pub = fn_proto.visib_token != null; 3398 const is_export = blk: { 3399 const maybe_export_token = fn_proto.extern_export_inline_token orelse break :blk false; 3400 break :blk token_tags[maybe_export_token] == .keyword_export; 3401 }; 3402 const is_extern = blk: { 3403 const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false; 3404 break :blk token_tags[maybe_extern_token] == .keyword_extern; 3405 }; 3406 const has_inline_keyword = blk: { 3407 const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false; 3408 break :blk token_tags[maybe_inline_token] == .keyword_inline; 3409 }; 3410 3411 const doc_comment_index = try astgen.docCommentAsString(fn_proto.firstToken()); 3412 3413 // align, linksection, and addrspace is passed in the func instruction in this case. 3414 wip_members.nextDecl(is_pub, is_export, false, false); 3415 3416 var noalias_bits: u32 = 0; 3417 var params_scope = &fn_gz.base; 3418 const is_var_args = is_var_args: { 3419 var param_type_i: usize = 0; 3420 var it = fn_proto.iterate(tree); 3421 while (it.next()) |param| : (param_type_i += 1) { 3422 const is_comptime = if (param.comptime_noalias) |token| switch (token_tags[token]) { 3423 .keyword_noalias => is_comptime: { 3424 noalias_bits |= @as(u32, 1) << (std.math.cast(u5, param_type_i) orelse 3425 return astgen.failTok(token, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{})); 3426 break :is_comptime false; 3427 }, 3428 .keyword_comptime => true, 3429 else => false, 3430 } else false; 3431 3432 const is_anytype = if (param.anytype_ellipsis3) |token| blk: { 3433 switch (token_tags[token]) { 3434 .keyword_anytype => break :blk true, 3435 .ellipsis3 => break :is_var_args true, 3436 else => unreachable, 3437 } 3438 } else false; 3439 3440 const param_name: u32 = if (param.name_token) |name_token| blk: { 3441 const name_bytes = tree.tokenSlice(name_token); 3442 if (mem.eql(u8, "_", name_bytes)) 3443 break :blk 0; 3444 3445 const param_name = try astgen.identAsString(name_token); 3446 if (!is_extern) { 3447 try astgen.detectLocalShadowing(params_scope, param_name, name_token, name_bytes); 3448 } 3449 break :blk param_name; 3450 } else if (!is_extern) { 3451 if (param.anytype_ellipsis3) |tok| { 3452 return astgen.failTok(tok, "missing parameter name", .{}); 3453 } else { 3454 return astgen.failNode(param.type_expr, "missing parameter name", .{}); 3455 } 3456 } else 0; 3457 3458 const param_inst = if (is_anytype) param: { 3459 const name_token = param.name_token orelse param.anytype_ellipsis3.?; 3460 const tag: Zir.Inst.Tag = if (is_comptime) 3461 .param_anytype_comptime 3462 else 3463 .param_anytype; 3464 break :param try decl_gz.addStrTok(tag, param_name, name_token); 3465 } else param: { 3466 const param_type_node = param.type_expr; 3467 assert(param_type_node != 0); 3468 var param_gz = decl_gz.makeSubBlock(scope); 3469 defer param_gz.unstack(); 3470 const param_type = try expr(¶m_gz, params_scope, coerced_type_rl, param_type_node); 3471 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1); 3472 _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type); 3473 3474 const main_tokens = tree.nodes.items(.main_token); 3475 const name_token = param.name_token orelse main_tokens[param_type_node]; 3476 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param; 3477 const param_inst = try decl_gz.addParam(¶m_gz, tag, name_token, param_name, param.first_doc_comment); 3478 assert(param_inst_expected == param_inst); 3479 break :param indexToRef(param_inst); 3480 }; 3481 3482 if (param_name == 0 or is_extern) continue; 3483 3484 const sub_scope = try astgen.arena.create(Scope.LocalVal); 3485 sub_scope.* = .{ 3486 .parent = params_scope, 3487 .gen_zir = &decl_gz, 3488 .name = param_name, 3489 .inst = param_inst, 3490 .token_src = param.name_token.?, 3491 .id_cat = .@"function parameter", 3492 }; 3493 params_scope = &sub_scope.base; 3494 } 3495 break :is_var_args false; 3496 }; 3497 3498 const lib_name: u32 = if (fn_proto.lib_name) |lib_name_token| blk: { 3499 const lib_name_str = try astgen.strLitAsString(lib_name_token); 3500 break :blk lib_name_str.index; 3501 } else 0; 3502 3503 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; 3504 const is_inferred_error = token_tags[maybe_bang] == .bang; 3505 3506 // After creating the function ZIR instruction, it will need to update the break 3507 // instructions inside the expression blocks for align, addrspace, cc, and ret_ty 3508 // to use the function instruction as the "block" to break from. 3509 3510 var align_gz = decl_gz.makeSubBlock(params_scope); 3511 defer align_gz.unstack(); 3512 const align_ref: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: { 3513 const inst = try expr(&decl_gz, params_scope, coerced_align_rl, fn_proto.ast.align_expr); 3514 if (align_gz.instructionsSlice().len == 0) { 3515 // In this case we will send a len=0 body which can be encoded more efficiently. 3516 break :inst inst; 3517 } 3518 _ = try align_gz.addBreak(.break_inline, 0, inst); 3519 break :inst inst; 3520 }; 3521 3522 var addrspace_gz = decl_gz.makeSubBlock(params_scope); 3523 defer addrspace_gz.unstack(); 3524 const addrspace_ref: Zir.Inst.Ref = if (fn_proto.ast.addrspace_expr == 0) .none else inst: { 3525 const inst = try expr(&decl_gz, params_scope, .{ .coerced_ty = .address_space_type }, fn_proto.ast.addrspace_expr); 3526 if (addrspace_gz.instructionsSlice().len == 0) { 3527 // In this case we will send a len=0 body which can be encoded more efficiently. 3528 break :inst inst; 3529 } 3530 _ = try addrspace_gz.addBreak(.break_inline, 0, inst); 3531 break :inst inst; 3532 }; 3533 3534 var section_gz = decl_gz.makeSubBlock(params_scope); 3535 defer section_gz.unstack(); 3536 const section_ref: Zir.Inst.Ref = if (fn_proto.ast.section_expr == 0) .none else inst: { 3537 const inst = try expr(&decl_gz, params_scope, .{ .coerced_ty = .const_slice_u8_type }, fn_proto.ast.section_expr); 3538 if (section_gz.instructionsSlice().len == 0) { 3539 // In this case we will send a len=0 body which can be encoded more efficiently. 3540 break :inst inst; 3541 } 3542 _ = try section_gz.addBreak(.break_inline, 0, inst); 3543 break :inst inst; 3544 }; 3545 3546 var cc_gz = decl_gz.makeSubBlock(params_scope); 3547 defer cc_gz.unstack(); 3548 const cc_ref: Zir.Inst.Ref = blk: { 3549 if (fn_proto.ast.callconv_expr != 0) { 3550 if (has_inline_keyword) { 3551 return astgen.failNode( 3552 fn_proto.ast.callconv_expr, 3553 "explicit callconv incompatible with inline keyword", 3554 .{}, 3555 ); 3556 } 3557 const inst = try expr( 3558 &decl_gz, 3559 params_scope, 3560 .{ .coerced_ty = .calling_convention_type }, 3561 fn_proto.ast.callconv_expr, 3562 ); 3563 if (cc_gz.instructionsSlice().len == 0) { 3564 // In this case we will send a len=0 body which can be encoded more efficiently. 3565 break :blk inst; 3566 } 3567 _ = try cc_gz.addBreak(.break_inline, 0, inst); 3568 break :blk inst; 3569 } else if (is_extern) { 3570 // note: https://github.com/ziglang/zig/issues/5269 3571 break :blk .calling_convention_c; 3572 } else if (has_inline_keyword) { 3573 break :blk .calling_convention_inline; 3574 } else { 3575 break :blk .none; 3576 } 3577 }; 3578 3579 var ret_gz = decl_gz.makeSubBlock(params_scope); 3580 defer ret_gz.unstack(); 3581 const ret_ref: Zir.Inst.Ref = inst: { 3582 const inst = try expr(&ret_gz, params_scope, coerced_type_rl, fn_proto.ast.return_type); 3583 if (ret_gz.instructionsSlice().len == 0) { 3584 // In this case we will send a len=0 body which can be encoded more efficiently. 3585 break :inst inst; 3586 } 3587 _ = try ret_gz.addBreak(.break_inline, 0, inst); 3588 break :inst inst; 3589 }; 3590 3591 const func_inst: Zir.Inst.Ref = if (body_node == 0) func: { 3592 if (!is_extern) { 3593 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function has no body", .{}); 3594 } 3595 if (is_inferred_error) { 3596 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{}); 3597 } 3598 break :func try decl_gz.addFunc(.{ 3599 .src_node = decl_node, 3600 .cc_ref = cc_ref, 3601 .cc_gz = &cc_gz, 3602 .align_ref = align_ref, 3603 .align_gz = &align_gz, 3604 .ret_ref = ret_ref, 3605 .ret_gz = &ret_gz, 3606 .section_ref = section_ref, 3607 .section_gz = §ion_gz, 3608 .addrspace_ref = addrspace_ref, 3609 .addrspace_gz = &addrspace_gz, 3610 .param_block = block_inst, 3611 .body_gz = null, 3612 .lib_name = lib_name, 3613 .is_var_args = is_var_args, 3614 .is_inferred_error = false, 3615 .is_test = false, 3616 .is_extern = true, 3617 .noalias_bits = noalias_bits, 3618 }); 3619 } else func: { 3620 if (is_var_args) { 3621 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function is variadic", .{}); 3622 } 3623 3624 // as a scope, fn_gz encloses ret_gz, but for instruction list, fn_gz stacks on ret_gz 3625 fn_gz.instructions_top = ret_gz.instructions.items.len; 3626 3627 const prev_fn_block = astgen.fn_block; 3628 astgen.fn_block = &fn_gz; 3629 defer astgen.fn_block = prev_fn_block; 3630 3631 astgen.advanceSourceCursorToNode(body_node); 3632 const lbrace_line = astgen.source_line - decl_gz.decl_line; 3633 const lbrace_column = astgen.source_column; 3634 3635 _ = try expr(&fn_gz, params_scope, .none, body_node); 3636 try checkUsed(gz, &fn_gz.base, params_scope); 3637 3638 if (!fn_gz.endsWithNoReturn()) { 3639 // Since we are adding the return instruction here, we must handle the coercion. 3640 // We do this by using the `ret_tok` instruction. 3641 _ = try fn_gz.addUnTok(.ret_tok, .void_value, tree.lastToken(body_node)); 3642 } 3643 3644 break :func try decl_gz.addFunc(.{ 3645 .src_node = decl_node, 3646 .cc_ref = cc_ref, 3647 .cc_gz = &cc_gz, 3648 .align_ref = align_ref, 3649 .align_gz = &align_gz, 3650 .ret_ref = ret_ref, 3651 .ret_gz = &ret_gz, 3652 .section_ref = section_ref, 3653 .section_gz = §ion_gz, 3654 .addrspace_ref = addrspace_ref, 3655 .addrspace_gz = &addrspace_gz, 3656 .lbrace_line = lbrace_line, 3657 .lbrace_column = lbrace_column, 3658 .param_block = block_inst, 3659 .body_gz = &fn_gz, 3660 .lib_name = lib_name, 3661 .is_var_args = is_var_args, 3662 .is_inferred_error = is_inferred_error, 3663 .is_test = false, 3664 .is_extern = false, 3665 .noalias_bits = noalias_bits, 3666 }); 3667 }; 3668 3669 // We add this at the end so that its instruction index marks the end range 3670 // of the top level declaration. addFunc already unstacked fn_gz and ret_gz. 3671 _ = try decl_gz.addBreak(.break_inline, block_inst, func_inst); 3672 try decl_gz.setBlockBody(block_inst); 3673 3674 { 3675 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node)); 3676 const casted = @bitCast([4]u32, contents_hash); 3677 wip_members.appendToDeclSlice(&casted); 3678 } 3679 { 3680 const line_delta = decl_gz.decl_line - gz.decl_line; 3681 wip_members.appendToDecl(line_delta); 3682 } 3683 wip_members.appendToDecl(fn_name_str_index); 3684 wip_members.appendToDecl(block_inst); 3685 wip_members.appendToDecl(doc_comment_index); 3686 } 3687 3688 fn globalVarDecl( 3689 astgen: *AstGen, 3690 gz: *GenZir, 3691 scope: *Scope, 3692 wip_members: *WipMembers, 3693 node: Ast.Node.Index, 3694 var_decl: Ast.full.VarDecl, 3695 ) InnerError!void { 3696 const tree = astgen.tree; 3697 const token_tags = tree.tokens.items(.tag); 3698 3699 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var; 3700 // We do this at the beginning so that the instruction index marks the range start 3701 // of the top level declaration. 3702 const block_inst = try gz.makeBlockInst(.block_inline, node); 3703 3704 const name_token = var_decl.ast.mut_token + 1; 3705 const name_str_index = try astgen.identAsString(name_token); 3706 astgen.advanceSourceCursorToNode(node); 3707 3708 var block_scope: GenZir = .{ 3709 .parent = scope, 3710 .decl_node_index = node, 3711 .decl_line = astgen.source_line, 3712 .astgen = astgen, 3713 .force_comptime = true, 3714 .in_defer = false, 3715 .anon_name_strategy = .parent, 3716 .instructions = gz.instructions, 3717 .instructions_top = gz.instructions.items.len, 3718 }; 3719 defer block_scope.unstack(); 3720 3721 const is_pub = var_decl.visib_token != null; 3722 const is_export = blk: { 3723 const maybe_export_token = var_decl.extern_export_token orelse break :blk false; 3724 break :blk token_tags[maybe_export_token] == .keyword_export; 3725 }; 3726 const is_extern = blk: { 3727 const maybe_extern_token = var_decl.extern_export_token orelse break :blk false; 3728 break :blk token_tags[maybe_extern_token] == .keyword_extern; 3729 }; 3730 const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node == 0) .none else inst: { 3731 break :inst try expr(&block_scope, &block_scope.base, align_rl, var_decl.ast.align_node); 3732 }; 3733 const addrspace_inst: Zir.Inst.Ref = if (var_decl.ast.addrspace_node == 0) .none else inst: { 3734 break :inst try expr(&block_scope, &block_scope.base, .{ .ty = .address_space_type }, var_decl.ast.addrspace_node); 3735 }; 3736 const section_inst: Zir.Inst.Ref = if (var_decl.ast.section_node == 0) .none else inst: { 3737 break :inst try comptimeExpr(&block_scope, &block_scope.base, .{ .ty = .const_slice_u8_type }, var_decl.ast.section_node); 3738 }; 3739 const has_section_or_addrspace = section_inst != .none or addrspace_inst != .none; 3740 wip_members.nextDecl(is_pub, is_export, align_inst != .none, has_section_or_addrspace); 3741 3742 const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: { 3743 if (!is_mutable) { 3744 return astgen.failTok(tok, "threadlocal variable cannot be constant", .{}); 3745 } 3746 break :blk true; 3747 } else false; 3748 3749 const lib_name: u32 = if (var_decl.lib_name) |lib_name_token| blk: { 3750 const lib_name_str = try astgen.strLitAsString(lib_name_token); 3751 break :blk lib_name_str.index; 3752 } else 0; 3753 3754 const doc_comment_index = try astgen.docCommentAsString(var_decl.firstToken()); 3755 3756 assert(var_decl.comptime_token == null); // handled by parser 3757 3758 const var_inst: Zir.Inst.Ref = if (var_decl.ast.init_node != 0) vi: { 3759 if (is_extern) { 3760 return astgen.failNode( 3761 var_decl.ast.init_node, 3762 "extern variables have no initializers", 3763 .{}, 3764 ); 3765 } 3766 3767 const type_inst: Zir.Inst.Ref = if (var_decl.ast.type_node != 0) 3768 try expr( 3769 &block_scope, 3770 &block_scope.base, 3771 .{ .ty = .type_type }, 3772 var_decl.ast.type_node, 3773 ) 3774 else 3775 .none; 3776 3777 const init_inst = try expr( 3778 &block_scope, 3779 &block_scope.base, 3780 if (type_inst != .none) .{ .ty = type_inst } else .none, 3781 var_decl.ast.init_node, 3782 ); 3783 3784 if (is_mutable) { 3785 const var_inst = try block_scope.addVar(.{ 3786 .var_type = type_inst, 3787 .lib_name = 0, 3788 .align_inst = .none, // passed via the decls data 3789 .init = init_inst, 3790 .is_extern = false, 3791 .is_threadlocal = is_threadlocal, 3792 }); 3793 break :vi var_inst; 3794 } else { 3795 break :vi init_inst; 3796 } 3797 } else if (!is_extern) { 3798 return astgen.failNode(node, "variables must be initialized", .{}); 3799 } else if (var_decl.ast.type_node != 0) vi: { 3800 // Extern variable which has an explicit type. 3801 const type_inst = try typeExpr(&block_scope, &block_scope.base, var_decl.ast.type_node); 3802 3803 const var_inst = try block_scope.addVar(.{ 3804 .var_type = type_inst, 3805 .lib_name = lib_name, 3806 .align_inst = .none, // passed via the decls data 3807 .init = .none, 3808 .is_extern = true, 3809 .is_threadlocal = is_threadlocal, 3810 }); 3811 break :vi var_inst; 3812 } else { 3813 return astgen.failNode(node, "unable to infer variable type", .{}); 3814 }; 3815 // We do this at the end so that the instruction index marks the end 3816 // range of a top level declaration. 3817 _ = try block_scope.addBreak(.break_inline, block_inst, var_inst); 3818 try block_scope.setBlockBody(block_inst); 3819 3820 { 3821 const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); 3822 const casted = @bitCast([4]u32, contents_hash); 3823 wip_members.appendToDeclSlice(&casted); 3824 } 3825 { 3826 const line_delta = block_scope.decl_line - gz.decl_line; 3827 wip_members.appendToDecl(line_delta); 3828 } 3829 wip_members.appendToDecl(name_str_index); 3830 wip_members.appendToDecl(block_inst); 3831 wip_members.appendToDecl(doc_comment_index); // doc_comment wip 3832 if (align_inst != .none) { 3833 wip_members.appendToDecl(@enumToInt(align_inst)); 3834 } 3835 if (has_section_or_addrspace) { 3836 wip_members.appendToDecl(@enumToInt(section_inst)); 3837 wip_members.appendToDecl(@enumToInt(addrspace_inst)); 3838 } 3839 } 3840 3841 fn comptimeDecl( 3842 astgen: *AstGen, 3843 gz: *GenZir, 3844 scope: *Scope, 3845 wip_members: *WipMembers, 3846 node: Ast.Node.Index, 3847 ) InnerError!void { 3848 const tree = astgen.tree; 3849 const node_datas = tree.nodes.items(.data); 3850 const body_node = node_datas[node].lhs; 3851 3852 // Up top so the ZIR instruction index marks the start range of this 3853 // top-level declaration. 3854 const block_inst = try gz.makeBlockInst(.block_inline, node); 3855 wip_members.nextDecl(false, false, false, false); 3856 astgen.advanceSourceCursorToNode(node); 3857 3858 var decl_block: GenZir = .{ 3859 .force_comptime = true, 3860 .in_defer = false, 3861 .decl_node_index = node, 3862 .decl_line = astgen.source_line, 3863 .parent = scope, 3864 .astgen = astgen, 3865 .instructions = gz.instructions, 3866 .instructions_top = gz.instructions.items.len, 3867 }; 3868 defer decl_block.unstack(); 3869 3870 const block_result = try expr(&decl_block, &decl_block.base, .none, body_node); 3871 if (decl_block.isEmpty() or !decl_block.refIsNoReturn(block_result)) { 3872 _ = try decl_block.addBreak(.break_inline, block_inst, .void_value); 3873 } 3874 try decl_block.setBlockBody(block_inst); 3875 3876 { 3877 const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); 3878 const casted = @bitCast([4]u32, contents_hash); 3879 wip_members.appendToDeclSlice(&casted); 3880 } 3881 { 3882 const line_delta = decl_block.decl_line - gz.decl_line; 3883 wip_members.appendToDecl(line_delta); 3884 } 3885 wip_members.appendToDecl(0); 3886 wip_members.appendToDecl(block_inst); 3887 wip_members.appendToDecl(0); // no doc comments on comptime decls 3888 } 3889 3890 fn usingnamespaceDecl( 3891 astgen: *AstGen, 3892 gz: *GenZir, 3893 scope: *Scope, 3894 wip_members: *WipMembers, 3895 node: Ast.Node.Index, 3896 ) InnerError!void { 3897 const tree = astgen.tree; 3898 const node_datas = tree.nodes.items(.data); 3899 3900 const type_expr = node_datas[node].lhs; 3901 const is_pub = blk: { 3902 const main_tokens = tree.nodes.items(.main_token); 3903 const token_tags = tree.tokens.items(.tag); 3904 const main_token = main_tokens[node]; 3905 break :blk (main_token > 0 and token_tags[main_token - 1] == .keyword_pub); 3906 }; 3907 // Up top so the ZIR instruction index marks the start range of this 3908 // top-level declaration. 3909 const block_inst = try gz.makeBlockInst(.block_inline, node); 3910 wip_members.nextDecl(is_pub, true, false, false); 3911 astgen.advanceSourceCursorToNode(node); 3912 3913 var decl_block: GenZir = .{ 3914 .force_comptime = true, 3915 .in_defer = false, 3916 .decl_node_index = node, 3917 .decl_line = astgen.source_line, 3918 .parent = scope, 3919 .astgen = astgen, 3920 .instructions = gz.instructions, 3921 .instructions_top = gz.instructions.items.len, 3922 }; 3923 defer decl_block.unstack(); 3924 3925 const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr); 3926 _ = try decl_block.addBreak(.break_inline, block_inst, namespace_inst); 3927 try decl_block.setBlockBody(block_inst); 3928 3929 { 3930 const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); 3931 const casted = @bitCast([4]u32, contents_hash); 3932 wip_members.appendToDeclSlice(&casted); 3933 } 3934 { 3935 const line_delta = decl_block.decl_line - gz.decl_line; 3936 wip_members.appendToDecl(line_delta); 3937 } 3938 wip_members.appendToDecl(0); 3939 wip_members.appendToDecl(block_inst); 3940 wip_members.appendToDecl(0); // no doc comments on usingnamespace decls 3941 } 3942 3943 fn testDecl( 3944 astgen: *AstGen, 3945 gz: *GenZir, 3946 scope: *Scope, 3947 wip_members: *WipMembers, 3948 node: Ast.Node.Index, 3949 ) InnerError!void { 3950 const tree = astgen.tree; 3951 const node_datas = tree.nodes.items(.data); 3952 const body_node = node_datas[node].rhs; 3953 3954 // Up top so the ZIR instruction index marks the start range of this 3955 // top-level declaration. 3956 const block_inst = try gz.makeBlockInst(.block_inline, node); 3957 3958 wip_members.nextDecl(false, false, false, false); 3959 astgen.advanceSourceCursorToNode(node); 3960 3961 var decl_block: GenZir = .{ 3962 .force_comptime = true, 3963 .in_defer = false, 3964 .decl_node_index = node, 3965 .decl_line = astgen.source_line, 3966 .parent = scope, 3967 .astgen = astgen, 3968 .instructions = gz.instructions, 3969 .instructions_top = gz.instructions.items.len, 3970 }; 3971 defer decl_block.unstack(); 3972 3973 const main_tokens = tree.nodes.items(.main_token); 3974 const token_tags = tree.tokens.items(.tag); 3975 const test_token = main_tokens[node]; 3976 const test_name_token = test_token + 1; 3977 const test_name_token_tag = token_tags[test_name_token]; 3978 const is_decltest = test_name_token_tag == .identifier; 3979 const test_name: u32 = blk: { 3980 if (test_name_token_tag == .string_literal) { 3981 break :blk try astgen.testNameString(test_name_token); 3982 } else if (test_name_token_tag == .identifier) { 3983 const ident_name_raw = tree.tokenSlice(test_name_token); 3984 3985 if (mem.eql(u8, ident_name_raw, "_")) return astgen.failTok(test_name_token, "'_' used as an identifier without @\"_\" syntax", .{}); 3986 3987 // if not @"" syntax, just use raw token slice 3988 if (ident_name_raw[0] != '@') { 3989 if (primitives.get(ident_name_raw)) |_| return astgen.failTok(test_name_token, "cannot test a primitive", .{}); 3990 3991 if (ident_name_raw.len >= 2) integer: { 3992 const first_c = ident_name_raw[0]; 3993 if (first_c == 'i' or first_c == 'u') { 3994 _ = switch (first_c == 'i') { 3995 true => .signed, 3996 false => .unsigned, 3997 }; 3998 _ = parseBitCount(ident_name_raw[1..]) catch |err| switch (err) { 3999 error.Overflow => return astgen.failTok( 4000 test_name_token, 4001 "primitive integer type '{s}' exceeds maximum bit width of 65535", 4002 .{ident_name_raw}, 4003 ), 4004 error.InvalidCharacter => break :integer, 4005 }; 4006 return astgen.failTok(test_name_token, "cannot test a primitive", .{}); 4007 } 4008 } 4009 } 4010 4011 // Local variables, including function parameters. 4012 const name_str_index = try astgen.identAsString(test_name_token); 4013 var s = scope; 4014 var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already 4015 var num_namespaces_out: u32 = 0; 4016 var capturing_namespace: ?*Scope.Namespace = null; 4017 while (true) switch (s.tag) { 4018 .local_val, .local_ptr => unreachable, // a test cannot be in a local scope 4019 .gen_zir => s = s.cast(GenZir).?.parent, 4020 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, 4021 .namespace => { 4022 const ns = s.cast(Scope.Namespace).?; 4023 if (ns.decls.get(name_str_index)) |i| { 4024 if (found_already) |f| { 4025 return astgen.failTokNotes(test_name_token, "ambiguous reference", .{}, &.{ 4026 try astgen.errNoteNode(f, "declared here", .{}), 4027 try astgen.errNoteNode(i, "also declared here", .{}), 4028 }); 4029 } 4030 // We found a match but must continue looking for ambiguous references to decls. 4031 found_already = i; 4032 } 4033 num_namespaces_out += 1; 4034 capturing_namespace = ns; 4035 s = ns.parent; 4036 }, 4037 .top => break, 4038 }; 4039 if (found_already == null) { 4040 const ident_name = try astgen.identifierTokenString(test_name_token); 4041 return astgen.failTok(test_name_token, "use of undeclared identifier '{s}'", .{ident_name}); 4042 } 4043 4044 break :blk name_str_index; 4045 } 4046 // String table index 1 has a special meaning here of test decl with no name. 4047 break :blk 1; 4048 }; 4049 4050 var fn_block: GenZir = .{ 4051 .force_comptime = false, 4052 .in_defer = false, 4053 .decl_node_index = node, 4054 .decl_line = decl_block.decl_line, 4055 .parent = &decl_block.base, 4056 .astgen = astgen, 4057 .instructions = decl_block.instructions, 4058 .instructions_top = decl_block.instructions.items.len, 4059 }; 4060 defer fn_block.unstack(); 4061 4062 const prev_fn_block = astgen.fn_block; 4063 astgen.fn_block = &fn_block; 4064 defer astgen.fn_block = prev_fn_block; 4065 4066 astgen.advanceSourceCursorToNode(body_node); 4067 const lbrace_line = astgen.source_line - decl_block.decl_line; 4068 const lbrace_column = astgen.source_column; 4069 4070 const block_result = try expr(&fn_block, &fn_block.base, .none, body_node); 4071 if (fn_block.isEmpty() or !fn_block.refIsNoReturn(block_result)) { 4072 // Since we are adding the return instruction here, we must handle the coercion. 4073 // We do this by using the `ret_tok` instruction. 4074 _ = try fn_block.addUnTok(.ret_tok, .void_value, tree.lastToken(body_node)); 4075 } 4076 4077 const func_inst = try decl_block.addFunc(.{ 4078 .src_node = node, 4079 4080 .cc_ref = .none, 4081 .cc_gz = null, 4082 .align_ref = .none, 4083 .align_gz = null, 4084 .ret_ref = .void_type, 4085 .ret_gz = null, 4086 .section_ref = .none, 4087 .section_gz = null, 4088 .addrspace_ref = .none, 4089 .addrspace_gz = null, 4090 4091 .lbrace_line = lbrace_line, 4092 .lbrace_column = lbrace_column, 4093 .param_block = block_inst, 4094 .body_gz = &fn_block, 4095 .lib_name = 0, 4096 .is_var_args = false, 4097 .is_inferred_error = true, 4098 .is_test = true, 4099 .is_extern = false, 4100 .noalias_bits = 0, 4101 }); 4102 4103 _ = try decl_block.addBreak(.break_inline, block_inst, func_inst); 4104 try decl_block.setBlockBody(block_inst); 4105 4106 { 4107 const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); 4108 const casted = @bitCast([4]u32, contents_hash); 4109 wip_members.appendToDeclSlice(&casted); 4110 } 4111 { 4112 const line_delta = decl_block.decl_line - gz.decl_line; 4113 wip_members.appendToDecl(line_delta); 4114 } 4115 if (is_decltest) 4116 wip_members.appendToDecl(2) // 2 here means that it is a decltest, look at doc comment for name 4117 else 4118 wip_members.appendToDecl(test_name); 4119 wip_members.appendToDecl(block_inst); 4120 if (is_decltest) 4121 wip_members.appendToDecl(test_name) // the doc comment on a decltest represents it's name 4122 else 4123 wip_members.appendToDecl(0); // no doc comments on test decls 4124 } 4125 4126 fn structDeclInner( 4127 gz: *GenZir, 4128 scope: *Scope, 4129 node: Ast.Node.Index, 4130 container_decl: Ast.full.ContainerDecl, 4131 layout: std.builtin.Type.ContainerLayout, 4132 ) InnerError!Zir.Inst.Ref { 4133 const decl_inst = try gz.reserveInstructionIndex(); 4134 4135 if (container_decl.ast.members.len == 0) { 4136 try gz.setStruct(decl_inst, .{ 4137 .src_node = node, 4138 .layout = layout, 4139 .fields_len = 0, 4140 .body_len = 0, 4141 .decls_len = 0, 4142 .known_non_opv = false, 4143 .known_comptime_only = false, 4144 }); 4145 return indexToRef(decl_inst); 4146 } 4147 4148 const astgen = gz.astgen; 4149 const gpa = astgen.gpa; 4150 const tree = astgen.tree; 4151 4152 var namespace: Scope.Namespace = .{ 4153 .parent = scope, 4154 .node = node, 4155 .inst = decl_inst, 4156 .declaring_gz = gz, 4157 }; 4158 defer namespace.deinit(gpa); 4159 4160 // The struct_decl instruction introduces a scope in which the decls of the struct 4161 // are in scope, so that field types, alignments, and default value expressions 4162 // can refer to decls within the struct itself. 4163 astgen.advanceSourceCursorToNode(node); 4164 var block_scope: GenZir = .{ 4165 .parent = &namespace.base, 4166 .decl_node_index = node, 4167 .decl_line = astgen.source_line, 4168 .astgen = astgen, 4169 .force_comptime = true, 4170 .in_defer = false, 4171 .instructions = gz.instructions, 4172 .instructions_top = gz.instructions.items.len, 4173 }; 4174 defer block_scope.unstack(); 4175 4176 const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members); 4177 const field_count = @intCast(u32, container_decl.ast.members.len - decl_count); 4178 4179 const bits_per_field = 4; 4180 const max_field_size = 5; 4181 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size); 4182 defer wip_members.deinit(); 4183 4184 var known_non_opv = false; 4185 var known_comptime_only = false; 4186 for (container_decl.ast.members) |member_node| { 4187 const member = switch (try containerMember(gz, &namespace.base, &wip_members, member_node)) { 4188 .decl => continue, 4189 .field => |field| field, 4190 }; 4191 4192 const field_name = try astgen.identAsString(member.ast.name_token); 4193 wip_members.appendToField(field_name); 4194 4195 if (member.ast.type_expr == 0) { 4196 return astgen.failTok(member.ast.name_token, "struct field missing type", .{}); 4197 } 4198 4199 const field_type = try typeExpr(&block_scope, &namespace.base, member.ast.type_expr); 4200 wip_members.appendToField(@enumToInt(field_type)); 4201 4202 const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); 4203 wip_members.appendToField(doc_comment_index); 4204 4205 const have_align = member.ast.align_expr != 0; 4206 const have_value = member.ast.value_expr != 0; 4207 const is_comptime = member.comptime_token != null; 4208 const unused = false; 4209 4210 if (!is_comptime) { 4211 known_non_opv = known_non_opv or 4212 nodeImpliesMoreThanOnePossibleValue(tree, member.ast.type_expr); 4213 known_comptime_only = known_comptime_only or 4214 nodeImpliesComptimeOnly(tree, member.ast.type_expr); 4215 } 4216 wip_members.nextField(bits_per_field, .{ have_align, have_value, is_comptime, unused }); 4217 4218 if (have_align) { 4219 if (layout == .Packed) { 4220 try astgen.appendErrorNode(member.ast.align_expr, "unable to override alignment of packed struct fields", .{}); 4221 } 4222 const align_inst = try expr(&block_scope, &namespace.base, align_rl, member.ast.align_expr); 4223 wip_members.appendToField(@enumToInt(align_inst)); 4224 } 4225 if (have_value) { 4226 const rl: ResultLoc = if (field_type == .none) .none else .{ .ty = field_type }; 4227 4228 const default_inst = try expr(&block_scope, &namespace.base, rl, member.ast.value_expr); 4229 wip_members.appendToField(@enumToInt(default_inst)); 4230 } else if (member.comptime_token) |comptime_token| { 4231 return astgen.failTok(comptime_token, "comptime field without default initialization value", .{}); 4232 } 4233 } 4234 4235 if (!block_scope.isEmpty()) { 4236 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); 4237 } 4238 4239 const body = block_scope.instructionsSlice(); 4240 const body_len = astgen.countBodyLenAfterFixups(body); 4241 4242 try gz.setStruct(decl_inst, .{ 4243 .src_node = node, 4244 .layout = layout, 4245 .body_len = body_len, 4246 .fields_len = field_count, 4247 .decls_len = decl_count, 4248 .known_non_opv = known_non_opv, 4249 .known_comptime_only = known_comptime_only, 4250 }); 4251 4252 wip_members.finishBits(bits_per_field); 4253 const decls_slice = wip_members.declsSlice(); 4254 const fields_slice = wip_members.fieldsSlice(); 4255 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + body_len + fields_slice.len); 4256 astgen.extra.appendSliceAssumeCapacity(decls_slice); 4257 astgen.appendBodyWithFixups(body); 4258 astgen.extra.appendSliceAssumeCapacity(fields_slice); 4259 4260 block_scope.unstack(); 4261 try gz.addNamespaceCaptures(&namespace); 4262 return indexToRef(decl_inst); 4263 } 4264 4265 fn unionDeclInner( 4266 gz: *GenZir, 4267 scope: *Scope, 4268 node: Ast.Node.Index, 4269 members: []const Ast.Node.Index, 4270 layout: std.builtin.Type.ContainerLayout, 4271 arg_node: Ast.Node.Index, 4272 have_auto_enum: bool, 4273 ) InnerError!Zir.Inst.Ref { 4274 const decl_inst = try gz.reserveInstructionIndex(); 4275 4276 const astgen = gz.astgen; 4277 const gpa = astgen.gpa; 4278 4279 var namespace: Scope.Namespace = .{ 4280 .parent = scope, 4281 .node = node, 4282 .inst = decl_inst, 4283 .declaring_gz = gz, 4284 }; 4285 defer namespace.deinit(gpa); 4286 4287 // The union_decl instruction introduces a scope in which the decls of the union 4288 // are in scope, so that field types, alignments, and default value expressions 4289 // can refer to decls within the union itself. 4290 astgen.advanceSourceCursorToNode(node); 4291 var block_scope: GenZir = .{ 4292 .parent = &namespace.base, 4293 .decl_node_index = node, 4294 .decl_line = astgen.source_line, 4295 .astgen = astgen, 4296 .force_comptime = true, 4297 .in_defer = false, 4298 .instructions = gz.instructions, 4299 .instructions_top = gz.instructions.items.len, 4300 }; 4301 defer block_scope.unstack(); 4302 4303 const decl_count = try astgen.scanDecls(&namespace, members); 4304 const field_count = @intCast(u32, members.len - decl_count); 4305 4306 const arg_inst: Zir.Inst.Ref = if (arg_node != 0) 4307 try typeExpr(&block_scope, &namespace.base, arg_node) 4308 else 4309 .none; 4310 4311 const bits_per_field = 4; 4312 const max_field_size = 5; 4313 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size); 4314 defer wip_members.deinit(); 4315 4316 for (members) |member_node| { 4317 const member = switch (try containerMember(gz, &namespace.base, &wip_members, member_node)) { 4318 .decl => continue, 4319 .field => |field| field, 4320 }; 4321 if (member.comptime_token) |comptime_token| { 4322 return astgen.failTok(comptime_token, "union fields cannot be marked comptime", .{}); 4323 } 4324 4325 const field_name = try astgen.identAsString(member.ast.name_token); 4326 wip_members.appendToField(field_name); 4327 4328 const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); 4329 wip_members.appendToField(doc_comment_index); 4330 4331 const have_type = member.ast.type_expr != 0; 4332 const have_align = member.ast.align_expr != 0; 4333 const have_value = member.ast.value_expr != 0; 4334 const unused = false; 4335 wip_members.nextField(bits_per_field, .{ have_type, have_align, have_value, unused }); 4336 4337 if (have_type) { 4338 const field_type = try typeExpr(&block_scope, &namespace.base, member.ast.type_expr); 4339 wip_members.appendToField(@enumToInt(field_type)); 4340 } else if (arg_inst == .none and !have_auto_enum) { 4341 return astgen.failNode(member_node, "union field missing type", .{}); 4342 } 4343 if (have_align) { 4344 const align_inst = try expr(&block_scope, &block_scope.base, .{ .ty = .u32_type }, member.ast.align_expr); 4345 wip_members.appendToField(@enumToInt(align_inst)); 4346 } 4347 if (have_value) { 4348 if (arg_inst == .none) { 4349 return astgen.failNodeNotes( 4350 node, 4351 "explicitly valued tagged union missing integer tag type", 4352 .{}, 4353 &[_]u32{ 4354 try astgen.errNoteNode( 4355 member.ast.value_expr, 4356 "tag value specified here", 4357 .{}, 4358 ), 4359 }, 4360 ); 4361 } 4362 if (!have_auto_enum) { 4363 return astgen.failNodeNotes( 4364 node, 4365 "explicitly valued tagged union requires inferred enum tag type", 4366 .{}, 4367 &[_]u32{ 4368 try astgen.errNoteNode( 4369 member.ast.value_expr, 4370 "tag value specified here", 4371 .{}, 4372 ), 4373 }, 4374 ); 4375 } 4376 const tag_value = try expr(&block_scope, &block_scope.base, .{ .ty = arg_inst }, member.ast.value_expr); 4377 wip_members.appendToField(@enumToInt(tag_value)); 4378 } 4379 } 4380 if (field_count == 0) { 4381 return astgen.failNode(node, "union declarations must have at least one tag", .{}); 4382 } 4383 4384 if (!block_scope.isEmpty()) { 4385 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); 4386 } 4387 4388 const body = block_scope.instructionsSlice(); 4389 const body_len = astgen.countBodyLenAfterFixups(body); 4390 4391 try gz.setUnion(decl_inst, .{ 4392 .src_node = node, 4393 .layout = layout, 4394 .tag_type = arg_inst, 4395 .body_len = body_len, 4396 .fields_len = field_count, 4397 .decls_len = decl_count, 4398 .auto_enum_tag = have_auto_enum, 4399 }); 4400 4401 wip_members.finishBits(bits_per_field); 4402 const decls_slice = wip_members.declsSlice(); 4403 const fields_slice = wip_members.fieldsSlice(); 4404 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + body_len + fields_slice.len); 4405 astgen.extra.appendSliceAssumeCapacity(decls_slice); 4406 astgen.appendBodyWithFixups(body); 4407 astgen.extra.appendSliceAssumeCapacity(fields_slice); 4408 4409 block_scope.unstack(); 4410 try gz.addNamespaceCaptures(&namespace); 4411 return indexToRef(decl_inst); 4412 } 4413 4414 fn containerDecl( 4415 gz: *GenZir, 4416 scope: *Scope, 4417 rl: ResultLoc, 4418 node: Ast.Node.Index, 4419 container_decl: Ast.full.ContainerDecl, 4420 ) InnerError!Zir.Inst.Ref { 4421 const astgen = gz.astgen; 4422 const gpa = astgen.gpa; 4423 const tree = astgen.tree; 4424 const token_tags = tree.tokens.items(.tag); 4425 const node_tags = tree.nodes.items(.tag); 4426 4427 const prev_fn_block = astgen.fn_block; 4428 astgen.fn_block = null; 4429 defer astgen.fn_block = prev_fn_block; 4430 4431 // We must not create any types until Sema. Here the goal is only to generate 4432 // ZIR for all the field types, alignments, and default value expressions. 4433 4434 switch (token_tags[container_decl.ast.main_token]) { 4435 .keyword_struct => { 4436 const layout = if (container_decl.layout_token) |t| switch (token_tags[t]) { 4437 .keyword_packed => std.builtin.Type.ContainerLayout.Packed, 4438 .keyword_extern => std.builtin.Type.ContainerLayout.Extern, 4439 else => unreachable, 4440 } else std.builtin.Type.ContainerLayout.Auto; 4441 4442 assert(container_decl.ast.arg == 0); 4443 4444 const result = try structDeclInner(gz, scope, node, container_decl, layout); 4445 return rvalue(gz, rl, result, node); 4446 }, 4447 .keyword_union => { 4448 const layout = if (container_decl.layout_token) |t| switch (token_tags[t]) { 4449 .keyword_packed => std.builtin.Type.ContainerLayout.Packed, 4450 .keyword_extern => std.builtin.Type.ContainerLayout.Extern, 4451 else => unreachable, 4452 } else std.builtin.Type.ContainerLayout.Auto; 4453 4454 const have_auto_enum = container_decl.ast.enum_token != null; 4455 4456 const result = try unionDeclInner(gz, scope, node, container_decl.ast.members, layout, container_decl.ast.arg, have_auto_enum); 4457 return rvalue(gz, rl, result, node); 4458 }, 4459 .keyword_enum => { 4460 if (container_decl.layout_token) |t| { 4461 return astgen.failTok(t, "enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type", .{}); 4462 } 4463 // Count total fields as well as how many have explicitly provided tag values. 4464 const counts = blk: { 4465 var values: usize = 0; 4466 var total_fields: usize = 0; 4467 var decls: usize = 0; 4468 var nonexhaustive_node: Ast.Node.Index = 0; 4469 var nonfinal_nonexhaustive = false; 4470 for (container_decl.ast.members) |member_node| { 4471 const member = switch (node_tags[member_node]) { 4472 .container_field_init => tree.containerFieldInit(member_node), 4473 .container_field_align => tree.containerFieldAlign(member_node), 4474 .container_field => tree.containerField(member_node), 4475 else => { 4476 decls += 1; 4477 continue; 4478 }, 4479 }; 4480 if (member.comptime_token) |comptime_token| { 4481 return astgen.failTok(comptime_token, "enum fields cannot be marked comptime", .{}); 4482 } 4483 if (member.ast.type_expr != 0) { 4484 return astgen.failNodeNotes( 4485 member.ast.type_expr, 4486 "enum fields do not have types", 4487 .{}, 4488 &[_]u32{ 4489 try astgen.errNoteNode( 4490 node, 4491 "consider 'union(enum)' here to make it a tagged union", 4492 .{}, 4493 ), 4494 }, 4495 ); 4496 } 4497 // Alignment expressions in enums are caught by the parser. 4498 assert(member.ast.align_expr == 0); 4499 4500 const name_token = member.ast.name_token; 4501 if (mem.eql(u8, tree.tokenSlice(name_token), "_")) { 4502 if (nonexhaustive_node != 0) { 4503 return astgen.failNodeNotes( 4504 member_node, 4505 "redundant non-exhaustive enum mark", 4506 .{}, 4507 &[_]u32{ 4508 try astgen.errNoteNode( 4509 nonexhaustive_node, 4510 "other mark here", 4511 .{}, 4512 ), 4513 }, 4514 ); 4515 } 4516 nonexhaustive_node = member_node; 4517 if (member.ast.value_expr != 0) { 4518 return astgen.failNode(member.ast.value_expr, "'_' is used to mark an enum as non-exhaustive and cannot be assigned a value", .{}); 4519 } 4520 continue; 4521 } else if (nonexhaustive_node != 0) { 4522 nonfinal_nonexhaustive = true; 4523 } 4524 total_fields += 1; 4525 if (member.ast.value_expr != 0) { 4526 if (container_decl.ast.arg == 0) { 4527 return astgen.failNode(member.ast.value_expr, "value assigned to enum tag with inferred tag type", .{}); 4528 } 4529 values += 1; 4530 } 4531 } 4532 if (nonfinal_nonexhaustive) { 4533 return astgen.failNode(nonexhaustive_node, "'_' field of non-exhaustive enum must be last", .{}); 4534 } 4535 break :blk .{ 4536 .total_fields = total_fields, 4537 .values = values, 4538 .decls = decls, 4539 .nonexhaustive_node = nonexhaustive_node, 4540 }; 4541 }; 4542 if (counts.total_fields == 0 and counts.nonexhaustive_node == 0) { 4543 // One can construct an enum with no tags, and it functions the same as `noreturn`. But 4544 // this is only useful for generic code; when explicitly using `enum {}` syntax, there 4545 // must be at least one tag. 4546 try astgen.appendErrorNode(node, "enum declarations must have at least one tag", .{}); 4547 } 4548 if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) { 4549 try astgen.appendErrorNodeNotes( 4550 node, 4551 "non-exhaustive enum missing integer tag type", 4552 .{}, 4553 &[_]u32{ 4554 try astgen.errNoteNode( 4555 counts.nonexhaustive_node, 4556 "marked non-exhaustive here", 4557 .{}, 4558 ), 4559 }, 4560 ); 4561 } 4562 // In this case we must generate ZIR code for the tag values, similar to 4563 // how structs are handled above. 4564 const nonexhaustive = counts.nonexhaustive_node != 0; 4565 4566 const decl_inst = try gz.reserveInstructionIndex(); 4567 4568 var namespace: Scope.Namespace = .{ 4569 .parent = scope, 4570 .node = node, 4571 .inst = decl_inst, 4572 .declaring_gz = gz, 4573 }; 4574 defer namespace.deinit(gpa); 4575 4576 // The enum_decl instruction introduces a scope in which the decls of the enum 4577 // are in scope, so that tag values can refer to decls within the enum itself. 4578 astgen.advanceSourceCursorToNode(node); 4579 var block_scope: GenZir = .{ 4580 .parent = &namespace.base, 4581 .decl_node_index = node, 4582 .decl_line = astgen.source_line, 4583 .astgen = astgen, 4584 .force_comptime = true, 4585 .in_defer = false, 4586 .instructions = gz.instructions, 4587 .instructions_top = gz.instructions.items.len, 4588 }; 4589 defer block_scope.unstack(); 4590 4591 _ = try astgen.scanDecls(&namespace, container_decl.ast.members); 4592 4593 const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0) 4594 try comptimeExpr(&block_scope, &namespace.base, .{ .ty = .type_type }, container_decl.ast.arg) 4595 else 4596 .none; 4597 4598 const bits_per_field = 1; 4599 const max_field_size = 3; 4600 var wip_members = try WipMembers.init(gpa, &astgen.scratch, @intCast(u32, counts.decls), @intCast(u32, counts.total_fields), bits_per_field, max_field_size); 4601 defer wip_members.deinit(); 4602 4603 for (container_decl.ast.members) |member_node| { 4604 if (member_node == counts.nonexhaustive_node) 4605 continue; 4606 const member = switch (try containerMember(gz, &namespace.base, &wip_members, member_node)) { 4607 .decl => continue, 4608 .field => |field| field, 4609 }; 4610 assert(member.comptime_token == null); 4611 assert(member.ast.type_expr == 0); 4612 assert(member.ast.align_expr == 0); 4613 4614 const field_name = try astgen.identAsString(member.ast.name_token); 4615 wip_members.appendToField(field_name); 4616 4617 const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); 4618 wip_members.appendToField(doc_comment_index); 4619 4620 const have_value = member.ast.value_expr != 0; 4621 wip_members.nextField(bits_per_field, .{have_value}); 4622 4623 if (have_value) { 4624 if (arg_inst == .none) { 4625 return astgen.failNodeNotes( 4626 node, 4627 "explicitly valued enum missing integer tag type", 4628 .{}, 4629 &[_]u32{ 4630 try astgen.errNoteNode( 4631 member.ast.value_expr, 4632 "tag value specified here", 4633 .{}, 4634 ), 4635 }, 4636 ); 4637 } 4638 const tag_value_inst = try expr(&block_scope, &namespace.base, .{ .ty = arg_inst }, member.ast.value_expr); 4639 wip_members.appendToField(@enumToInt(tag_value_inst)); 4640 } 4641 } 4642 4643 if (!block_scope.isEmpty()) { 4644 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); 4645 } 4646 4647 const body = block_scope.instructionsSlice(); 4648 const body_len = astgen.countBodyLenAfterFixups(body); 4649 4650 try gz.setEnum(decl_inst, .{ 4651 .src_node = node, 4652 .nonexhaustive = nonexhaustive, 4653 .tag_type = arg_inst, 4654 .body_len = body_len, 4655 .fields_len = @intCast(u32, counts.total_fields), 4656 .decls_len = @intCast(u32, counts.decls), 4657 }); 4658 4659 wip_members.finishBits(bits_per_field); 4660 const decls_slice = wip_members.declsSlice(); 4661 const fields_slice = wip_members.fieldsSlice(); 4662 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + body_len + fields_slice.len); 4663 astgen.extra.appendSliceAssumeCapacity(decls_slice); 4664 astgen.appendBodyWithFixups(body); 4665 astgen.extra.appendSliceAssumeCapacity(fields_slice); 4666 4667 block_scope.unstack(); 4668 try gz.addNamespaceCaptures(&namespace); 4669 return rvalue(gz, rl, indexToRef(decl_inst), node); 4670 }, 4671 .keyword_opaque => { 4672 assert(container_decl.ast.arg == 0); 4673 4674 const decl_inst = try gz.reserveInstructionIndex(); 4675 4676 var namespace: Scope.Namespace = .{ 4677 .parent = scope, 4678 .node = node, 4679 .inst = decl_inst, 4680 .declaring_gz = gz, 4681 }; 4682 defer namespace.deinit(gpa); 4683 4684 const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members); 4685 4686 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, 0, 0, 0); 4687 defer wip_members.deinit(); 4688 4689 for (container_decl.ast.members) |member_node| { 4690 _ = try containerMember(gz, &namespace.base, &wip_members, member_node); 4691 } 4692 4693 try gz.setOpaque(decl_inst, .{ 4694 .src_node = node, 4695 .decls_len = decl_count, 4696 }); 4697 4698 wip_members.finishBits(0); 4699 const decls_slice = wip_members.declsSlice(); 4700 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len); 4701 astgen.extra.appendSliceAssumeCapacity(decls_slice); 4702 4703 try gz.addNamespaceCaptures(&namespace); 4704 return rvalue(gz, rl, indexToRef(decl_inst), node); 4705 }, 4706 else => unreachable, 4707 } 4708 } 4709 4710 const ContainerMemberResult = union(enum) { decl, field: Ast.full.ContainerField }; 4711 4712 fn containerMember( 4713 gz: *GenZir, 4714 scope: *Scope, 4715 wip_members: *WipMembers, 4716 member_node: Ast.Node.Index, 4717 ) InnerError!ContainerMemberResult { 4718 const astgen = gz.astgen; 4719 const tree = astgen.tree; 4720 const node_tags = tree.nodes.items(.tag); 4721 const node_datas = tree.nodes.items(.data); 4722 switch (node_tags[member_node]) { 4723 .container_field_init => return ContainerMemberResult{ .field = tree.containerFieldInit(member_node) }, 4724 .container_field_align => return ContainerMemberResult{ .field = tree.containerFieldAlign(member_node) }, 4725 .container_field => return ContainerMemberResult{ .field = tree.containerField(member_node) }, 4726 4727 .fn_decl => { 4728 const fn_proto = node_datas[member_node].lhs; 4729 const body = node_datas[member_node].rhs; 4730 switch (node_tags[fn_proto]) { 4731 .fn_proto_simple => { 4732 var params: [1]Ast.Node.Index = undefined; 4733 astgen.fnDecl(gz, scope, wip_members, member_node, body, tree.fnProtoSimple(¶ms, fn_proto)) catch |err| switch (err) { 4734 error.OutOfMemory => return error.OutOfMemory, 4735 error.AnalysisFail => {}, 4736 }; 4737 }, 4738 .fn_proto_multi => { 4739 astgen.fnDecl(gz, scope, wip_members, member_node, body, tree.fnProtoMulti(fn_proto)) catch |err| switch (err) { 4740 error.OutOfMemory => return error.OutOfMemory, 4741 error.AnalysisFail => {}, 4742 }; 4743 }, 4744 .fn_proto_one => { 4745 var params: [1]Ast.Node.Index = undefined; 4746 astgen.fnDecl(gz, scope, wip_members, member_node, body, tree.fnProtoOne(¶ms, fn_proto)) catch |err| switch (err) { 4747 error.OutOfMemory => return error.OutOfMemory, 4748 error.AnalysisFail => {}, 4749 }; 4750 }, 4751 .fn_proto => { 4752 astgen.fnDecl(gz, scope, wip_members, member_node, body, tree.fnProto(fn_proto)) catch |err| switch (err) { 4753 error.OutOfMemory => return error.OutOfMemory, 4754 error.AnalysisFail => {}, 4755 }; 4756 }, 4757 else => unreachable, 4758 } 4759 }, 4760 .fn_proto_simple => { 4761 var params: [1]Ast.Node.Index = undefined; 4762 astgen.fnDecl(gz, scope, wip_members, member_node, 0, tree.fnProtoSimple(¶ms, member_node)) catch |err| switch (err) { 4763 error.OutOfMemory => return error.OutOfMemory, 4764 error.AnalysisFail => {}, 4765 }; 4766 }, 4767 .fn_proto_multi => { 4768 astgen.fnDecl(gz, scope, wip_members, member_node, 0, tree.fnProtoMulti(member_node)) catch |err| switch (err) { 4769 error.OutOfMemory => return error.OutOfMemory, 4770 error.AnalysisFail => {}, 4771 }; 4772 }, 4773 .fn_proto_one => { 4774 var params: [1]Ast.Node.Index = undefined; 4775 astgen.fnDecl(gz, scope, wip_members, member_node, 0, tree.fnProtoOne(¶ms, member_node)) catch |err| switch (err) { 4776 error.OutOfMemory => return error.OutOfMemory, 4777 error.AnalysisFail => {}, 4778 }; 4779 }, 4780 .fn_proto => { 4781 astgen.fnDecl(gz, scope, wip_members, member_node, 0, tree.fnProto(member_node)) catch |err| switch (err) { 4782 error.OutOfMemory => return error.OutOfMemory, 4783 error.AnalysisFail => {}, 4784 }; 4785 }, 4786 4787 .global_var_decl => { 4788 astgen.globalVarDecl(gz, scope, wip_members, member_node, tree.globalVarDecl(member_node)) catch |err| switch (err) { 4789 error.OutOfMemory => return error.OutOfMemory, 4790 error.AnalysisFail => {}, 4791 }; 4792 }, 4793 .local_var_decl => { 4794 astgen.globalVarDecl(gz, scope, wip_members, member_node, tree.localVarDecl(member_node)) catch |err| switch (err) { 4795 error.OutOfMemory => return error.OutOfMemory, 4796 error.AnalysisFail => {}, 4797 }; 4798 }, 4799 .simple_var_decl => { 4800 astgen.globalVarDecl(gz, scope, wip_members, member_node, tree.simpleVarDecl(member_node)) catch |err| switch (err) { 4801 error.OutOfMemory => return error.OutOfMemory, 4802 error.AnalysisFail => {}, 4803 }; 4804 }, 4805 .aligned_var_decl => { 4806 astgen.globalVarDecl(gz, scope, wip_members, member_node, tree.alignedVarDecl(member_node)) catch |err| switch (err) { 4807 error.OutOfMemory => return error.OutOfMemory, 4808 error.AnalysisFail => {}, 4809 }; 4810 }, 4811 4812 .@"comptime" => { 4813 astgen.comptimeDecl(gz, scope, wip_members, member_node) catch |err| switch (err) { 4814 error.OutOfMemory => return error.OutOfMemory, 4815 error.AnalysisFail => {}, 4816 }; 4817 }, 4818 .@"usingnamespace" => { 4819 astgen.usingnamespaceDecl(gz, scope, wip_members, member_node) catch |err| switch (err) { 4820 error.OutOfMemory => return error.OutOfMemory, 4821 error.AnalysisFail => {}, 4822 }; 4823 }, 4824 .test_decl => { 4825 astgen.testDecl(gz, scope, wip_members, member_node) catch |err| switch (err) { 4826 error.OutOfMemory => return error.OutOfMemory, 4827 error.AnalysisFail => {}, 4828 }; 4829 }, 4830 else => unreachable, 4831 } 4832 return .decl; 4833 } 4834 4835 fn errorSetDecl(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 4836 const astgen = gz.astgen; 4837 const gpa = astgen.gpa; 4838 const tree = astgen.tree; 4839 const main_tokens = tree.nodes.items(.main_token); 4840 const token_tags = tree.tokens.items(.tag); 4841 4842 const payload_index = try reserveExtra(astgen, @typeInfo(Zir.Inst.ErrorSetDecl).Struct.fields.len); 4843 var fields_len: usize = 0; 4844 { 4845 var idents: std.AutoHashMapUnmanaged(u32, Ast.TokenIndex) = .{}; 4846 defer idents.deinit(gpa); 4847 4848 const error_token = main_tokens[node]; 4849 var tok_i = error_token + 2; 4850 while (true) : (tok_i += 1) { 4851 switch (token_tags[tok_i]) { 4852 .doc_comment, .comma => {}, 4853 .identifier => { 4854 const str_index = try astgen.identAsString(tok_i); 4855 const gop = try idents.getOrPut(gpa, str_index); 4856 if (gop.found_existing) { 4857 const name = try gpa.dupe(u8, mem.span(astgen.nullTerminatedString(str_index))); 4858 defer gpa.free(name); 4859 return astgen.failTokNotes( 4860 tok_i, 4861 "duplicate error set field '{s}'", 4862 .{name}, 4863 &[_]u32{ 4864 try astgen.errNoteTok( 4865 gop.value_ptr.*, 4866 "previous declaration here", 4867 .{}, 4868 ), 4869 }, 4870 ); 4871 } 4872 gop.value_ptr.* = tok_i; 4873 4874 try astgen.extra.ensureUnusedCapacity(gpa, 2); 4875 astgen.extra.appendAssumeCapacity(str_index); 4876 const doc_comment_index = try astgen.docCommentAsString(tok_i); 4877 astgen.extra.appendAssumeCapacity(doc_comment_index); 4878 fields_len += 1; 4879 }, 4880 .r_brace => break, 4881 else => unreachable, 4882 } 4883 } 4884 } 4885 4886 setExtra(astgen, payload_index, Zir.Inst.ErrorSetDecl{ 4887 .fields_len = @intCast(u32, fields_len), 4888 }); 4889 const result = try gz.addPlNodePayloadIndex(.error_set_decl, node, payload_index); 4890 return rvalue(gz, rl, result, node); 4891 } 4892 4893 fn tryExpr( 4894 parent_gz: *GenZir, 4895 scope: *Scope, 4896 rl: ResultLoc, 4897 node: Ast.Node.Index, 4898 operand_node: Ast.Node.Index, 4899 ) InnerError!Zir.Inst.Ref { 4900 const astgen = parent_gz.astgen; 4901 4902 const fn_block = astgen.fn_block orelse { 4903 return astgen.failNode(node, "'try' outside function scope", .{}); 4904 }; 4905 4906 if (parent_gz.in_defer) return astgen.failNode(node, "'try' not allowed inside defer expression", .{}); 4907 4908 const operand_rl: ResultLoc = switch (rl) { 4909 .ref => .ref, 4910 else => .none, 4911 }; 4912 // This could be a pointer or value depending on the `rl` parameter. 4913 const operand = try expr(parent_gz, scope, operand_rl, operand_node); 4914 const is_inline = parent_gz.force_comptime; 4915 const is_inline_bit = @as(u2, @boolToInt(is_inline)); 4916 const is_ptr_bit = @as(u2, @boolToInt(operand_rl == .ref)) << 1; 4917 const block_tag: Zir.Inst.Tag = switch (is_inline_bit | is_ptr_bit) { 4918 0b00 => .@"try", 4919 0b01 => .@"try", 4920 //0b01 => .try_inline, 4921 0b10 => .try_ptr, 4922 0b11 => .try_ptr, 4923 //0b11 => .try_ptr_inline, 4924 }; 4925 const try_inst = try parent_gz.makeBlockInst(block_tag, node); 4926 try parent_gz.instructions.append(astgen.gpa, try_inst); 4927 4928 var else_scope = parent_gz.makeSubBlock(scope); 4929 defer else_scope.unstack(); 4930 4931 const err_tag = switch (rl) { 4932 .ref => Zir.Inst.Tag.err_union_code_ptr, 4933 else => Zir.Inst.Tag.err_union_code, 4934 }; 4935 const err_code = try else_scope.addUnNode(err_tag, operand, node); 4936 try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code }); 4937 _ = try else_scope.addUnNode(.ret_node, err_code, node); 4938 4939 try else_scope.setTryBody(try_inst, operand); 4940 const result = indexToRef(try_inst); 4941 switch (rl) { 4942 .ref => return result, 4943 else => return rvalue(parent_gz, rl, result, node), 4944 } 4945 } 4946 4947 fn orelseCatchExpr( 4948 parent_gz: *GenZir, 4949 scope: *Scope, 4950 rl: ResultLoc, 4951 node: Ast.Node.Index, 4952 lhs: Ast.Node.Index, 4953 cond_op: Zir.Inst.Tag, 4954 unwrap_op: Zir.Inst.Tag, 4955 unwrap_code_op: Zir.Inst.Tag, 4956 rhs: Ast.Node.Index, 4957 payload_token: ?Ast.TokenIndex, 4958 ) InnerError!Zir.Inst.Ref { 4959 const astgen = parent_gz.astgen; 4960 const tree = astgen.tree; 4961 4962 var block_scope = parent_gz.makeSubBlock(scope); 4963 block_scope.setBreakResultLoc(rl); 4964 defer block_scope.unstack(); 4965 4966 const operand_rl: ResultLoc = switch (block_scope.break_result_loc) { 4967 .ref => .ref, 4968 else => .none, 4969 }; 4970 block_scope.break_count += 1; 4971 // This could be a pointer or value depending on the `operand_rl` parameter. 4972 // We cannot use `block_scope.break_result_loc` because that has the bare 4973 // type, whereas this expression has the optional type. Later we make 4974 // up for this fact by calling rvalue on the else branch. 4975 const operand = try reachableExpr(&block_scope, &block_scope.base, operand_rl, lhs, rhs); 4976 const cond = try block_scope.addUnNode(cond_op, operand, node); 4977 const condbr = try block_scope.addCondBr(.condbr, node); 4978 4979 const block = try parent_gz.makeBlockInst(.block, node); 4980 try block_scope.setBlockBody(block); 4981 // block_scope unstacked now, can add new instructions to parent_gz 4982 try parent_gz.instructions.append(astgen.gpa, block); 4983 4984 var then_scope = block_scope.makeSubBlock(scope); 4985 defer then_scope.unstack(); 4986 4987 // This could be a pointer or value depending on `unwrap_op`. 4988 const unwrapped_payload = try then_scope.addUnNode(unwrap_op, operand, node); 4989 const then_result = switch (rl) { 4990 .ref => unwrapped_payload, 4991 else => try rvalue(&then_scope, block_scope.break_result_loc, unwrapped_payload, node), 4992 }; 4993 4994 var else_scope = block_scope.makeSubBlock(scope); 4995 defer else_scope.unstack(); 4996 4997 var err_val_scope: Scope.LocalVal = undefined; 4998 const else_sub_scope = blk: { 4999 const payload = payload_token orelse break :blk &else_scope.base; 5000 if (mem.eql(u8, tree.tokenSlice(payload), "_")) { 5001 return astgen.failTok(payload, "discard of error capture; omit it instead", .{}); 5002 } 5003 const err_name = try astgen.identAsString(payload); 5004 err_val_scope = .{ 5005 .parent = &else_scope.base, 5006 .gen_zir = &else_scope, 5007 .name = err_name, 5008 .inst = try else_scope.addUnNode(unwrap_code_op, operand, node), 5009 .token_src = payload, 5010 .id_cat = .@"capture", 5011 }; 5012 break :blk &err_val_scope.base; 5013 }; 5014 5015 const else_result = try expr(&else_scope, else_sub_scope, block_scope.break_result_loc, rhs); 5016 if (!else_scope.endsWithNoReturn()) { 5017 block_scope.break_count += 1; 5018 } 5019 try checkUsed(parent_gz, &else_scope.base, else_sub_scope); 5020 5021 // We hold off on the break instructions as well as copying the then/else 5022 // instructions into place until we know whether to keep store_to_block_ptr 5023 // instructions or not. 5024 5025 const break_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .break_inline else .@"break"; 5026 return finishThenElseBlock( 5027 parent_gz, 5028 rl, 5029 node, 5030 &block_scope, 5031 &then_scope, 5032 &else_scope, 5033 condbr, 5034 cond, 5035 then_result, 5036 else_result, 5037 block, 5038 block, 5039 break_tag, 5040 ); 5041 } 5042 5043 /// Supports `else_scope` stacked on `then_scope` stacked on `block_scope`. Unstacks `else_scope` then `then_scope`. 5044 fn finishThenElseBlock( 5045 parent_gz: *GenZir, 5046 rl: ResultLoc, 5047 node: Ast.Node.Index, 5048 block_scope: *GenZir, 5049 then_scope: *GenZir, 5050 else_scope: *GenZir, 5051 condbr: Zir.Inst.Index, 5052 cond: Zir.Inst.Ref, 5053 then_result: Zir.Inst.Ref, 5054 else_result: Zir.Inst.Ref, 5055 main_block: Zir.Inst.Index, 5056 then_break_block: Zir.Inst.Index, 5057 break_tag: Zir.Inst.Tag, 5058 ) InnerError!Zir.Inst.Ref { 5059 // We now have enough information to decide whether the result instruction should 5060 // be communicated via result location pointer or break instructions. 5061 const strat = rl.strategy(block_scope); 5062 // else_scope may be stacked on then_scope, so check for no-return on then_scope manually 5063 const tags = parent_gz.astgen.instructions.items(.tag); 5064 const then_slice = then_scope.instructionsSliceUpto(else_scope); 5065 const then_no_return = then_slice.len > 0 and tags[then_slice[then_slice.len - 1]].isNoReturn(); 5066 const else_no_return = else_scope.endsWithNoReturn(); 5067 5068 switch (strat.tag) { 5069 .break_void => { 5070 const then_break = if (!then_no_return) try then_scope.makeBreak(break_tag, then_break_block, .void_value) else 0; 5071 const else_break = if (!else_no_return) try else_scope.makeBreak(break_tag, main_block, .void_value) else 0; 5072 assert(!strat.elide_store_to_block_ptr_instructions); 5073 try setCondBrPayload(condbr, cond, then_scope, then_break, else_scope, else_break); 5074 return indexToRef(main_block); 5075 }, 5076 .break_operand => { 5077 const then_break = if (!then_no_return) try then_scope.makeBreak(break_tag, then_break_block, then_result) else 0; 5078 const else_break = if (else_result == .none) 5079 try else_scope.makeBreak(break_tag, main_block, .void_value) 5080 else if (!else_no_return) 5081 try else_scope.makeBreak(break_tag, main_block, else_result) 5082 else 5083 0; 5084 5085 if (strat.elide_store_to_block_ptr_instructions) { 5086 try setCondBrPayloadElideBlockStorePtr(condbr, cond, then_scope, then_break, else_scope, else_break, block_scope.rl_ptr); 5087 } else { 5088 try setCondBrPayload(condbr, cond, then_scope, then_break, else_scope, else_break); 5089 } 5090 const block_ref = indexToRef(main_block); 5091 switch (rl) { 5092 .ref => return block_ref, 5093 else => return rvalue(parent_gz, rl, block_ref, node), 5094 } 5095 }, 5096 } 5097 } 5098 5099 /// Return whether the identifier names of two tokens are equal. Resolves @"" 5100 /// tokens without allocating. 5101 /// OK in theory it could do it without allocating. This implementation 5102 /// allocates when the @"" form is used. 5103 fn tokenIdentEql(astgen: *AstGen, token1: Ast.TokenIndex, token2: Ast.TokenIndex) !bool { 5104 const ident_name_1 = try astgen.identifierTokenString(token1); 5105 const ident_name_2 = try astgen.identifierTokenString(token2); 5106 return mem.eql(u8, ident_name_1, ident_name_2); 5107 } 5108 5109 fn fieldAccess( 5110 gz: *GenZir, 5111 scope: *Scope, 5112 rl: ResultLoc, 5113 node: Ast.Node.Index, 5114 ) InnerError!Zir.Inst.Ref { 5115 switch (rl) { 5116 .ref => return addFieldAccess(.field_ptr, gz, scope, .ref, node), 5117 else => { 5118 const access = try addFieldAccess(.field_val, gz, scope, .none, node); 5119 return rvalue(gz, rl, access, node); 5120 }, 5121 } 5122 } 5123 5124 fn addFieldAccess( 5125 tag: Zir.Inst.Tag, 5126 gz: *GenZir, 5127 scope: *Scope, 5128 lhs_rl: ResultLoc, 5129 node: Ast.Node.Index, 5130 ) InnerError!Zir.Inst.Ref { 5131 const astgen = gz.astgen; 5132 const tree = astgen.tree; 5133 const main_tokens = tree.nodes.items(.main_token); 5134 const node_datas = tree.nodes.items(.data); 5135 5136 const object_node = node_datas[node].lhs; 5137 const dot_token = main_tokens[node]; 5138 const field_ident = dot_token + 1; 5139 const str_index = try astgen.identAsString(field_ident); 5140 5141 return gz.addPlNode(tag, node, Zir.Inst.Field{ 5142 .lhs = try expr(gz, scope, lhs_rl, object_node), 5143 .field_name_start = str_index, 5144 }); 5145 } 5146 5147 fn arrayAccess( 5148 gz: *GenZir, 5149 scope: *Scope, 5150 rl: ResultLoc, 5151 node: Ast.Node.Index, 5152 ) InnerError!Zir.Inst.Ref { 5153 const astgen = gz.astgen; 5154 const tree = astgen.tree; 5155 const node_datas = tree.nodes.items(.data); 5156 switch (rl) { 5157 .ref => return gz.addPlNode(.elem_ptr_node, node, Zir.Inst.Bin{ 5158 .lhs = try expr(gz, scope, .ref, node_datas[node].lhs), 5159 .rhs = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs), 5160 }), 5161 else => return rvalue(gz, rl, try gz.addPlNode(.elem_val_node, node, Zir.Inst.Bin{ 5162 .lhs = try expr(gz, scope, .none, node_datas[node].lhs), 5163 .rhs = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs), 5164 }), node), 5165 } 5166 } 5167 5168 fn simpleBinOp( 5169 gz: *GenZir, 5170 scope: *Scope, 5171 rl: ResultLoc, 5172 node: Ast.Node.Index, 5173 op_inst_tag: Zir.Inst.Tag, 5174 ) InnerError!Zir.Inst.Ref { 5175 const astgen = gz.astgen; 5176 const tree = astgen.tree; 5177 const node_datas = tree.nodes.items(.data); 5178 5179 const result = try gz.addPlNode(op_inst_tag, node, Zir.Inst.Bin{ 5180 .lhs = try reachableExpr(gz, scope, .none, node_datas[node].lhs, node), 5181 .rhs = try reachableExpr(gz, scope, .none, node_datas[node].rhs, node), 5182 }); 5183 return rvalue(gz, rl, result, node); 5184 } 5185 5186 fn simpleStrTok( 5187 gz: *GenZir, 5188 rl: ResultLoc, 5189 ident_token: Ast.TokenIndex, 5190 node: Ast.Node.Index, 5191 op_inst_tag: Zir.Inst.Tag, 5192 ) InnerError!Zir.Inst.Ref { 5193 const astgen = gz.astgen; 5194 const str_index = try astgen.identAsString(ident_token); 5195 const result = try gz.addStrTok(op_inst_tag, str_index, ident_token); 5196 return rvalue(gz, rl, result, node); 5197 } 5198 5199 fn boolBinOp( 5200 gz: *GenZir, 5201 scope: *Scope, 5202 rl: ResultLoc, 5203 node: Ast.Node.Index, 5204 zir_tag: Zir.Inst.Tag, 5205 ) InnerError!Zir.Inst.Ref { 5206 const astgen = gz.astgen; 5207 const tree = astgen.tree; 5208 const node_datas = tree.nodes.items(.data); 5209 5210 const lhs = try expr(gz, scope, bool_rl, node_datas[node].lhs); 5211 const bool_br = try gz.addBoolBr(zir_tag, lhs); 5212 5213 var rhs_scope = gz.makeSubBlock(scope); 5214 defer rhs_scope.unstack(); 5215 const rhs = try expr(&rhs_scope, &rhs_scope.base, bool_rl, node_datas[node].rhs); 5216 if (!gz.refIsNoReturn(rhs)) { 5217 _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs); 5218 } 5219 try rhs_scope.setBoolBrBody(bool_br); 5220 5221 const block_ref = indexToRef(bool_br); 5222 return rvalue(gz, rl, block_ref, node); 5223 } 5224 5225 fn ifExpr( 5226 parent_gz: *GenZir, 5227 scope: *Scope, 5228 rl: ResultLoc, 5229 node: Ast.Node.Index, 5230 if_full: Ast.full.If, 5231 ) InnerError!Zir.Inst.Ref { 5232 const astgen = parent_gz.astgen; 5233 const tree = astgen.tree; 5234 const token_tags = tree.tokens.items(.tag); 5235 5236 var block_scope = parent_gz.makeSubBlock(scope); 5237 block_scope.setBreakResultLoc(rl); 5238 defer block_scope.unstack(); 5239 5240 const payload_is_ref = if (if_full.payload_token) |payload_token| 5241 token_tags[payload_token] == .asterisk 5242 else 5243 false; 5244 5245 try emitDbgNode(parent_gz, if_full.ast.cond_expr); 5246 const cond: struct { 5247 inst: Zir.Inst.Ref, 5248 bool_bit: Zir.Inst.Ref, 5249 } = c: { 5250 if (if_full.error_token) |_| { 5251 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; 5252 const err_union = try expr(&block_scope, &block_scope.base, cond_rl, if_full.ast.cond_expr); 5253 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err; 5254 break :c .{ 5255 .inst = err_union, 5256 .bool_bit = try block_scope.addUnNode(tag, err_union, node), 5257 }; 5258 } else if (if_full.payload_token) |_| { 5259 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; 5260 const optional = try expr(&block_scope, &block_scope.base, cond_rl, if_full.ast.cond_expr); 5261 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_null_ptr else .is_non_null; 5262 break :c .{ 5263 .inst = optional, 5264 .bool_bit = try block_scope.addUnNode(tag, optional, node), 5265 }; 5266 } else { 5267 const cond = try expr(&block_scope, &block_scope.base, bool_rl, if_full.ast.cond_expr); 5268 break :c .{ 5269 .inst = cond, 5270 .bool_bit = cond, 5271 }; 5272 } 5273 }; 5274 5275 const condbr = try block_scope.addCondBr(.condbr, node); 5276 5277 const block = try parent_gz.makeBlockInst(.block, node); 5278 try block_scope.setBlockBody(block); 5279 // block_scope unstacked now, can add new instructions to parent_gz 5280 try parent_gz.instructions.append(astgen.gpa, block); 5281 5282 var then_scope = parent_gz.makeSubBlock(scope); 5283 defer then_scope.unstack(); 5284 5285 var payload_val_scope: Scope.LocalVal = undefined; 5286 5287 try then_scope.addDbgBlockBegin(); 5288 const then_sub_scope = s: { 5289 if (if_full.error_token != null) { 5290 if (if_full.payload_token) |payload_token| { 5291 const tag: Zir.Inst.Tag = if (payload_is_ref) 5292 .err_union_payload_unsafe_ptr 5293 else 5294 .err_union_payload_unsafe; 5295 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); 5296 const token_name_index = payload_token + @boolToInt(payload_is_ref); 5297 const ident_name = try astgen.identAsString(token_name_index); 5298 const token_name_str = tree.tokenSlice(token_name_index); 5299 if (mem.eql(u8, "_", token_name_str)) 5300 break :s &then_scope.base; 5301 try astgen.detectLocalShadowing(&then_scope.base, ident_name, token_name_index, token_name_str); 5302 payload_val_scope = .{ 5303 .parent = &then_scope.base, 5304 .gen_zir = &then_scope, 5305 .name = ident_name, 5306 .inst = payload_inst, 5307 .token_src = payload_token, 5308 .id_cat = .@"capture", 5309 }; 5310 try then_scope.addDbgVar(.dbg_var_val, ident_name, payload_inst); 5311 break :s &payload_val_scope.base; 5312 } else { 5313 break :s &then_scope.base; 5314 } 5315 } else if (if_full.payload_token) |payload_token| { 5316 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; 5317 const tag: Zir.Inst.Tag = if (payload_is_ref) 5318 .optional_payload_unsafe_ptr 5319 else 5320 .optional_payload_unsafe; 5321 const ident_bytes = tree.tokenSlice(ident_token); 5322 if (mem.eql(u8, "_", ident_bytes)) 5323 break :s &then_scope.base; 5324 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); 5325 const ident_name = try astgen.identAsString(ident_token); 5326 try astgen.detectLocalShadowing(&then_scope.base, ident_name, ident_token, ident_bytes); 5327 payload_val_scope = .{ 5328 .parent = &then_scope.base, 5329 .gen_zir = &then_scope, 5330 .name = ident_name, 5331 .inst = payload_inst, 5332 .token_src = ident_token, 5333 .id_cat = .@"capture", 5334 }; 5335 try then_scope.addDbgVar(.dbg_var_val, ident_name, payload_inst); 5336 break :s &payload_val_scope.base; 5337 } else { 5338 break :s &then_scope.base; 5339 } 5340 }; 5341 5342 const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_loc, if_full.ast.then_expr); 5343 if (!then_scope.endsWithNoReturn()) { 5344 block_scope.break_count += 1; 5345 } 5346 try checkUsed(parent_gz, &then_scope.base, then_sub_scope); 5347 try then_scope.addDbgBlockEnd(); 5348 // We hold off on the break instructions as well as copying the then/else 5349 // instructions into place until we know whether to keep store_to_block_ptr 5350 // instructions or not. 5351 5352 var else_scope = parent_gz.makeSubBlock(scope); 5353 defer else_scope.unstack(); 5354 5355 const else_node = if_full.ast.else_expr; 5356 const else_info: struct { 5357 src: Ast.Node.Index, 5358 result: Zir.Inst.Ref, 5359 } = if (else_node != 0) blk: { 5360 try else_scope.addDbgBlockBegin(); 5361 const sub_scope = s: { 5362 if (if_full.error_token) |error_token| { 5363 const tag: Zir.Inst.Tag = if (payload_is_ref) 5364 .err_union_code_ptr 5365 else 5366 .err_union_code; 5367 const payload_inst = try else_scope.addUnNode(tag, cond.inst, node); 5368 const ident_name = try astgen.identAsString(error_token); 5369 const error_token_str = tree.tokenSlice(error_token); 5370 if (mem.eql(u8, "_", error_token_str)) 5371 break :s &else_scope.base; 5372 try astgen.detectLocalShadowing(&else_scope.base, ident_name, error_token, error_token_str); 5373 payload_val_scope = .{ 5374 .parent = &else_scope.base, 5375 .gen_zir = &else_scope, 5376 .name = ident_name, 5377 .inst = payload_inst, 5378 .token_src = error_token, 5379 .id_cat = .@"capture", 5380 }; 5381 try else_scope.addDbgVar(.dbg_var_val, ident_name, payload_inst); 5382 break :s &payload_val_scope.base; 5383 } else { 5384 break :s &else_scope.base; 5385 } 5386 }; 5387 const e = try expr(&else_scope, sub_scope, block_scope.break_result_loc, else_node); 5388 if (!else_scope.endsWithNoReturn()) { 5389 block_scope.break_count += 1; 5390 } 5391 try checkUsed(parent_gz, &else_scope.base, sub_scope); 5392 try else_scope.addDbgBlockEnd(); 5393 break :blk .{ 5394 .src = else_node, 5395 .result = e, 5396 }; 5397 } else .{ 5398 .src = if_full.ast.then_expr, 5399 .result = .none, 5400 }; 5401 5402 const break_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .break_inline else .@"break"; 5403 return finishThenElseBlock( 5404 parent_gz, 5405 rl, 5406 node, 5407 &block_scope, 5408 &then_scope, 5409 &else_scope, 5410 condbr, 5411 cond.bool_bit, 5412 then_result, 5413 else_info.result, 5414 block, 5415 block, 5416 break_tag, 5417 ); 5418 } 5419 5420 /// Supports `else_scope` stacked on `then_scope`. Unstacks `else_scope` then `then_scope`. 5421 fn setCondBrPayload( 5422 condbr: Zir.Inst.Index, 5423 cond: Zir.Inst.Ref, 5424 then_scope: *GenZir, 5425 then_break: Zir.Inst.Index, 5426 else_scope: *GenZir, 5427 else_break: Zir.Inst.Index, 5428 ) !void { 5429 defer then_scope.unstack(); 5430 defer else_scope.unstack(); 5431 const astgen = then_scope.astgen; 5432 const then_body = then_scope.instructionsSliceUpto(else_scope); 5433 const else_body = else_scope.instructionsSlice(); 5434 const then_body_len = astgen.countBodyLenAfterFixups(then_body) + @boolToInt(then_break != 0); 5435 const else_body_len = astgen.countBodyLenAfterFixups(else_body) + @boolToInt(else_break != 0); 5436 try astgen.extra.ensureUnusedCapacity( 5437 astgen.gpa, 5438 @typeInfo(Zir.Inst.CondBr).Struct.fields.len + then_body_len + else_body_len, 5439 ); 5440 5441 const zir_datas = astgen.instructions.items(.data); 5442 zir_datas[condbr].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{ 5443 .condition = cond, 5444 .then_body_len = then_body_len, 5445 .else_body_len = else_body_len, 5446 }); 5447 astgen.appendBodyWithFixups(then_body); 5448 if (then_break != 0) astgen.extra.appendAssumeCapacity(then_break); 5449 astgen.appendBodyWithFixups(else_body); 5450 if (else_break != 0) astgen.extra.appendAssumeCapacity(else_break); 5451 } 5452 5453 /// Supports `else_scope` stacked on `then_scope`. Unstacks `else_scope` then `then_scope`. 5454 fn setCondBrPayloadElideBlockStorePtr( 5455 condbr: Zir.Inst.Index, 5456 cond: Zir.Inst.Ref, 5457 then_scope: *GenZir, 5458 then_break: Zir.Inst.Index, 5459 else_scope: *GenZir, 5460 else_break: Zir.Inst.Index, 5461 block_ptr: Zir.Inst.Ref, 5462 ) !void { 5463 defer then_scope.unstack(); 5464 defer else_scope.unstack(); 5465 const astgen = then_scope.astgen; 5466 const then_body = then_scope.instructionsSliceUpto(else_scope); 5467 const else_body = else_scope.instructionsSlice(); 5468 const has_then_break = then_break != 0; 5469 const has_else_break = else_break != 0; 5470 const then_body_len = astgen.countBodyLenAfterFixups(then_body) + @boolToInt(has_then_break); 5471 const else_body_len = astgen.countBodyLenAfterFixups(else_body) + @boolToInt(has_else_break); 5472 try astgen.extra.ensureUnusedCapacity( 5473 astgen.gpa, 5474 @typeInfo(Zir.Inst.CondBr).Struct.fields.len + then_body_len + else_body_len, 5475 ); 5476 5477 const zir_tags = astgen.instructions.items(.tag); 5478 const zir_datas = astgen.instructions.items(.data); 5479 5480 const condbr_pl = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{ 5481 .condition = cond, 5482 .then_body_len = then_body_len, 5483 .else_body_len = else_body_len, 5484 }); 5485 zir_datas[condbr].pl_node.payload_index = condbr_pl; 5486 const then_body_len_index = condbr_pl + 1; 5487 const else_body_len_index = condbr_pl + 2; 5488 5489 // The break instructions need to have their operands coerced if the 5490 // switch's result location is a `ty`. In this case we overwrite the 5491 // `store_to_block_ptr` instruction with an `as` instruction and repurpose 5492 // it as the break operand. 5493 // This corresponds to similar code in `labeledBlockExpr`. 5494 for (then_body) |src_inst| { 5495 if (zir_tags[src_inst] == .store_to_block_ptr and 5496 zir_datas[src_inst].bin.lhs == block_ptr) 5497 { 5498 if (then_scope.rl_ty_inst != .none and has_then_break) { 5499 zir_tags[src_inst] = .as; 5500 zir_datas[src_inst].bin = .{ 5501 .lhs = then_scope.rl_ty_inst, 5502 .rhs = zir_datas[then_break].@"break".operand, 5503 }; 5504 zir_datas[then_break].@"break".operand = indexToRef(src_inst); 5505 } else { 5506 astgen.extra.items[then_body_len_index] -= 1; 5507 continue; 5508 } 5509 } 5510 appendPossiblyRefdBodyInst(astgen, &astgen.extra, src_inst); 5511 } 5512 if (has_then_break) astgen.extra.appendAssumeCapacity(then_break); 5513 5514 for (else_body) |src_inst| { 5515 if (zir_tags[src_inst] == .store_to_block_ptr and 5516 zir_datas[src_inst].bin.lhs == block_ptr) 5517 { 5518 if (else_scope.rl_ty_inst != .none and has_else_break) { 5519 zir_tags[src_inst] = .as; 5520 zir_datas[src_inst].bin = .{ 5521 .lhs = else_scope.rl_ty_inst, 5522 .rhs = zir_datas[else_break].@"break".operand, 5523 }; 5524 zir_datas[else_break].@"break".operand = indexToRef(src_inst); 5525 } else { 5526 astgen.extra.items[else_body_len_index] -= 1; 5527 continue; 5528 } 5529 } 5530 appendPossiblyRefdBodyInst(astgen, &astgen.extra, src_inst); 5531 } 5532 if (has_else_break) astgen.extra.appendAssumeCapacity(else_break); 5533 } 5534 5535 fn whileExpr( 5536 parent_gz: *GenZir, 5537 scope: *Scope, 5538 rl: ResultLoc, 5539 node: Ast.Node.Index, 5540 while_full: Ast.full.While, 5541 ) InnerError!Zir.Inst.Ref { 5542 const astgen = parent_gz.astgen; 5543 const tree = astgen.tree; 5544 const token_tags = tree.tokens.items(.tag); 5545 5546 if (while_full.label_token) |label_token| { 5547 try astgen.checkLabelRedefinition(scope, label_token); 5548 } 5549 5550 const is_inline = parent_gz.force_comptime or while_full.inline_token != null; 5551 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop; 5552 const loop_block = try parent_gz.makeBlockInst(loop_tag, node); 5553 try parent_gz.instructions.append(astgen.gpa, loop_block); 5554 5555 var loop_scope = parent_gz.makeSubBlock(scope); 5556 loop_scope.is_inline = is_inline; 5557 loop_scope.setBreakResultLoc(rl); 5558 defer loop_scope.unstack(); 5559 defer loop_scope.labeled_breaks.deinit(astgen.gpa); 5560 5561 var continue_scope = parent_gz.makeSubBlock(&loop_scope.base); 5562 defer continue_scope.unstack(); 5563 5564 const payload_is_ref = if (while_full.payload_token) |payload_token| 5565 token_tags[payload_token] == .asterisk 5566 else 5567 false; 5568 5569 try emitDbgNode(parent_gz, while_full.ast.cond_expr); 5570 const cond: struct { 5571 inst: Zir.Inst.Ref, 5572 bool_bit: Zir.Inst.Ref, 5573 } = c: { 5574 if (while_full.error_token) |_| { 5575 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; 5576 const err_union = try expr(&continue_scope, &continue_scope.base, cond_rl, while_full.ast.cond_expr); 5577 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err; 5578 break :c .{ 5579 .inst = err_union, 5580 .bool_bit = try continue_scope.addUnNode(tag, err_union, node), 5581 }; 5582 } else if (while_full.payload_token) |_| { 5583 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; 5584 const optional = try expr(&continue_scope, &continue_scope.base, cond_rl, while_full.ast.cond_expr); 5585 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_null_ptr else .is_non_null; 5586 break :c .{ 5587 .inst = optional, 5588 .bool_bit = try continue_scope.addUnNode(tag, optional, node), 5589 }; 5590 } else { 5591 const cond = try expr(&continue_scope, &continue_scope.base, bool_rl, while_full.ast.cond_expr); 5592 break :c .{ 5593 .inst = cond, 5594 .bool_bit = cond, 5595 }; 5596 } 5597 }; 5598 5599 const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr; 5600 const condbr = try continue_scope.addCondBr(condbr_tag, node); 5601 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block; 5602 const cond_block = try loop_scope.makeBlockInst(block_tag, node); 5603 try continue_scope.setBlockBody(cond_block); 5604 // continue_scope unstacked now, can add new instructions to loop_scope 5605 try loop_scope.instructions.append(astgen.gpa, cond_block); 5606 5607 // make scope now but don't stack on parent_gz until loop_scope 5608 // gets unstacked after cont_expr is emitted and added below 5609 var then_scope = parent_gz.makeSubBlock(&continue_scope.base); 5610 then_scope.markAsLoopBody(loop_scope); 5611 then_scope.instructions_top = GenZir.unstacked_top; 5612 defer then_scope.unstack(); 5613 5614 var dbg_var_name: ?u32 = null; 5615 var dbg_var_inst: Zir.Inst.Ref = undefined; 5616 var payload_inst: Zir.Inst.Index = 0; 5617 var payload_val_scope: Scope.LocalVal = undefined; 5618 const then_sub_scope = s: { 5619 if (while_full.error_token != null) { 5620 if (while_full.payload_token) |payload_token| { 5621 const tag: Zir.Inst.Tag = if (payload_is_ref) 5622 .err_union_payload_unsafe_ptr 5623 else 5624 .err_union_payload_unsafe; 5625 // will add this instruction to then_scope.instructions below 5626 payload_inst = try then_scope.makeUnNode(tag, cond.inst, node); 5627 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; 5628 const ident_bytes = tree.tokenSlice(ident_token); 5629 if (mem.eql(u8, "_", ident_bytes)) 5630 break :s &then_scope.base; 5631 const payload_name_loc = payload_token + @boolToInt(payload_is_ref); 5632 const ident_name = try astgen.identAsString(payload_name_loc); 5633 try astgen.detectLocalShadowing(&then_scope.base, ident_name, payload_name_loc, ident_bytes); 5634 payload_val_scope = .{ 5635 .parent = &then_scope.base, 5636 .gen_zir = &then_scope, 5637 .name = ident_name, 5638 .inst = indexToRef(payload_inst), 5639 .token_src = payload_token, 5640 .id_cat = .@"capture", 5641 }; 5642 dbg_var_name = ident_name; 5643 dbg_var_inst = indexToRef(payload_inst); 5644 break :s &payload_val_scope.base; 5645 } else { 5646 break :s &then_scope.base; 5647 } 5648 } else if (while_full.payload_token) |payload_token| { 5649 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; 5650 const tag: Zir.Inst.Tag = if (payload_is_ref) 5651 .optional_payload_unsafe_ptr 5652 else 5653 .optional_payload_unsafe; 5654 // will add this instruction to then_scope.instructions below 5655 payload_inst = try then_scope.makeUnNode(tag, cond.inst, node); 5656 const ident_name = try astgen.identAsString(ident_token); 5657 const ident_bytes = tree.tokenSlice(ident_token); 5658 if (mem.eql(u8, "_", ident_bytes)) 5659 break :s &then_scope.base; 5660 try astgen.detectLocalShadowing(&then_scope.base, ident_name, ident_token, ident_bytes); 5661 payload_val_scope = .{ 5662 .parent = &then_scope.base, 5663 .gen_zir = &then_scope, 5664 .name = ident_name, 5665 .inst = indexToRef(payload_inst), 5666 .token_src = ident_token, 5667 .id_cat = .@"capture", 5668 }; 5669 dbg_var_name = ident_name; 5670 dbg_var_inst = indexToRef(payload_inst); 5671 break :s &payload_val_scope.base; 5672 } else { 5673 break :s &then_scope.base; 5674 } 5675 }; 5676 5677 // This code could be improved to avoid emitting the continue expr when there 5678 // are no jumps to it. This happens when the last statement of a while body is noreturn 5679 // and there are no `continue` statements. 5680 // Tracking issue: https://github.com/ziglang/zig/issues/9185 5681 try then_scope.addDbgBlockBegin(); 5682 if (dbg_var_name) |some| { 5683 try then_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst); 5684 } 5685 if (while_full.ast.cont_expr != 0) { 5686 _ = try unusedResultExpr(&loop_scope, then_sub_scope, while_full.ast.cont_expr); 5687 } 5688 try then_scope.addDbgBlockEnd(); 5689 const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; 5690 _ = try loop_scope.addNode(repeat_tag, node); 5691 5692 try loop_scope.setBlockBody(loop_block); 5693 loop_scope.break_block = loop_block; 5694 loop_scope.continue_block = cond_block; 5695 if (while_full.label_token) |label_token| { 5696 loop_scope.label = @as(?GenZir.Label, GenZir.Label{ 5697 .token = label_token, 5698 .block_inst = loop_block, 5699 }); 5700 } 5701 5702 // done adding instructions to loop_scope, can now stack then_scope 5703 then_scope.instructions_top = then_scope.instructions.items.len; 5704 5705 if (payload_inst != 0) try then_scope.instructions.append(astgen.gpa, payload_inst); 5706 try then_scope.addDbgBlockBegin(); 5707 if (dbg_var_name) |some| { 5708 try then_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst); 5709 } 5710 const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr); 5711 try checkUsed(parent_gz, &then_scope.base, then_sub_scope); 5712 try then_scope.addDbgBlockEnd(); 5713 5714 var else_scope = parent_gz.makeSubBlock(&continue_scope.base); 5715 defer else_scope.unstack(); 5716 5717 const else_node = while_full.ast.else_expr; 5718 const else_info: struct { 5719 src: Ast.Node.Index, 5720 result: Zir.Inst.Ref, 5721 } = if (else_node != 0) blk: { 5722 try else_scope.addDbgBlockBegin(); 5723 const sub_scope = s: { 5724 if (while_full.error_token) |error_token| { 5725 const tag: Zir.Inst.Tag = if (payload_is_ref) 5726 .err_union_code_ptr 5727 else 5728 .err_union_code; 5729 const else_payload_inst = try else_scope.addUnNode(tag, cond.inst, node); 5730 const ident_name = try astgen.identAsString(error_token); 5731 const ident_bytes = tree.tokenSlice(error_token); 5732 if (mem.eql(u8, ident_bytes, "_")) 5733 break :s &else_scope.base; 5734 try astgen.detectLocalShadowing(&else_scope.base, ident_name, error_token, ident_bytes); 5735 payload_val_scope = .{ 5736 .parent = &else_scope.base, 5737 .gen_zir = &else_scope, 5738 .name = ident_name, 5739 .inst = else_payload_inst, 5740 .token_src = error_token, 5741 .id_cat = .@"capture", 5742 }; 5743 try else_scope.addDbgVar(.dbg_var_val, ident_name, else_payload_inst); 5744 break :s &payload_val_scope.base; 5745 } else { 5746 break :s &else_scope.base; 5747 } 5748 }; 5749 const e = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node); 5750 if (!else_scope.endsWithNoReturn()) { 5751 loop_scope.break_count += 1; 5752 } 5753 try checkUsed(parent_gz, &else_scope.base, sub_scope); 5754 try else_scope.addDbgBlockEnd(); 5755 break :blk .{ 5756 .src = else_node, 5757 .result = e, 5758 }; 5759 } else .{ 5760 .src = while_full.ast.then_expr, 5761 .result = .none, 5762 }; 5763 5764 if (loop_scope.label) |some| { 5765 if (!some.used) { 5766 try astgen.appendErrorTok(some.token, "unused while loop label", .{}); 5767 } 5768 } 5769 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; 5770 return finishThenElseBlock( 5771 parent_gz, 5772 rl, 5773 node, 5774 &loop_scope, 5775 &then_scope, 5776 &else_scope, 5777 condbr, 5778 cond.bool_bit, 5779 then_result, 5780 else_info.result, 5781 loop_block, 5782 cond_block, 5783 break_tag, 5784 ); 5785 } 5786 5787 fn forExpr( 5788 parent_gz: *GenZir, 5789 scope: *Scope, 5790 rl: ResultLoc, 5791 node: Ast.Node.Index, 5792 for_full: Ast.full.While, 5793 ) InnerError!Zir.Inst.Ref { 5794 const astgen = parent_gz.astgen; 5795 5796 if (for_full.label_token) |label_token| { 5797 try astgen.checkLabelRedefinition(scope, label_token); 5798 } 5799 5800 // Set up variables and constants. 5801 const is_inline = parent_gz.force_comptime or for_full.inline_token != null; 5802 const tree = astgen.tree; 5803 const token_tags = tree.tokens.items(.tag); 5804 5805 const payload_is_ref = if (for_full.payload_token) |payload_token| 5806 token_tags[payload_token] == .asterisk 5807 else 5808 false; 5809 5810 try emitDbgNode(parent_gz, for_full.ast.cond_expr); 5811 5812 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; 5813 const array_ptr = try expr(parent_gz, scope, cond_rl, for_full.ast.cond_expr); 5814 const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr); 5815 5816 const index_ptr = blk: { 5817 const alloc_tag: Zir.Inst.Tag = if (is_inline) .alloc_comptime_mut else .alloc; 5818 const index_ptr = try parent_gz.addUnNode(alloc_tag, .usize_type, node); 5819 // initialize to zero 5820 _ = try parent_gz.addBin(.store, index_ptr, .zero_usize); 5821 break :blk index_ptr; 5822 }; 5823 5824 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop; 5825 const loop_block = try parent_gz.makeBlockInst(loop_tag, node); 5826 try parent_gz.instructions.append(astgen.gpa, loop_block); 5827 5828 var loop_scope = parent_gz.makeSubBlock(scope); 5829 loop_scope.is_inline = is_inline; 5830 loop_scope.setBreakResultLoc(rl); 5831 defer loop_scope.unstack(); 5832 defer loop_scope.labeled_breaks.deinit(astgen.gpa); 5833 5834 var cond_scope = parent_gz.makeSubBlock(&loop_scope.base); 5835 defer cond_scope.unstack(); 5836 5837 // check condition i < array_expr.len 5838 const index = try cond_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr); 5839 const cond = try cond_scope.addPlNode(.cmp_lt, for_full.ast.cond_expr, Zir.Inst.Bin{ 5840 .lhs = index, 5841 .rhs = len, 5842 }); 5843 5844 const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr; 5845 const condbr = try cond_scope.addCondBr(condbr_tag, node); 5846 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block; 5847 const cond_block = try loop_scope.makeBlockInst(block_tag, node); 5848 try cond_scope.setBlockBody(cond_block); 5849 // cond_block unstacked now, can add new instructions to loop_scope 5850 try loop_scope.instructions.append(astgen.gpa, cond_block); 5851 5852 // Increment the index variable. 5853 const index_2 = try loop_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr); 5854 const index_plus_one = try loop_scope.addPlNode(.add, node, Zir.Inst.Bin{ 5855 .lhs = index_2, 5856 .rhs = .one_usize, 5857 }); 5858 _ = try loop_scope.addBin(.store, index_ptr, index_plus_one); 5859 const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; 5860 _ = try loop_scope.addNode(repeat_tag, node); 5861 5862 try loop_scope.setBlockBody(loop_block); 5863 loop_scope.break_block = loop_block; 5864 loop_scope.continue_block = cond_block; 5865 if (for_full.label_token) |label_token| { 5866 loop_scope.label = @as(?GenZir.Label, GenZir.Label{ 5867 .token = label_token, 5868 .block_inst = loop_block, 5869 }); 5870 } 5871 5872 var then_scope = parent_gz.makeSubBlock(&cond_scope.base); 5873 then_scope.markAsLoopBody(loop_scope); 5874 defer then_scope.unstack(); 5875 5876 try then_scope.addDbgBlockBegin(); 5877 var payload_val_scope: Scope.LocalVal = undefined; 5878 var index_scope: Scope.LocalPtr = undefined; 5879 const then_sub_scope = blk: { 5880 const payload_token = for_full.payload_token.?; 5881 const ident = if (token_tags[payload_token] == .asterisk) 5882 payload_token + 1 5883 else 5884 payload_token; 5885 const is_ptr = ident != payload_token; 5886 const value_name = tree.tokenSlice(ident); 5887 var payload_sub_scope: *Scope = undefined; 5888 if (!mem.eql(u8, value_name, "_")) { 5889 const name_str_index = try astgen.identAsString(ident); 5890 const tag: Zir.Inst.Tag = if (is_ptr) .elem_ptr else .elem_val; 5891 const payload_inst = try then_scope.addPlNode(tag, for_full.ast.cond_expr, Zir.Inst.Bin{ 5892 .lhs = array_ptr, 5893 .rhs = index, 5894 }); 5895 try astgen.detectLocalShadowing(&then_scope.base, name_str_index, ident, value_name); 5896 payload_val_scope = .{ 5897 .parent = &then_scope.base, 5898 .gen_zir = &then_scope, 5899 .name = name_str_index, 5900 .inst = payload_inst, 5901 .token_src = ident, 5902 .id_cat = .@"capture", 5903 }; 5904 try then_scope.addDbgVar(.dbg_var_val, name_str_index, payload_inst); 5905 payload_sub_scope = &payload_val_scope.base; 5906 } else if (is_ptr) { 5907 return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{}); 5908 } else { 5909 payload_sub_scope = &then_scope.base; 5910 } 5911 5912 const index_token = if (token_tags[ident + 1] == .comma) 5913 ident + 2 5914 else 5915 break :blk payload_sub_scope; 5916 const token_bytes = tree.tokenSlice(index_token); 5917 if (mem.eql(u8, token_bytes, "_")) { 5918 return astgen.failTok(index_token, "discard of index capture; omit it instead", .{}); 5919 } 5920 const index_name = try astgen.identAsString(index_token); 5921 try astgen.detectLocalShadowing(payload_sub_scope, index_name, index_token, token_bytes); 5922 index_scope = .{ 5923 .parent = payload_sub_scope, 5924 .gen_zir = &then_scope, 5925 .name = index_name, 5926 .ptr = index_ptr, 5927 .token_src = index_token, 5928 .maybe_comptime = is_inline, 5929 .id_cat = .@"loop index capture", 5930 }; 5931 try then_scope.addDbgVar(.dbg_var_val, index_name, index_ptr); 5932 break :blk &index_scope.base; 5933 }; 5934 5935 const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr); 5936 try checkUsed(parent_gz, &then_scope.base, then_sub_scope); 5937 try then_scope.addDbgBlockEnd(); 5938 5939 var else_scope = parent_gz.makeSubBlock(&cond_scope.base); 5940 defer else_scope.unstack(); 5941 5942 const else_node = for_full.ast.else_expr; 5943 const else_info: struct { 5944 src: Ast.Node.Index, 5945 result: Zir.Inst.Ref, 5946 } = if (else_node != 0) blk: { 5947 const sub_scope = &else_scope.base; 5948 const else_result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node); 5949 if (!else_scope.endsWithNoReturn()) { 5950 loop_scope.break_count += 1; 5951 } 5952 break :blk .{ 5953 .src = else_node, 5954 .result = else_result, 5955 }; 5956 } else .{ 5957 .src = for_full.ast.then_expr, 5958 .result = .none, 5959 }; 5960 5961 if (loop_scope.label) |some| { 5962 if (!some.used) { 5963 try astgen.appendErrorTok(some.token, "unused for loop label", .{}); 5964 } 5965 } 5966 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; 5967 return finishThenElseBlock( 5968 parent_gz, 5969 rl, 5970 node, 5971 &loop_scope, 5972 &then_scope, 5973 &else_scope, 5974 condbr, 5975 cond, 5976 then_result, 5977 else_info.result, 5978 loop_block, 5979 cond_block, 5980 break_tag, 5981 ); 5982 } 5983 5984 fn switchExpr( 5985 parent_gz: *GenZir, 5986 scope: *Scope, 5987 rl: ResultLoc, 5988 switch_node: Ast.Node.Index, 5989 ) InnerError!Zir.Inst.Ref { 5990 const astgen = parent_gz.astgen; 5991 const gpa = astgen.gpa; 5992 const tree = astgen.tree; 5993 const node_datas = tree.nodes.items(.data); 5994 const node_tags = tree.nodes.items(.tag); 5995 const main_tokens = tree.nodes.items(.main_token); 5996 const token_tags = tree.tokens.items(.tag); 5997 const operand_node = node_datas[switch_node].lhs; 5998 const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange); 5999 const case_nodes = tree.extra_data[extra.start..extra.end]; 6000 6001 // We perform two passes over the AST. This first pass is to collect information 6002 // for the following variables, make note of the special prong AST node index, 6003 // and bail out with a compile error if there are multiple special prongs present. 6004 var any_payload_is_ref = false; 6005 var scalar_cases_len: u32 = 0; 6006 var multi_cases_len: u32 = 0; 6007 var special_prong: Zir.SpecialProng = .none; 6008 var special_node: Ast.Node.Index = 0; 6009 var else_src: ?Ast.TokenIndex = null; 6010 var underscore_src: ?Ast.TokenIndex = null; 6011 for (case_nodes) |case_node| { 6012 const case = switch (node_tags[case_node]) { 6013 .switch_case_one => tree.switchCaseOne(case_node), 6014 .switch_case => tree.switchCase(case_node), 6015 else => unreachable, 6016 }; 6017 if (case.payload_token) |payload_token| { 6018 if (token_tags[payload_token] == .asterisk) { 6019 any_payload_is_ref = true; 6020 } 6021 } 6022 // Check for else/`_` prong. 6023 if (case.ast.values.len == 0) { 6024 const case_src = case.ast.arrow_token - 1; 6025 if (else_src) |src| { 6026 return astgen.failTokNotes( 6027 case_src, 6028 "multiple else prongs in switch expression", 6029 .{}, 6030 &[_]u32{ 6031 try astgen.errNoteTok( 6032 src, 6033 "previous else prong here", 6034 .{}, 6035 ), 6036 }, 6037 ); 6038 } else if (underscore_src) |some_underscore| { 6039 return astgen.failNodeNotes( 6040 switch_node, 6041 "else and '_' prong in switch expression", 6042 .{}, 6043 &[_]u32{ 6044 try astgen.errNoteTok( 6045 case_src, 6046 "else prong here", 6047 .{}, 6048 ), 6049 try astgen.errNoteTok( 6050 some_underscore, 6051 "'_' prong here", 6052 .{}, 6053 ), 6054 }, 6055 ); 6056 } 6057 special_node = case_node; 6058 special_prong = .@"else"; 6059 else_src = case_src; 6060 continue; 6061 } else if (case.ast.values.len == 1 and 6062 node_tags[case.ast.values[0]] == .identifier and 6063 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_")) 6064 { 6065 const case_src = case.ast.arrow_token - 1; 6066 if (underscore_src) |src| { 6067 return astgen.failTokNotes( 6068 case_src, 6069 "multiple '_' prongs in switch expression", 6070 .{}, 6071 &[_]u32{ 6072 try astgen.errNoteTok( 6073 src, 6074 "previous '_' prong here", 6075 .{}, 6076 ), 6077 }, 6078 ); 6079 } else if (else_src) |some_else| { 6080 return astgen.failNodeNotes( 6081 switch_node, 6082 "else and '_' prong in switch expression", 6083 .{}, 6084 &[_]u32{ 6085 try astgen.errNoteTok( 6086 some_else, 6087 "else prong here", 6088 .{}, 6089 ), 6090 try astgen.errNoteTok( 6091 case_src, 6092 "'_' prong here", 6093 .{}, 6094 ), 6095 }, 6096 ); 6097 } 6098 special_node = case_node; 6099 special_prong = .under; 6100 underscore_src = case_src; 6101 continue; 6102 } 6103 6104 if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] != .switch_range) { 6105 scalar_cases_len += 1; 6106 } else { 6107 multi_cases_len += 1; 6108 } 6109 } 6110 6111 const operand_rl: ResultLoc = if (any_payload_is_ref) .ref else .none; 6112 const raw_operand = try expr(parent_gz, scope, operand_rl, operand_node); 6113 const cond_tag: Zir.Inst.Tag = if (any_payload_is_ref) .switch_cond_ref else .switch_cond; 6114 const cond = try parent_gz.addUnNode(cond_tag, raw_operand, operand_node); 6115 // We need the type of the operand to use as the result location for all the prong items. 6116 const cond_ty_inst = try parent_gz.addUnNode(.typeof, cond, operand_node); 6117 const item_rl: ResultLoc = .{ .ty = cond_ty_inst }; 6118 6119 // This contains the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti, 6120 // except the first cases_nodes.len slots are a table that indexes payloads later in the array, with 6121 // the special case index coming first, then scalar_case_len indexes, then multi_cases_len indexes 6122 const payloads = &astgen.scratch; 6123 const scratch_top = astgen.scratch.items.len; 6124 const case_table_start = scratch_top; 6125 const scalar_case_table = case_table_start + @boolToInt(special_prong != .none); 6126 const multi_case_table = scalar_case_table + scalar_cases_len; 6127 const case_table_end = multi_case_table + multi_cases_len; 6128 try astgen.scratch.resize(gpa, case_table_end); 6129 defer astgen.scratch.items.len = scratch_top; 6130 6131 var block_scope = parent_gz.makeSubBlock(scope); 6132 // block_scope not used for collecting instructions 6133 block_scope.instructions_top = GenZir.unstacked_top; 6134 block_scope.setBreakResultLoc(rl); 6135 6136 // This gets added to the parent block later, after the item expressions. 6137 const switch_block = try parent_gz.makeBlockInst(.switch_block, switch_node); 6138 6139 // We re-use this same scope for all cases, including the special prong, if any. 6140 var case_scope = parent_gz.makeSubBlock(&block_scope.base); 6141 case_scope.instructions_top = GenZir.unstacked_top; 6142 6143 // In this pass we generate all the item and prong expressions. 6144 var multi_case_index: u32 = 0; 6145 var scalar_case_index: u32 = 0; 6146 for (case_nodes) |case_node| { 6147 const case = switch (node_tags[case_node]) { 6148 .switch_case_one => tree.switchCaseOne(case_node), 6149 .switch_case => tree.switchCase(case_node), 6150 else => unreachable, 6151 }; 6152 6153 const is_multi_case = case.ast.values.len > 1 or 6154 (case.ast.values.len == 1 and node_tags[case.ast.values[0]] == .switch_range); 6155 6156 var dbg_var_name: ?u32 = null; 6157 var dbg_var_inst: Zir.Inst.Ref = undefined; 6158 var capture_inst: Zir.Inst.Index = 0; 6159 var capture_val_scope: Scope.LocalVal = undefined; 6160 const sub_scope = blk: { 6161 const payload_token = case.payload_token orelse break :blk &case_scope.base; 6162 const ident = if (token_tags[payload_token] == .asterisk) 6163 payload_token + 1 6164 else 6165 payload_token; 6166 const is_ptr = ident != payload_token; 6167 if (mem.eql(u8, tree.tokenSlice(ident), "_")) { 6168 if (is_ptr) { 6169 return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{}); 6170 } 6171 break :blk &case_scope.base; 6172 } 6173 if (case_node == special_node) { 6174 const capture_tag: Zir.Inst.Tag = if (is_ptr) 6175 .switch_capture_ref 6176 else 6177 .switch_capture; 6178 capture_inst = @intCast(Zir.Inst.Index, astgen.instructions.len); 6179 try astgen.instructions.append(gpa, .{ 6180 .tag = capture_tag, 6181 .data = .{ 6182 .switch_capture = .{ 6183 .switch_inst = switch_block, 6184 // Max int communicates that this is the else/underscore prong. 6185 .prong_index = std.math.maxInt(u32), 6186 }, 6187 }, 6188 }); 6189 } else { 6190 const is_multi_case_bits: u2 = @boolToInt(is_multi_case); 6191 const is_ptr_bits: u2 = @boolToInt(is_ptr); 6192 const capture_tag: Zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) { 6193 0b00 => .switch_capture, 6194 0b01 => .switch_capture_ref, 6195 0b10 => .switch_capture_multi, 6196 0b11 => .switch_capture_multi_ref, 6197 }; 6198 const capture_index = if (is_multi_case) multi_case_index else scalar_case_index; 6199 capture_inst = @intCast(Zir.Inst.Index, astgen.instructions.len); 6200 try astgen.instructions.append(gpa, .{ 6201 .tag = capture_tag, 6202 .data = .{ .switch_capture = .{ 6203 .switch_inst = switch_block, 6204 .prong_index = capture_index, 6205 } }, 6206 }); 6207 } 6208 const capture_name = try astgen.identAsString(ident); 6209 capture_val_scope = .{ 6210 .parent = &case_scope.base, 6211 .gen_zir = &case_scope, 6212 .name = capture_name, 6213 .inst = indexToRef(capture_inst), 6214 .token_src = payload_token, 6215 .id_cat = .@"capture", 6216 }; 6217 dbg_var_name = capture_name; 6218 dbg_var_inst = indexToRef(capture_inst); 6219 break :blk &capture_val_scope.base; 6220 }; 6221 6222 const header_index = @intCast(u32, payloads.items.len); 6223 const body_len_index = if (is_multi_case) blk: { 6224 payloads.items[multi_case_table + multi_case_index] = header_index; 6225 multi_case_index += 1; 6226 try payloads.resize(gpa, header_index + 3); // items_len, ranges_len, body_len 6227 6228 // items 6229 var items_len: u32 = 0; 6230 for (case.ast.values) |item_node| { 6231 if (node_tags[item_node] == .switch_range) continue; 6232 items_len += 1; 6233 6234 const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node); 6235 try payloads.append(gpa, @enumToInt(item_inst)); 6236 } 6237 6238 // ranges 6239 var ranges_len: u32 = 0; 6240 for (case.ast.values) |range| { 6241 if (node_tags[range] != .switch_range) continue; 6242 ranges_len += 1; 6243 6244 const first = try comptimeExpr(parent_gz, scope, item_rl, node_datas[range].lhs); 6245 const last = try comptimeExpr(parent_gz, scope, item_rl, node_datas[range].rhs); 6246 try payloads.appendSlice(gpa, &[_]u32{ 6247 @enumToInt(first), @enumToInt(last), 6248 }); 6249 } 6250 6251 payloads.items[header_index] = items_len; 6252 payloads.items[header_index + 1] = ranges_len; 6253 break :blk header_index + 2; 6254 } else if (case_node == special_node) blk: { 6255 payloads.items[case_table_start] = header_index; 6256 try payloads.resize(gpa, header_index + 1); // body_len 6257 break :blk header_index; 6258 } else blk: { 6259 payloads.items[scalar_case_table + scalar_case_index] = header_index; 6260 scalar_case_index += 1; 6261 try payloads.resize(gpa, header_index + 2); // item, body_len 6262 const item_node = case.ast.values[0]; 6263 const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node); 6264 payloads.items[header_index] = @enumToInt(item_inst); 6265 break :blk header_index + 1; 6266 }; 6267 6268 { 6269 // temporarily stack case_scope on parent_gz 6270 case_scope.instructions_top = parent_gz.instructions.items.len; 6271 defer case_scope.unstack(); 6272 6273 if (capture_inst != 0) try case_scope.instructions.append(gpa, capture_inst); 6274 try case_scope.addDbgBlockBegin(); 6275 if (dbg_var_name) |some| { 6276 try case_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst); 6277 } 6278 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); 6279 try checkUsed(parent_gz, &case_scope.base, sub_scope); 6280 try case_scope.addDbgBlockEnd(); 6281 if (!parent_gz.refIsNoReturn(case_result)) { 6282 block_scope.break_count += 1; 6283 _ = try case_scope.addBreak(.@"break", switch_block, case_result); 6284 } 6285 6286 const case_slice = case_scope.instructionsSlice(); 6287 const body_len = astgen.countBodyLenAfterFixups(case_slice); 6288 try payloads.ensureUnusedCapacity(gpa, body_len); 6289 payloads.items[body_len_index] = body_len; 6290 appendBodyWithFixupsArrayList(astgen, payloads, case_slice); 6291 } 6292 } 6293 // Now that the item expressions are generated we can add this. 6294 try parent_gz.instructions.append(gpa, switch_block); 6295 6296 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.SwitchBlock).Struct.fields.len + 6297 @boolToInt(multi_cases_len != 0) + 6298 payloads.items.len - case_table_end); 6299 6300 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.SwitchBlock{ 6301 .operand = cond, 6302 .bits = Zir.Inst.SwitchBlock.Bits{ 6303 .is_ref = any_payload_is_ref, 6304 .has_multi_cases = multi_cases_len != 0, 6305 .has_else = special_prong == .@"else", 6306 .has_under = special_prong == .under, 6307 .scalar_cases_len = @intCast(Zir.Inst.SwitchBlock.Bits.ScalarCasesLen, scalar_cases_len), 6308 }, 6309 }); 6310 6311 if (multi_cases_len != 0) { 6312 astgen.extra.appendAssumeCapacity(multi_cases_len); 6313 } 6314 6315 const zir_datas = astgen.instructions.items(.data); 6316 const zir_tags = astgen.instructions.items(.tag); 6317 6318 zir_datas[switch_block].pl_node.payload_index = payload_index; 6319 6320 const strat = rl.strategy(&block_scope); 6321 for (payloads.items[case_table_start..case_table_end]) |start_index, i| { 6322 var body_len_index = start_index; 6323 var end_index = start_index; 6324 const table_index = case_table_start + i; 6325 if (table_index < scalar_case_table) { 6326 end_index += 1; 6327 } else if (table_index < multi_case_table) { 6328 body_len_index += 1; 6329 end_index += 2; 6330 } else { 6331 body_len_index += 2; 6332 const items_len = payloads.items[start_index]; 6333 const ranges_len = payloads.items[start_index + 1]; 6334 end_index += 3 + items_len + 2 * ranges_len; 6335 } 6336 6337 const body_len = payloads.items[body_len_index]; 6338 end_index += body_len; 6339 6340 switch (strat.tag) { 6341 .break_operand => blk: { 6342 // Switch expressions return `true` for `nodeMayNeedMemoryLocation` thus 6343 // `elide_store_to_block_ptr_instructions` will either be true, 6344 // or all prongs are noreturn. 6345 if (!strat.elide_store_to_block_ptr_instructions) 6346 break :blk; 6347 6348 // There will necessarily be a store_to_block_ptr for 6349 // all prongs, except for prongs that ended with a noreturn instruction. 6350 // Elide all the `store_to_block_ptr` instructions. 6351 6352 // The break instructions need to have their operands coerced if the 6353 // switch's result location is a `ty`. In this case we overwrite the 6354 // `store_to_block_ptr` instruction with an `as` instruction and repurpose 6355 // it as the break operand. 6356 if (body_len < 2) 6357 break :blk; 6358 const store_inst = payloads.items[end_index - 2]; 6359 if (zir_tags[store_inst] != .store_to_block_ptr or 6360 zir_datas[store_inst].bin.lhs != block_scope.rl_ptr) 6361 break :blk; 6362 const break_inst = payloads.items[end_index - 1]; 6363 if (block_scope.rl_ty_inst != .none) { 6364 zir_tags[store_inst] = .as; 6365 zir_datas[store_inst].bin = .{ 6366 .lhs = block_scope.rl_ty_inst, 6367 .rhs = zir_datas[break_inst].@"break".operand, 6368 }; 6369 zir_datas[break_inst].@"break".operand = indexToRef(store_inst); 6370 } else { 6371 payloads.items[body_len_index] -= 1; 6372 astgen.extra.appendSliceAssumeCapacity(payloads.items[start_index .. end_index - 2]); 6373 astgen.extra.appendAssumeCapacity(break_inst); 6374 continue; 6375 } 6376 }, 6377 .break_void => { 6378 assert(!strat.elide_store_to_block_ptr_instructions); 6379 const last_inst = payloads.items[end_index - 1]; 6380 if (zir_tags[last_inst] == .@"break" and 6381 zir_datas[last_inst].@"break".block_inst == switch_block) 6382 { 6383 zir_datas[last_inst].@"break".operand = .void_value; 6384 } 6385 }, 6386 } 6387 6388 astgen.extra.appendSliceAssumeCapacity(payloads.items[start_index..end_index]); 6389 } 6390 6391 const block_ref = indexToRef(switch_block); 6392 if (strat.tag == .break_operand and strat.elide_store_to_block_ptr_instructions and rl != .ref) 6393 return rvalue(parent_gz, rl, block_ref, switch_node); 6394 return block_ref; 6395 } 6396 6397 fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 6398 const astgen = gz.astgen; 6399 const tree = astgen.tree; 6400 const node_datas = tree.nodes.items(.data); 6401 const node_tags = tree.nodes.items(.tag); 6402 6403 if (astgen.fn_block == null) { 6404 return astgen.failNode(node, "'return' outside function scope", .{}); 6405 } 6406 6407 if (gz.in_defer) return astgen.failNode(node, "cannot return from defer expression", .{}); 6408 6409 const defer_outer = &astgen.fn_block.?.base; 6410 6411 const operand_node = node_datas[node].lhs; 6412 if (operand_node == 0) { 6413 // Returning a void value; skip error defers. 6414 try genDefers(gz, defer_outer, scope, .normal_only); 6415 _ = try gz.addUnNode(.ret_node, .void_value, node); 6416 return Zir.Inst.Ref.unreachable_value; 6417 } 6418 6419 if (node_tags[operand_node] == .error_value) { 6420 // Hot path for `return error.Foo`. This bypasses result location logic as well as logic 6421 // for detecting whether to add something to the function's inferred error set. 6422 const ident_token = node_datas[operand_node].rhs; 6423 const err_name_str_index = try astgen.identAsString(ident_token); 6424 const defer_counts = countDefers(astgen, defer_outer, scope); 6425 if (!defer_counts.need_err_code) { 6426 try genDefers(gz, defer_outer, scope, .both_sans_err); 6427 _ = try gz.addStrTok(.ret_err_value, err_name_str_index, ident_token); 6428 return Zir.Inst.Ref.unreachable_value; 6429 } 6430 const err_code = try gz.addStrTok(.ret_err_value_code, err_name_str_index, ident_token); 6431 try genDefers(gz, defer_outer, scope, .{ .both = err_code }); 6432 _ = try gz.addUnNode(.ret_node, err_code, node); 6433 return Zir.Inst.Ref.unreachable_value; 6434 } 6435 6436 const rl: ResultLoc = if (nodeMayNeedMemoryLocation(tree, operand_node, true)) .{ 6437 .ptr = try gz.addNode(.ret_ptr, node), 6438 } else .{ 6439 .ty = try gz.addNode(.ret_type, node), 6440 }; 6441 const prev_anon_name_strategy = gz.anon_name_strategy; 6442 gz.anon_name_strategy = .func; 6443 const operand = try reachableExpr(gz, scope, rl, operand_node, node); 6444 gz.anon_name_strategy = prev_anon_name_strategy; 6445 6446 switch (nodeMayEvalToError(tree, operand_node)) { 6447 .never => { 6448 // Returning a value that cannot be an error; skip error defers. 6449 try genDefers(gz, defer_outer, scope, .normal_only); 6450 try gz.addRet(rl, operand, node); 6451 return Zir.Inst.Ref.unreachable_value; 6452 }, 6453 .always => { 6454 // Value is always an error. Emit both error defers and regular defers. 6455 const result = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand; 6456 const err_code = try gz.addUnNode(.err_union_code, result, node); 6457 try genDefers(gz, defer_outer, scope, .{ .both = err_code }); 6458 try gz.addRet(rl, operand, node); 6459 return Zir.Inst.Ref.unreachable_value; 6460 }, 6461 .maybe => { 6462 const defer_counts = countDefers(astgen, defer_outer, scope); 6463 if (!defer_counts.have_err) { 6464 // Only regular defers; no branch needed. 6465 try genDefers(gz, defer_outer, scope, .normal_only); 6466 try gz.addRet(rl, operand, node); 6467 return Zir.Inst.Ref.unreachable_value; 6468 } 6469 6470 // Emit conditional branch for generating errdefers. 6471 const result = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand; 6472 const is_non_err = try gz.addUnNode(.is_non_err, result, node); 6473 const condbr = try gz.addCondBr(.condbr, node); 6474 6475 var then_scope = gz.makeSubBlock(scope); 6476 defer then_scope.unstack(); 6477 6478 try genDefers(&then_scope, defer_outer, scope, .normal_only); 6479 try then_scope.addRet(rl, operand, node); 6480 6481 var else_scope = gz.makeSubBlock(scope); 6482 defer else_scope.unstack(); 6483 6484 const which_ones: DefersToEmit = if (!defer_counts.need_err_code) .both_sans_err else .{ 6485 .both = try else_scope.addUnNode(.err_union_code, result, node), 6486 }; 6487 try genDefers(&else_scope, defer_outer, scope, which_ones); 6488 try else_scope.addRet(rl, operand, node); 6489 6490 try setCondBrPayload(condbr, is_non_err, &then_scope, 0, &else_scope, 0); 6491 6492 return Zir.Inst.Ref.unreachable_value; 6493 }, 6494 } 6495 } 6496 6497 /// Parses the string `buf` as a base 10 integer of type `u16`. 6498 /// 6499 /// Unlike std.fmt.parseInt, does not allow the '_' character in `buf`. 6500 fn parseBitCount(buf: []const u8) std.fmt.ParseIntError!u16 { 6501 if (buf.len == 0) return error.InvalidCharacter; 6502 6503 var x: u16 = 0; 6504 6505 for (buf) |c| { 6506 const digit = switch (c) { 6507 '0'...'9' => c - '0', 6508 else => return error.InvalidCharacter, 6509 }; 6510 6511 if (x != 0) x = try std.math.mul(u16, x, 10); 6512 x = try std.math.add(u16, x, @as(u16, digit)); 6513 } 6514 6515 return x; 6516 } 6517 6518 fn identifier( 6519 gz: *GenZir, 6520 scope: *Scope, 6521 rl: ResultLoc, 6522 ident: Ast.Node.Index, 6523 ) InnerError!Zir.Inst.Ref { 6524 const tracy = trace(@src()); 6525 defer tracy.end(); 6526 6527 const astgen = gz.astgen; 6528 const tree = astgen.tree; 6529 const main_tokens = tree.nodes.items(.main_token); 6530 6531 const ident_token = main_tokens[ident]; 6532 const ident_name_raw = tree.tokenSlice(ident_token); 6533 if (mem.eql(u8, ident_name_raw, "_")) { 6534 return astgen.failNode(ident, "'_' used as an identifier without @\"_\" syntax", .{}); 6535 } 6536 6537 // if not @"" syntax, just use raw token slice 6538 if (ident_name_raw[0] != '@') { 6539 if (primitives.get(ident_name_raw)) |zir_const_ref| { 6540 return rvalue(gz, rl, zir_const_ref, ident); 6541 } 6542 6543 if (ident_name_raw.len >= 2) integer: { 6544 const first_c = ident_name_raw[0]; 6545 if (first_c == 'i' or first_c == 'u') { 6546 const signedness: std.builtin.Signedness = switch (first_c == 'i') { 6547 true => .signed, 6548 false => .unsigned, 6549 }; 6550 const bit_count = parseBitCount(ident_name_raw[1..]) catch |err| switch (err) { 6551 error.Overflow => return astgen.failNode( 6552 ident, 6553 "primitive integer type '{s}' exceeds maximum bit width of 65535", 6554 .{ident_name_raw}, 6555 ), 6556 error.InvalidCharacter => break :integer, 6557 }; 6558 const result = try gz.add(.{ 6559 .tag = .int_type, 6560 .data = .{ .int_type = .{ 6561 .src_node = gz.nodeIndexToRelative(ident), 6562 .signedness = signedness, 6563 .bit_count = bit_count, 6564 } }, 6565 }); 6566 return rvalue(gz, rl, result, ident); 6567 } 6568 } 6569 } 6570 6571 // Local variables, including function parameters. 6572 return localVarRef(gz, scope, rl, ident, ident_token); 6573 } 6574 6575 fn localVarRef( 6576 gz: *GenZir, 6577 scope: *Scope, 6578 rl: ResultLoc, 6579 ident: Ast.Node.Index, 6580 ident_token: Ast.Node.Index, 6581 ) InnerError!Zir.Inst.Ref { 6582 const astgen = gz.astgen; 6583 const gpa = astgen.gpa; 6584 6585 const name_str_index = try astgen.identAsString(ident_token); 6586 var s = scope; 6587 var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already 6588 var num_namespaces_out: u32 = 0; 6589 var capturing_namespace: ?*Scope.Namespace = null; 6590 while (true) switch (s.tag) { 6591 .local_val => { 6592 const local_val = s.cast(Scope.LocalVal).?; 6593 6594 if (local_val.name == name_str_index) { 6595 // Locals cannot shadow anything, so we do not need to look for ambiguous 6596 // references in this case. 6597 local_val.used = true; 6598 6599 const value_inst = try tunnelThroughClosure( 6600 gz, 6601 ident, 6602 num_namespaces_out, 6603 capturing_namespace, 6604 local_val.inst, 6605 local_val.token_src, 6606 gpa, 6607 ); 6608 6609 return rvalue(gz, rl, value_inst, ident); 6610 } 6611 s = local_val.parent; 6612 }, 6613 .local_ptr => { 6614 const local_ptr = s.cast(Scope.LocalPtr).?; 6615 if (local_ptr.name == name_str_index) { 6616 local_ptr.used = true; 6617 6618 // Can't close over a runtime variable 6619 if (num_namespaces_out != 0 and !local_ptr.maybe_comptime) { 6620 const ident_name = try astgen.identifierTokenString(ident_token); 6621 return astgen.failNodeNotes(ident, "mutable '{s}' not accessible from here", .{ident_name}, &.{ 6622 try astgen.errNoteTok(local_ptr.token_src, "declared mutable here", .{}), 6623 try astgen.errNoteNode(capturing_namespace.?.node, "crosses namespace boundary here", .{}), 6624 }); 6625 } 6626 6627 const ptr_inst = try tunnelThroughClosure( 6628 gz, 6629 ident, 6630 num_namespaces_out, 6631 capturing_namespace, 6632 local_ptr.ptr, 6633 local_ptr.token_src, 6634 gpa, 6635 ); 6636 6637 switch (rl) { 6638 .ref => return ptr_inst, 6639 else => { 6640 const loaded = try gz.addUnNode(.load, ptr_inst, ident); 6641 return rvalue(gz, rl, loaded, ident); 6642 }, 6643 } 6644 } 6645 s = local_ptr.parent; 6646 }, 6647 .gen_zir => s = s.cast(GenZir).?.parent, 6648 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, 6649 .namespace => { 6650 const ns = s.cast(Scope.Namespace).?; 6651 if (ns.decls.get(name_str_index)) |i| { 6652 if (found_already) |f| { 6653 return astgen.failNodeNotes(ident, "ambiguous reference", .{}, &.{ 6654 try astgen.errNoteNode(f, "declared here", .{}), 6655 try astgen.errNoteNode(i, "also declared here", .{}), 6656 }); 6657 } 6658 // We found a match but must continue looking for ambiguous references to decls. 6659 found_already = i; 6660 } 6661 num_namespaces_out += 1; 6662 capturing_namespace = ns; 6663 s = ns.parent; 6664 }, 6665 .top => break, 6666 }; 6667 if (found_already == null) { 6668 const ident_name = try astgen.identifierTokenString(ident_token); 6669 return astgen.failNode(ident, "use of undeclared identifier '{s}'", .{ident_name}); 6670 } 6671 6672 // Decl references happen by name rather than ZIR index so that when unrelated 6673 // decls are modified, ZIR code containing references to them can be unmodified. 6674 switch (rl) { 6675 .ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token), 6676 else => { 6677 const result = try gz.addStrTok(.decl_val, name_str_index, ident_token); 6678 return rvalue(gz, rl, result, ident); 6679 }, 6680 } 6681 } 6682 6683 /// Adds a capture to a namespace, if needed. 6684 /// Returns the index of the closure_capture instruction. 6685 fn tunnelThroughClosure( 6686 gz: *GenZir, 6687 inner_ref_node: Ast.Node.Index, 6688 num_tunnels: u32, 6689 ns: ?*Scope.Namespace, 6690 value: Zir.Inst.Ref, 6691 token: Ast.TokenIndex, 6692 gpa: Allocator, 6693 ) !Zir.Inst.Ref { 6694 // For trivial values, we don't need a tunnel. 6695 // Just return the ref. 6696 if (num_tunnels == 0 or refToIndex(value) == null) { 6697 return value; 6698 } 6699 6700 // Otherwise we need a tunnel. Check if this namespace 6701 // already has one for this value. 6702 const gop = try ns.?.captures.getOrPut(gpa, refToIndex(value).?); 6703 if (!gop.found_existing) { 6704 // Make a new capture for this value but don't add it to the declaring_gz yet 6705 try gz.astgen.instructions.append(gz.astgen.gpa, .{ 6706 .tag = .closure_capture, 6707 .data = .{ .un_tok = .{ 6708 .operand = value, 6709 .src_tok = ns.?.declaring_gz.?.tokenIndexToRelative(token), 6710 } }, 6711 }); 6712 gop.value_ptr.* = @intCast(Zir.Inst.Index, gz.astgen.instructions.len - 1); 6713 } 6714 6715 // Add an instruction to get the value from the closure into 6716 // our current context 6717 return try gz.addInstNode(.closure_get, gop.value_ptr.*, inner_ref_node); 6718 } 6719 6720 fn stringLiteral( 6721 gz: *GenZir, 6722 rl: ResultLoc, 6723 node: Ast.Node.Index, 6724 ) InnerError!Zir.Inst.Ref { 6725 const astgen = gz.astgen; 6726 const tree = astgen.tree; 6727 const main_tokens = tree.nodes.items(.main_token); 6728 const str_lit_token = main_tokens[node]; 6729 const str = try astgen.strLitAsString(str_lit_token); 6730 const result = try gz.add(.{ 6731 .tag = .str, 6732 .data = .{ .str = .{ 6733 .start = str.index, 6734 .len = str.len, 6735 } }, 6736 }); 6737 return rvalue(gz, rl, result, node); 6738 } 6739 6740 fn multilineStringLiteral( 6741 gz: *GenZir, 6742 rl: ResultLoc, 6743 node: Ast.Node.Index, 6744 ) InnerError!Zir.Inst.Ref { 6745 const astgen = gz.astgen; 6746 const str = try astgen.strLitNodeAsString(node); 6747 const result = try gz.add(.{ 6748 .tag = .str, 6749 .data = .{ .str = .{ 6750 .start = str.index, 6751 .len = str.len, 6752 } }, 6753 }); 6754 return rvalue(gz, rl, result, node); 6755 } 6756 6757 fn charLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 6758 const astgen = gz.astgen; 6759 const tree = astgen.tree; 6760 const main_tokens = tree.nodes.items(.main_token); 6761 const main_token = main_tokens[node]; 6762 const slice = tree.tokenSlice(main_token); 6763 6764 switch (std.zig.parseCharLiteral(slice)) { 6765 .success => |codepoint| { 6766 const result = try gz.addInt(codepoint); 6767 return rvalue(gz, rl, result, node); 6768 }, 6769 .failure => |err| return astgen.failWithStrLitError(err, main_token, slice, 0), 6770 } 6771 } 6772 6773 fn integerLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 6774 const astgen = gz.astgen; 6775 const tree = astgen.tree; 6776 const main_tokens = tree.nodes.items(.main_token); 6777 const int_token = main_tokens[node]; 6778 const prefixed_bytes = tree.tokenSlice(int_token); 6779 if (std.fmt.parseInt(u64, prefixed_bytes, 0)) |small_int| { 6780 const result: Zir.Inst.Ref = switch (small_int) { 6781 0 => .zero, 6782 1 => .one, 6783 else => try gz.addInt(small_int), 6784 }; 6785 return rvalue(gz, rl, result, node); 6786 } else |err| switch (err) { 6787 error.InvalidCharacter => unreachable, // Caught by the parser. 6788 error.Overflow => {}, 6789 } 6790 6791 var base: u8 = 10; 6792 var non_prefixed: []const u8 = prefixed_bytes; 6793 if (mem.startsWith(u8, prefixed_bytes, "0x")) { 6794 base = 16; 6795 non_prefixed = prefixed_bytes[2..]; 6796 } else if (mem.startsWith(u8, prefixed_bytes, "0o")) { 6797 base = 8; 6798 non_prefixed = prefixed_bytes[2..]; 6799 } else if (mem.startsWith(u8, prefixed_bytes, "0b")) { 6800 base = 2; 6801 non_prefixed = prefixed_bytes[2..]; 6802 } 6803 6804 const gpa = astgen.gpa; 6805 var big_int = try std.math.big.int.Managed.init(gpa); 6806 defer big_int.deinit(); 6807 big_int.setString(base, non_prefixed) catch |err| switch (err) { 6808 error.InvalidCharacter => unreachable, // caught by parser 6809 error.InvalidBase => unreachable, // we only pass 16, 8, 2, see above 6810 error.OutOfMemory => return error.OutOfMemory, 6811 }; 6812 6813 const limbs = big_int.limbs[0..big_int.len()]; 6814 assert(big_int.isPositive()); 6815 const result = try gz.addIntBig(limbs); 6816 return rvalue(gz, rl, result, node); 6817 } 6818 6819 const Sign = enum { negative, positive }; 6820 6821 fn floatLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index, sign: Sign) InnerError!Zir.Inst.Ref { 6822 const astgen = gz.astgen; 6823 const tree = astgen.tree; 6824 const main_tokens = tree.nodes.items(.main_token); 6825 6826 const main_token = main_tokens[node]; 6827 const bytes = tree.tokenSlice(main_token); 6828 const unsigned_float_number = std.fmt.parseFloat(f128, bytes) catch |err| switch (err) { 6829 error.InvalidCharacter => unreachable, // validated by tokenizer 6830 }; 6831 const float_number = switch (sign) { 6832 .negative => -unsigned_float_number, 6833 .positive => unsigned_float_number, 6834 }; 6835 // If the value fits into a f64 without losing any precision, store it that way. 6836 @setFloatMode(.Strict); 6837 const smaller_float = @floatCast(f64, float_number); 6838 const bigger_again: f128 = smaller_float; 6839 if (bigger_again == float_number) { 6840 const result = try gz.addFloat(smaller_float); 6841 return rvalue(gz, rl, result, node); 6842 } 6843 // We need to use 128 bits. Break the float into 4 u32 values so we can 6844 // put it into the `extra` array. 6845 const int_bits = @bitCast(u128, float_number); 6846 const result = try gz.addPlNode(.float128, node, Zir.Inst.Float128{ 6847 .piece0 = @truncate(u32, int_bits), 6848 .piece1 = @truncate(u32, int_bits >> 32), 6849 .piece2 = @truncate(u32, int_bits >> 64), 6850 .piece3 = @truncate(u32, int_bits >> 96), 6851 }); 6852 return rvalue(gz, rl, result, node); 6853 } 6854 6855 fn asmExpr( 6856 gz: *GenZir, 6857 scope: *Scope, 6858 rl: ResultLoc, 6859 node: Ast.Node.Index, 6860 full: Ast.full.Asm, 6861 ) InnerError!Zir.Inst.Ref { 6862 const astgen = gz.astgen; 6863 const tree = astgen.tree; 6864 const main_tokens = tree.nodes.items(.main_token); 6865 const node_datas = tree.nodes.items(.data); 6866 const node_tags = tree.nodes.items(.tag); 6867 const token_tags = tree.tokens.items(.tag); 6868 6869 const asm_source = switch (node_tags[full.ast.template]) { 6870 .string_literal => try astgen.strLitAsString(main_tokens[full.ast.template]), 6871 .multiline_string_literal => try astgen.strLitNodeAsString(full.ast.template), 6872 else => blk: { 6873 // stage1 allows this, and until we do another design iteration on inline assembly 6874 // in stage2 to improve support for the various needed use cases, we allow inline 6875 // assembly templates to be an expression. Once stage2 addresses the real world needs 6876 // of people using inline assembly (primarily OS developers) then we can re-institute 6877 // the rule into AstGen that assembly code must use string literal syntax. 6878 //return astgen.failNode(full.ast.template, "assembly code must use string literal syntax", .{}), 6879 // We still need to trigger all the expr() calls here to avoid errors for unused things. 6880 // So we pass 0 as the asm source and stage2 Sema will notice this and 6881 // report the error. 6882 _ = try comptimeExpr(gz, scope, .none, full.ast.template); 6883 break :blk IndexSlice{ .index = 0, .len = 0 }; 6884 }, 6885 }; 6886 6887 // See https://github.com/ziglang/zig/issues/215 and related issues discussing 6888 // possible inline assembly improvements. Until then here is status quo AstGen 6889 // for assembly syntax. It's used by std lib crypto aesni.zig. 6890 const is_container_asm = astgen.fn_block == null; 6891 if (is_container_asm) { 6892 if (full.volatile_token) |t| 6893 return astgen.failTok(t, "volatile is meaningless on global assembly", .{}); 6894 if (full.outputs.len != 0 or full.inputs.len != 0 or full.first_clobber != null) 6895 return astgen.failNode(node, "global assembly cannot have inputs, outputs, or clobbers", .{}); 6896 } else { 6897 if (full.outputs.len == 0 and full.volatile_token == null) { 6898 return astgen.failNode(node, "assembly expression with no output must be marked volatile", .{}); 6899 } 6900 } 6901 if (full.outputs.len > 32) { 6902 return astgen.failNode(full.outputs[32], "too many asm outputs", .{}); 6903 } 6904 var outputs_buffer: [32]Zir.Inst.Asm.Output = undefined; 6905 const outputs = outputs_buffer[0..full.outputs.len]; 6906 6907 var output_type_bits: u32 = 0; 6908 6909 for (full.outputs) |output_node, i| { 6910 const symbolic_name = main_tokens[output_node]; 6911 const name = try astgen.identAsString(symbolic_name); 6912 const constraint_token = symbolic_name + 2; 6913 const constraint = (try astgen.strLitAsString(constraint_token)).index; 6914 const has_arrow = token_tags[symbolic_name + 4] == .arrow; 6915 if (has_arrow) { 6916 if (output_type_bits != 0) { 6917 return astgen.failNode(output_node, "inline assembly allows up to one output value", .{}); 6918 } 6919 output_type_bits |= @as(u32, 1) << @intCast(u5, i); 6920 const out_type_node = node_datas[output_node].lhs; 6921 const out_type_inst = try typeExpr(gz, scope, out_type_node); 6922 outputs[i] = .{ 6923 .name = name, 6924 .constraint = constraint, 6925 .operand = out_type_inst, 6926 }; 6927 } else { 6928 const ident_token = symbolic_name + 4; 6929 // TODO have a look at #215 and related issues and decide how to 6930 // handle outputs. Do we want this to be identifiers? 6931 // Or maybe we want to force this to be expressions with a pointer type. 6932 outputs[i] = .{ 6933 .name = name, 6934 .constraint = constraint, 6935 .operand = try localVarRef(gz, scope, .ref, node, ident_token), 6936 }; 6937 } 6938 } 6939 6940 if (full.inputs.len > 32) { 6941 return astgen.failNode(full.inputs[32], "too many asm inputs", .{}); 6942 } 6943 var inputs_buffer: [32]Zir.Inst.Asm.Input = undefined; 6944 const inputs = inputs_buffer[0..full.inputs.len]; 6945 6946 for (full.inputs) |input_node, i| { 6947 const symbolic_name = main_tokens[input_node]; 6948 const name = try astgen.identAsString(symbolic_name); 6949 const constraint_token = symbolic_name + 2; 6950 const constraint = (try astgen.strLitAsString(constraint_token)).index; 6951 const operand = try expr(gz, scope, .none, node_datas[input_node].lhs); 6952 inputs[i] = .{ 6953 .name = name, 6954 .constraint = constraint, 6955 .operand = operand, 6956 }; 6957 } 6958 6959 var clobbers_buffer: [32]u32 = undefined; 6960 var clobber_i: usize = 0; 6961 if (full.first_clobber) |first_clobber| clobbers: { 6962 // asm ("foo" ::: "a", "b") 6963 // asm ("foo" ::: "a", "b",) 6964 var tok_i = first_clobber; 6965 while (true) : (tok_i += 1) { 6966 if (clobber_i >= clobbers_buffer.len) { 6967 return astgen.failTok(tok_i, "too many asm clobbers", .{}); 6968 } 6969 clobbers_buffer[clobber_i] = (try astgen.strLitAsString(tok_i)).index; 6970 clobber_i += 1; 6971 tok_i += 1; 6972 switch (token_tags[tok_i]) { 6973 .r_paren => break :clobbers, 6974 .comma => { 6975 if (token_tags[tok_i + 1] == .r_paren) { 6976 break :clobbers; 6977 } else { 6978 continue; 6979 } 6980 }, 6981 else => unreachable, 6982 } 6983 } 6984 } 6985 6986 const result = try gz.addAsm(.{ 6987 .node = node, 6988 .asm_source = asm_source.index, 6989 .is_volatile = full.volatile_token != null, 6990 .output_type_bits = output_type_bits, 6991 .outputs = outputs, 6992 .inputs = inputs, 6993 .clobbers = clobbers_buffer[0..clobber_i], 6994 }); 6995 return rvalue(gz, rl, result, node); 6996 } 6997 6998 fn as( 6999 gz: *GenZir, 7000 scope: *Scope, 7001 rl: ResultLoc, 7002 node: Ast.Node.Index, 7003 lhs: Ast.Node.Index, 7004 rhs: Ast.Node.Index, 7005 ) InnerError!Zir.Inst.Ref { 7006 const dest_type = try typeExpr(gz, scope, lhs); 7007 switch (rl) { 7008 .none, .discard, .ref, .ty, .coerced_ty => { 7009 const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node); 7010 return rvalue(gz, rl, result, node); 7011 }, 7012 .ptr, .inferred_ptr => |result_ptr| { 7013 return asRlPtr(gz, scope, rl, node, result_ptr, rhs, dest_type); 7014 }, 7015 .block_ptr => |block_scope| { 7016 return asRlPtr(gz, scope, rl, node, block_scope.rl_ptr, rhs, dest_type); 7017 }, 7018 } 7019 } 7020 7021 fn unionInit( 7022 gz: *GenZir, 7023 scope: *Scope, 7024 rl: ResultLoc, 7025 node: Ast.Node.Index, 7026 params: []const Ast.Node.Index, 7027 ) InnerError!Zir.Inst.Ref { 7028 const union_type = try typeExpr(gz, scope, params[0]); 7029 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); 7030 const field_type = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{ 7031 .container_type = union_type, 7032 .field_name = field_name, 7033 }); 7034 const init = try reachableExpr(gz, scope, .{ .ty = field_type }, params[2], node); 7035 const result = try gz.addPlNode(.union_init, node, Zir.Inst.UnionInit{ 7036 .union_type = union_type, 7037 .init = init, 7038 .field_name = field_name, 7039 }); 7040 return rvalue(gz, rl, result, node); 7041 } 7042 7043 fn asRlPtr( 7044 parent_gz: *GenZir, 7045 scope: *Scope, 7046 rl: ResultLoc, 7047 src_node: Ast.Node.Index, 7048 result_ptr: Zir.Inst.Ref, 7049 operand_node: Ast.Node.Index, 7050 dest_type: Zir.Inst.Ref, 7051 ) InnerError!Zir.Inst.Ref { 7052 var as_scope = try parent_gz.makeCoercionScope(scope, dest_type, result_ptr, src_node); 7053 defer as_scope.unstack(); 7054 7055 const result = try reachableExpr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node, src_node); 7056 return as_scope.finishCoercion(parent_gz, rl, operand_node, result, dest_type); 7057 } 7058 7059 fn bitCast( 7060 gz: *GenZir, 7061 scope: *Scope, 7062 rl: ResultLoc, 7063 node: Ast.Node.Index, 7064 lhs: Ast.Node.Index, 7065 rhs: Ast.Node.Index, 7066 ) InnerError!Zir.Inst.Ref { 7067 const dest_type = try reachableTypeExpr(gz, scope, lhs, node); 7068 const operand = try reachableExpr(gz, scope, .none, rhs, node); 7069 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{ 7070 .lhs = dest_type, 7071 .rhs = operand, 7072 }); 7073 return rvalue(gz, rl, result, node); 7074 } 7075 7076 fn typeOf( 7077 gz: *GenZir, 7078 scope: *Scope, 7079 rl: ResultLoc, 7080 node: Ast.Node.Index, 7081 args: []const Ast.Node.Index, 7082 ) InnerError!Zir.Inst.Ref { 7083 const astgen = gz.astgen; 7084 if (args.len < 1) { 7085 return astgen.failNode(node, "expected at least 1 argument, found 0", .{}); 7086 } 7087 const gpa = astgen.gpa; 7088 if (args.len == 1) { 7089 const typeof_inst = try gz.makeBlockInst(.typeof_builtin, node); 7090 7091 var typeof_scope = gz.makeSubBlock(scope); 7092 typeof_scope.force_comptime = false; 7093 defer typeof_scope.unstack(); 7094 7095 const ty_expr = try reachableExpr(&typeof_scope, &typeof_scope.base, .none, args[0], node); 7096 if (!gz.refIsNoReturn(ty_expr)) { 7097 _ = try typeof_scope.addBreak(.break_inline, typeof_inst, ty_expr); 7098 } 7099 try typeof_scope.setBlockBody(typeof_inst); 7100 7101 // typeof_scope unstacked now, can add new instructions to gz 7102 try gz.instructions.append(gpa, typeof_inst); 7103 return rvalue(gz, rl, indexToRef(typeof_inst), node); 7104 } 7105 const payload_size: u32 = std.meta.fields(Zir.Inst.TypeOfPeer).len; 7106 const payload_index = try reserveExtra(astgen, payload_size + args.len); 7107 var args_index = payload_index + payload_size; 7108 7109 const typeof_inst = try gz.addExtendedMultiOpPayloadIndex(.typeof_peer, payload_index, args.len); 7110 7111 var typeof_scope = gz.makeSubBlock(scope); 7112 typeof_scope.force_comptime = false; 7113 7114 for (args) |arg, i| { 7115 const param_ref = try reachableExpr(&typeof_scope, &typeof_scope.base, .none, arg, node); 7116 astgen.extra.items[args_index + i] = @enumToInt(param_ref); 7117 } 7118 _ = try typeof_scope.addBreak(.break_inline, refToIndex(typeof_inst).?, .void_value); 7119 7120 const body = typeof_scope.instructionsSlice(); 7121 const body_len = astgen.countBodyLenAfterFixups(body); 7122 astgen.setExtra(payload_index, Zir.Inst.TypeOfPeer{ 7123 .body_len = @intCast(u32, body_len), 7124 .body_index = @intCast(u32, astgen.extra.items.len), 7125 .src_node = gz.nodeIndexToRelative(node), 7126 }); 7127 try astgen.extra.ensureUnusedCapacity(gpa, body_len); 7128 astgen.appendBodyWithFixups(body); 7129 typeof_scope.unstack(); 7130 7131 return rvalue(gz, rl, typeof_inst, node); 7132 } 7133 7134 fn builtinCall( 7135 gz: *GenZir, 7136 scope: *Scope, 7137 rl: ResultLoc, 7138 node: Ast.Node.Index, 7139 params: []const Ast.Node.Index, 7140 ) InnerError!Zir.Inst.Ref { 7141 const astgen = gz.astgen; 7142 const tree = astgen.tree; 7143 const main_tokens = tree.nodes.items(.main_token); 7144 7145 const builtin_token = main_tokens[node]; 7146 const builtin_name = tree.tokenSlice(builtin_token); 7147 7148 // We handle the different builtins manually because they have different semantics depending 7149 // on the function. For example, `@as` and others participate in result location semantics, 7150 // and `@cImport` creates a special scope that collects a .c source code text buffer. 7151 // Also, some builtins have a variable number of parameters. 7152 7153 const info = BuiltinFn.list.get(builtin_name) orelse { 7154 return astgen.failNode(node, "invalid builtin function: '{s}'", .{ 7155 builtin_name, 7156 }); 7157 }; 7158 if (info.param_count) |expected| { 7159 if (expected != params.len) { 7160 const s = if (expected == 1) "" else "s"; 7161 return astgen.failNode(node, "expected {d} argument{s}, found {d}", .{ 7162 expected, s, params.len, 7163 }); 7164 } 7165 } 7166 7167 switch (info.tag) { 7168 .import => { 7169 const node_tags = tree.nodes.items(.tag); 7170 const operand_node = params[0]; 7171 7172 if (node_tags[operand_node] != .string_literal) { 7173 // Spec reference: https://github.com/ziglang/zig/issues/2206 7174 return astgen.failNode(operand_node, "@import operand must be a string literal", .{}); 7175 } 7176 const str_lit_token = main_tokens[operand_node]; 7177 const str = try astgen.strLitAsString(str_lit_token); 7178 const result = try gz.addStrTok(.import, str.index, str_lit_token); 7179 const gop = try astgen.imports.getOrPut(astgen.gpa, str.index); 7180 if (!gop.found_existing) { 7181 gop.value_ptr.* = str_lit_token; 7182 } 7183 return rvalue(gz, rl, result, node); 7184 }, 7185 .compile_log => { 7186 const payload_index = try addExtra(gz.astgen, Zir.Inst.NodeMultiOp{ 7187 .src_node = gz.nodeIndexToRelative(node), 7188 }); 7189 var extra_index = try reserveExtra(gz.astgen, params.len); 7190 for (params) |param| { 7191 const param_ref = try expr(gz, scope, .none, param); 7192 astgen.extra.items[extra_index] = @enumToInt(param_ref); 7193 extra_index += 1; 7194 } 7195 const result = try gz.addExtendedMultiOpPayloadIndex(.compile_log, payload_index, params.len); 7196 return rvalue(gz, rl, result, node); 7197 }, 7198 .field => { 7199 if (rl == .ref) { 7200 return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{ 7201 .lhs = try expr(gz, scope, .ref, params[0]), 7202 .field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]), 7203 }); 7204 } 7205 const result = try gz.addPlNode(.field_val_named, node, Zir.Inst.FieldNamed{ 7206 .lhs = try expr(gz, scope, .none, params[0]), 7207 .field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]), 7208 }); 7209 return rvalue(gz, rl, result, node); 7210 }, 7211 7212 // zig fmt: off 7213 .as => return as( gz, scope, rl, node, params[0], params[1]), 7214 .bit_cast => return bitCast( gz, scope, rl, node, params[0], params[1]), 7215 .TypeOf => return typeOf( gz, scope, rl, node, params), 7216 .union_init => return unionInit(gz, scope, rl, node, params), 7217 .c_import => return cImport( gz, scope, node, params[0]), 7218 // zig fmt: on 7219 7220 .@"export" => { 7221 const node_tags = tree.nodes.items(.tag); 7222 const node_datas = tree.nodes.items(.data); 7223 // This function causes a Decl to be exported. The first parameter is not an expression, 7224 // but an identifier of the Decl to be exported. 7225 var namespace: Zir.Inst.Ref = .none; 7226 var decl_name: u32 = 0; 7227 switch (node_tags[params[0]]) { 7228 .identifier => { 7229 const ident_token = main_tokens[params[0]]; 7230 decl_name = try astgen.identAsString(ident_token); 7231 7232 var s = scope; 7233 var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already 7234 while (true) switch (s.tag) { 7235 .local_val => { 7236 const local_val = s.cast(Scope.LocalVal).?; 7237 if (local_val.name == decl_name) { 7238 local_val.used = true; 7239 _ = try gz.addPlNode(.export_value, node, Zir.Inst.ExportValue{ 7240 .operand = local_val.inst, 7241 .options = try comptimeExpr(gz, scope, .{ .coerced_ty = .export_options_type }, params[1]), 7242 }); 7243 return rvalue(gz, rl, .void_value, node); 7244 } 7245 s = local_val.parent; 7246 }, 7247 .local_ptr => { 7248 const local_ptr = s.cast(Scope.LocalPtr).?; 7249 if (local_ptr.name == decl_name) { 7250 if (!local_ptr.maybe_comptime) 7251 return astgen.failNode(params[0], "unable to export runtime-known value", .{}); 7252 local_ptr.used = true; 7253 const loaded = try gz.addUnNode(.load, local_ptr.ptr, node); 7254 _ = try gz.addPlNode(.export_value, node, Zir.Inst.ExportValue{ 7255 .operand = loaded, 7256 .options = try comptimeExpr(gz, scope, .{ .coerced_ty = .export_options_type }, params[1]), 7257 }); 7258 return rvalue(gz, rl, .void_value, node); 7259 } 7260 s = local_ptr.parent; 7261 }, 7262 .gen_zir => s = s.cast(GenZir).?.parent, 7263 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, 7264 .namespace => { 7265 const ns = s.cast(Scope.Namespace).?; 7266 if (ns.decls.get(decl_name)) |i| { 7267 if (found_already) |f| { 7268 return astgen.failNodeNotes(node, "ambiguous reference", .{}, &.{ 7269 try astgen.errNoteNode(f, "declared here", .{}), 7270 try astgen.errNoteNode(i, "also declared here", .{}), 7271 }); 7272 } 7273 // We found a match but must continue looking for ambiguous references to decls. 7274 found_already = i; 7275 } 7276 s = ns.parent; 7277 }, 7278 .top => break, 7279 }; 7280 }, 7281 .field_access => { 7282 const namespace_node = node_datas[params[0]].lhs; 7283 namespace = try typeExpr(gz, scope, namespace_node); 7284 const dot_token = main_tokens[params[0]]; 7285 const field_ident = dot_token + 1; 7286 decl_name = try astgen.identAsString(field_ident); 7287 }, 7288 else => return astgen.failNode(params[0], "symbol to export must identify a declaration", .{}), 7289 } 7290 const options = try comptimeExpr(gz, scope, .{ .ty = .export_options_type }, params[1]); 7291 _ = try gz.addPlNode(.@"export", node, Zir.Inst.Export{ 7292 .namespace = namespace, 7293 .decl_name = decl_name, 7294 .options = options, 7295 }); 7296 return rvalue(gz, rl, .void_value, node); 7297 }, 7298 .@"extern" => { 7299 const type_inst = try typeExpr(gz, scope, params[0]); 7300 const options = try comptimeExpr(gz, scope, .{ .ty = .extern_options_type }, params[1]); 7301 const result = try gz.addExtendedPayload(.builtin_extern, Zir.Inst.BinNode{ 7302 .node = gz.nodeIndexToRelative(node), 7303 .lhs = type_inst, 7304 .rhs = options, 7305 }); 7306 return rvalue(gz, rl, result, node); 7307 }, 7308 .fence => { 7309 const order = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[0]); 7310 const result = try gz.addExtendedPayload(.fence, Zir.Inst.UnNode{ 7311 .node = gz.nodeIndexToRelative(node), 7312 .operand = order, 7313 }); 7314 return rvalue(gz, rl, result, node); 7315 }, 7316 .set_float_mode => { 7317 const order = try expr(gz, scope, .{ .coerced_ty = .float_mode_type }, params[0]); 7318 const result = try gz.addExtendedPayload(.set_float_mode, Zir.Inst.UnNode{ 7319 .node = gz.nodeIndexToRelative(node), 7320 .operand = order, 7321 }); 7322 return rvalue(gz, rl, result, node); 7323 }, 7324 .set_align_stack => { 7325 const order = try expr(gz, scope, align_rl, params[0]); 7326 const result = try gz.addExtendedPayload(.set_align_stack, Zir.Inst.UnNode{ 7327 .node = gz.nodeIndexToRelative(node), 7328 .operand = order, 7329 }); 7330 return rvalue(gz, rl, result, node); 7331 }, 7332 7333 .src => { 7334 const token_starts = tree.tokens.items(.start); 7335 const node_start = token_starts[tree.firstToken(node)]; 7336 astgen.advanceSourceCursor(node_start); 7337 const result = try gz.addExtendedPayload(.builtin_src, Zir.Inst.LineColumn{ 7338 .line = astgen.source_line, 7339 .column = astgen.source_column, 7340 }); 7341 return rvalue(gz, rl, result, node); 7342 }, 7343 7344 // zig fmt: off 7345 .This => return rvalue(gz, rl, try gz.addNodeExtended(.this, node), node), 7346 .return_address => return rvalue(gz, rl, try gz.addNodeExtended(.ret_addr, node), node), 7347 .error_return_trace => return rvalue(gz, rl, try gz.addNodeExtended(.error_return_trace, node), node), 7348 .frame => return rvalue(gz, rl, try gz.addNodeExtended(.frame, node), node), 7349 .frame_address => return rvalue(gz, rl, try gz.addNodeExtended(.frame_address, node), node), 7350 .breakpoint => return rvalue(gz, rl, try gz.addNodeExtended(.breakpoint, node), node), 7351 7352 .type_info => return simpleUnOpType(gz, scope, rl, node, params[0], .type_info), 7353 .size_of => return simpleUnOpType(gz, scope, rl, node, params[0], .size_of), 7354 .bit_size_of => return simpleUnOpType(gz, scope, rl, node, params[0], .bit_size_of), 7355 .align_of => return simpleUnOpType(gz, scope, rl, node, params[0], .align_of), 7356 7357 .ptr_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .ptr_to_int), 7358 .error_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .error_to_int), 7359 .int_to_error => return simpleUnOp(gz, scope, rl, node, .{ .coerced_ty = .u16_type }, params[0], .int_to_error), 7360 .compile_error => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .compile_error), 7361 .set_eval_branch_quota => return simpleUnOp(gz, scope, rl, node, .{ .coerced_ty = .u32_type }, params[0], .set_eval_branch_quota), 7362 .enum_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .enum_to_int), 7363 .bool_to_int => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .bool_to_int), 7364 .embed_file => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .embed_file), 7365 .error_name => return simpleUnOp(gz, scope, rl, node, .{ .ty = .anyerror_type }, params[0], .error_name), 7366 .panic => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .panic), 7367 .set_cold => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .set_cold), 7368 .set_runtime_safety => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .set_runtime_safety), 7369 .sqrt => return simpleUnOp(gz, scope, rl, node, .none, params[0], .sqrt), 7370 .sin => return simpleUnOp(gz, scope, rl, node, .none, params[0], .sin), 7371 .cos => return simpleUnOp(gz, scope, rl, node, .none, params[0], .cos), 7372 .tan => return simpleUnOp(gz, scope, rl, node, .none, params[0], .tan), 7373 .exp => return simpleUnOp(gz, scope, rl, node, .none, params[0], .exp), 7374 .exp2 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .exp2), 7375 .log => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log), 7376 .log2 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log2), 7377 .log10 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log10), 7378 .fabs => return simpleUnOp(gz, scope, rl, node, .none, params[0], .fabs), 7379 .floor => return simpleUnOp(gz, scope, rl, node, .none, params[0], .floor), 7380 .ceil => return simpleUnOp(gz, scope, rl, node, .none, params[0], .ceil), 7381 .trunc => return simpleUnOp(gz, scope, rl, node, .none, params[0], .trunc), 7382 .round => return simpleUnOp(gz, scope, rl, node, .none, params[0], .round), 7383 .tag_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .tag_name), 7384 .Type => return simpleUnOp(gz, scope, rl, node, .{ .coerced_ty = .type_info_type }, params[0], .reify), 7385 .type_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .type_name), 7386 .Frame => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_type), 7387 .frame_size => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_size), 7388 7389 .float_to_int => return typeCast(gz, scope, rl, node, params[0], params[1], .float_to_int), 7390 .int_to_float => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_float), 7391 .int_to_ptr => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_ptr), 7392 .int_to_enum => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_enum), 7393 .float_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .float_cast), 7394 .int_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .int_cast), 7395 .ptr_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .ptr_cast), 7396 .truncate => return typeCast(gz, scope, rl, node, params[0], params[1], .truncate), 7397 // zig fmt: on 7398 7399 .align_cast => { 7400 const dest_align = try comptimeExpr(gz, scope, align_rl, params[0]); 7401 const rhs = try expr(gz, scope, .none, params[1]); 7402 const result = try gz.addPlNode(.align_cast, node, Zir.Inst.Bin{ 7403 .lhs = dest_align, 7404 .rhs = rhs, 7405 }); 7406 return rvalue(gz, rl, result, node); 7407 }, 7408 .err_set_cast => { 7409 const result = try gz.addExtendedPayload(.err_set_cast, Zir.Inst.BinNode{ 7410 .lhs = try typeExpr(gz, scope, params[0]), 7411 .rhs = try expr(gz, scope, .none, params[1]), 7412 .node = gz.nodeIndexToRelative(node), 7413 }); 7414 return rvalue(gz, rl, result, node); 7415 }, 7416 7417 // zig fmt: off 7418 .has_decl => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_decl), 7419 .has_field => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_field), 7420 7421 .clz => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .clz), 7422 .ctz => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .ctz), 7423 .pop_count => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .pop_count), 7424 .byte_swap => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .byte_swap), 7425 .bit_reverse => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .bit_reverse), 7426 7427 .div_exact => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_exact), 7428 .div_floor => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_floor), 7429 .div_trunc => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_trunc), 7430 .mod => return divBuiltin(gz, scope, rl, node, params[0], params[1], .mod), 7431 .rem => return divBuiltin(gz, scope, rl, node, params[0], params[1], .rem), 7432 7433 .shl_exact => return shiftOp(gz, scope, rl, node, params[0], params[1], .shl_exact), 7434 .shr_exact => return shiftOp(gz, scope, rl, node, params[0], params[1], .shr_exact), 7435 7436 .bit_offset_of => return offsetOf(gz, scope, rl, node, params[0], params[1], .bit_offset_of), 7437 .offset_of => return offsetOf(gz, scope, rl, node, params[0], params[1], .offset_of), 7438 7439 .c_undef => return simpleCBuiltin(gz, scope, rl, node, params[0], .c_undef), 7440 .c_include => return simpleCBuiltin(gz, scope, rl, node, params[0], .c_include), 7441 7442 .cmpxchg_strong => return cmpxchg(gz, scope, rl, node, params, .cmpxchg_strong), 7443 .cmpxchg_weak => return cmpxchg(gz, scope, rl, node, params, .cmpxchg_weak), 7444 // zig fmt: on 7445 7446 .wasm_memory_size => { 7447 const operand = try comptimeExpr(gz, scope, .{ .coerced_ty = .u32_type }, params[0]); 7448 const result = try gz.addExtendedPayload(.wasm_memory_size, Zir.Inst.UnNode{ 7449 .node = gz.nodeIndexToRelative(node), 7450 .operand = operand, 7451 }); 7452 return rvalue(gz, rl, result, node); 7453 }, 7454 .wasm_memory_grow => { 7455 const index_arg = try comptimeExpr(gz, scope, .{ .coerced_ty = .u32_type }, params[0]); 7456 const delta_arg = try expr(gz, scope, .{ .coerced_ty = .u32_type }, params[1]); 7457 const result = try gz.addExtendedPayload(.wasm_memory_grow, Zir.Inst.BinNode{ 7458 .node = gz.nodeIndexToRelative(node), 7459 .lhs = index_arg, 7460 .rhs = delta_arg, 7461 }); 7462 return rvalue(gz, rl, result, node); 7463 }, 7464 .c_define => { 7465 if (!gz.c_import) return gz.astgen.failNode(node, "C define valid only inside C import block", .{}); 7466 const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[0]); 7467 const value = try comptimeExpr(gz, scope, .none, params[1]); 7468 const result = try gz.addExtendedPayload(.c_define, Zir.Inst.BinNode{ 7469 .node = gz.nodeIndexToRelative(node), 7470 .lhs = name, 7471 .rhs = value, 7472 }); 7473 return rvalue(gz, rl, result, node); 7474 }, 7475 7476 .splat => { 7477 const len = try expr(gz, scope, .{ .coerced_ty = .u32_type }, params[0]); 7478 const scalar = try expr(gz, scope, .none, params[1]); 7479 const result = try gz.addPlNode(.splat, node, Zir.Inst.Bin{ 7480 .lhs = len, 7481 .rhs = scalar, 7482 }); 7483 return rvalue(gz, rl, result, node); 7484 }, 7485 .reduce => { 7486 const op = try expr(gz, scope, .{ .ty = .reduce_op_type }, params[0]); 7487 const scalar = try expr(gz, scope, .none, params[1]); 7488 const result = try gz.addPlNode(.reduce, node, Zir.Inst.Bin{ 7489 .lhs = op, 7490 .rhs = scalar, 7491 }); 7492 return rvalue(gz, rl, result, node); 7493 }, 7494 7495 .maximum => { 7496 const a = try expr(gz, scope, .none, params[0]); 7497 const b = try expr(gz, scope, .none, params[1]); 7498 const result = try gz.addPlNode(.maximum, node, Zir.Inst.Bin{ 7499 .lhs = a, 7500 .rhs = b, 7501 }); 7502 return rvalue(gz, rl, result, node); 7503 }, 7504 .minimum => { 7505 const a = try expr(gz, scope, .none, params[0]); 7506 const b = try expr(gz, scope, .none, params[1]); 7507 const result = try gz.addPlNode(.minimum, node, Zir.Inst.Bin{ 7508 .lhs = a, 7509 .rhs = b, 7510 }); 7511 return rvalue(gz, rl, result, node); 7512 }, 7513 7514 .add_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .add_with_overflow), 7515 .sub_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .sub_with_overflow), 7516 .mul_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .mul_with_overflow), 7517 .shl_with_overflow => { 7518 const int_type = try typeExpr(gz, scope, params[0]); 7519 const log2_int_type = try gz.addUnNode(.log2_int_type, int_type, params[0]); 7520 const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ 7521 .ptr_type_simple = .{ 7522 .is_allowzero = false, 7523 .is_mutable = true, 7524 .is_volatile = false, 7525 .size = .One, 7526 .elem_type = int_type, 7527 }, 7528 } }); 7529 const lhs = try expr(gz, scope, .{ .ty = int_type }, params[1]); 7530 const rhs = try expr(gz, scope, .{ .ty = log2_int_type }, params[2]); 7531 const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[3]); 7532 const result = try gz.addExtendedPayload(.shl_with_overflow, Zir.Inst.OverflowArithmetic{ 7533 .node = gz.nodeIndexToRelative(node), 7534 .lhs = lhs, 7535 .rhs = rhs, 7536 .ptr = ptr, 7537 }); 7538 return rvalue(gz, rl, result, node); 7539 }, 7540 7541 .atomic_load => { 7542 const result = try gz.addPlNode(.atomic_load, node, Zir.Inst.AtomicLoad{ 7543 // zig fmt: off 7544 .elem_type = try typeExpr(gz, scope, params[0]), 7545 .ptr = try expr (gz, scope, .none, params[1]), 7546 .ordering = try expr (gz, scope, .{ .coerced_ty = .atomic_order_type }, params[2]), 7547 // zig fmt: on 7548 }); 7549 return rvalue(gz, rl, result, node); 7550 }, 7551 .atomic_rmw => { 7552 const int_type = try typeExpr(gz, scope, params[0]); 7553 const result = try gz.addPlNode(.atomic_rmw, node, Zir.Inst.AtomicRmw{ 7554 // zig fmt: off 7555 .ptr = try expr(gz, scope, .none, params[1]), 7556 .operation = try expr(gz, scope, .{ .coerced_ty = .atomic_rmw_op_type }, params[2]), 7557 .operand = try expr(gz, scope, .{ .ty = int_type }, params[3]), 7558 .ordering = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[4]), 7559 // zig fmt: on 7560 }); 7561 return rvalue(gz, rl, result, node); 7562 }, 7563 .atomic_store => { 7564 const int_type = try typeExpr(gz, scope, params[0]); 7565 const result = try gz.addPlNode(.atomic_store, node, Zir.Inst.AtomicStore{ 7566 // zig fmt: off 7567 .ptr = try expr(gz, scope, .none, params[1]), 7568 .operand = try expr(gz, scope, .{ .ty = int_type }, params[2]), 7569 .ordering = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[3]), 7570 // zig fmt: on 7571 }); 7572 return rvalue(gz, rl, result, node); 7573 }, 7574 .mul_add => { 7575 const float_type = try typeExpr(gz, scope, params[0]); 7576 const mulend1 = try expr(gz, scope, .{ .coerced_ty = float_type }, params[1]); 7577 const mulend2 = try expr(gz, scope, .{ .coerced_ty = float_type }, params[2]); 7578 const addend = try expr(gz, scope, .{ .ty = float_type }, params[3]); 7579 const result = try gz.addPlNode(.mul_add, node, Zir.Inst.MulAdd{ 7580 .mulend1 = mulend1, 7581 .mulend2 = mulend2, 7582 .addend = addend, 7583 }); 7584 return rvalue(gz, rl, result, node); 7585 }, 7586 .call => { 7587 const options = try comptimeExpr(gz, scope, .{ .ty = .call_options_type }, params[0]); 7588 const callee = try calleeExpr(gz, scope, params[1]); 7589 const args = try expr(gz, scope, .none, params[2]); 7590 const result = try gz.addPlNode(.builtin_call, node, Zir.Inst.BuiltinCall{ 7591 .options = options, 7592 .callee = callee, 7593 .args = args, 7594 .flags = .{ 7595 .is_nosuspend = gz.nosuspend_node != 0, 7596 .is_comptime = gz.force_comptime, 7597 .ensure_result_used = false, 7598 }, 7599 }); 7600 return rvalue(gz, rl, result, node); 7601 }, 7602 .field_parent_ptr => { 7603 const parent_type = try typeExpr(gz, scope, params[0]); 7604 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); 7605 const result = try gz.addPlNode(.field_parent_ptr, node, Zir.Inst.FieldParentPtr{ 7606 .parent_type = parent_type, 7607 .field_name = field_name, 7608 .field_ptr = try expr(gz, scope, .none, params[2]), 7609 }); 7610 return rvalue(gz, rl, result, node); 7611 }, 7612 .memcpy => { 7613 const result = try gz.addPlNode(.memcpy, node, Zir.Inst.Memcpy{ 7614 .dest = try expr(gz, scope, .{ .coerced_ty = .manyptr_u8_type }, params[0]), 7615 .source = try expr(gz, scope, .{ .coerced_ty = .manyptr_const_u8_type }, params[1]), 7616 .byte_count = try expr(gz, scope, .{ .coerced_ty = .usize_type }, params[2]), 7617 }); 7618 return rvalue(gz, rl, result, node); 7619 }, 7620 .memset => { 7621 const result = try gz.addPlNode(.memset, node, Zir.Inst.Memset{ 7622 .dest = try expr(gz, scope, .{ .coerced_ty = .manyptr_u8_type }, params[0]), 7623 .byte = try expr(gz, scope, .{ .coerced_ty = .u8_type }, params[1]), 7624 .byte_count = try expr(gz, scope, .{ .coerced_ty = .usize_type }, params[2]), 7625 }); 7626 return rvalue(gz, rl, result, node); 7627 }, 7628 .shuffle => { 7629 const result = try gz.addPlNode(.shuffle, node, Zir.Inst.Shuffle{ 7630 .elem_type = try typeExpr(gz, scope, params[0]), 7631 .a = try expr(gz, scope, .none, params[1]), 7632 .b = try expr(gz, scope, .none, params[2]), 7633 .mask = try comptimeExpr(gz, scope, .none, params[3]), 7634 }); 7635 return rvalue(gz, rl, result, node); 7636 }, 7637 .select => { 7638 const result = try gz.addPlNode(.select, node, Zir.Inst.Select{ 7639 .elem_type = try typeExpr(gz, scope, params[0]), 7640 .pred = try expr(gz, scope, .none, params[1]), 7641 .a = try expr(gz, scope, .none, params[2]), 7642 .b = try expr(gz, scope, .none, params[3]), 7643 }); 7644 return rvalue(gz, rl, result, node); 7645 }, 7646 .async_call => { 7647 const result = try gz.addPlNode(.builtin_async_call, node, Zir.Inst.AsyncCall{ 7648 .frame_buffer = try expr(gz, scope, .none, params[0]), 7649 .result_ptr = try expr(gz, scope, .none, params[1]), 7650 .fn_ptr = try expr(gz, scope, .none, params[2]), 7651 .args = try expr(gz, scope, .none, params[3]), 7652 }); 7653 return rvalue(gz, rl, result, node); 7654 }, 7655 .Vector => { 7656 const result = try gz.addPlNode(.vector_type, node, Zir.Inst.Bin{ 7657 .lhs = try comptimeExpr(gz, scope, .{ .coerced_ty = .u32_type }, params[0]), 7658 .rhs = try typeExpr(gz, scope, params[1]), 7659 }); 7660 return rvalue(gz, rl, result, node); 7661 }, 7662 .prefetch => { 7663 const ptr = try expr(gz, scope, .none, params[0]); 7664 const options = try comptimeExpr(gz, scope, .{ .ty = .prefetch_options_type }, params[1]); 7665 const result = try gz.addExtendedPayload(.prefetch, Zir.Inst.BinNode{ 7666 .node = gz.nodeIndexToRelative(node), 7667 .lhs = ptr, 7668 .rhs = options, 7669 }); 7670 return rvalue(gz, rl, result, node); 7671 }, 7672 } 7673 } 7674 7675 fn simpleNoOpVoid( 7676 gz: *GenZir, 7677 rl: ResultLoc, 7678 node: Ast.Node.Index, 7679 tag: Zir.Inst.Tag, 7680 ) InnerError!Zir.Inst.Ref { 7681 _ = try gz.addNode(tag, node); 7682 return rvalue(gz, rl, .void_value, node); 7683 } 7684 7685 fn hasDeclOrField( 7686 gz: *GenZir, 7687 scope: *Scope, 7688 rl: ResultLoc, 7689 node: Ast.Node.Index, 7690 lhs_node: Ast.Node.Index, 7691 rhs_node: Ast.Node.Index, 7692 tag: Zir.Inst.Tag, 7693 ) InnerError!Zir.Inst.Ref { 7694 const container_type = try typeExpr(gz, scope, lhs_node); 7695 const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, rhs_node); 7696 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 7697 .lhs = container_type, 7698 .rhs = name, 7699 }); 7700 return rvalue(gz, rl, result, node); 7701 } 7702 7703 fn typeCast( 7704 gz: *GenZir, 7705 scope: *Scope, 7706 rl: ResultLoc, 7707 node: Ast.Node.Index, 7708 lhs_node: Ast.Node.Index, 7709 rhs_node: Ast.Node.Index, 7710 tag: Zir.Inst.Tag, 7711 ) InnerError!Zir.Inst.Ref { 7712 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 7713 .lhs = try typeExpr(gz, scope, lhs_node), 7714 .rhs = try expr(gz, scope, .none, rhs_node), 7715 }); 7716 return rvalue(gz, rl, result, node); 7717 } 7718 7719 fn simpleUnOpType( 7720 gz: *GenZir, 7721 scope: *Scope, 7722 rl: ResultLoc, 7723 node: Ast.Node.Index, 7724 operand_node: Ast.Node.Index, 7725 tag: Zir.Inst.Tag, 7726 ) InnerError!Zir.Inst.Ref { 7727 const operand = try typeExpr(gz, scope, operand_node); 7728 const result = try gz.addUnNode(tag, operand, node); 7729 return rvalue(gz, rl, result, node); 7730 } 7731 7732 fn simpleUnOp( 7733 gz: *GenZir, 7734 scope: *Scope, 7735 rl: ResultLoc, 7736 node: Ast.Node.Index, 7737 operand_rl: ResultLoc, 7738 operand_node: Ast.Node.Index, 7739 tag: Zir.Inst.Tag, 7740 ) InnerError!Zir.Inst.Ref { 7741 const operand = try expr(gz, scope, operand_rl, operand_node); 7742 const result = try gz.addUnNode(tag, operand, node); 7743 return rvalue(gz, rl, result, node); 7744 } 7745 7746 fn negation( 7747 gz: *GenZir, 7748 scope: *Scope, 7749 rl: ResultLoc, 7750 node: Ast.Node.Index, 7751 ) InnerError!Zir.Inst.Ref { 7752 const astgen = gz.astgen; 7753 const tree = astgen.tree; 7754 const node_tags = tree.nodes.items(.tag); 7755 const node_datas = tree.nodes.items(.data); 7756 7757 // Check for float literal as the sub-expression because we want to preserve 7758 // its negativity rather than having it go through comptime subtraction. 7759 const operand_node = node_datas[node].lhs; 7760 if (node_tags[operand_node] == .float_literal) { 7761 return floatLiteral(gz, rl, operand_node, .negative); 7762 } 7763 7764 const operand = try expr(gz, scope, .none, operand_node); 7765 const result = try gz.addUnNode(.negate, operand, node); 7766 return rvalue(gz, rl, result, node); 7767 } 7768 7769 fn cmpxchg( 7770 gz: *GenZir, 7771 scope: *Scope, 7772 rl: ResultLoc, 7773 node: Ast.Node.Index, 7774 params: []const Ast.Node.Index, 7775 tag: Zir.Inst.Tag, 7776 ) InnerError!Zir.Inst.Ref { 7777 const int_type = try typeExpr(gz, scope, params[0]); 7778 const result = try gz.addPlNode(tag, node, Zir.Inst.Cmpxchg{ 7779 // zig fmt: off 7780 .ptr = try expr(gz, scope, .none, params[1]), 7781 .expected_value = try expr(gz, scope, .{ .ty = int_type }, params[2]), 7782 .new_value = try expr(gz, scope, .{ .coerced_ty = int_type }, params[3]), 7783 .success_order = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[4]), 7784 .failure_order = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[5]), 7785 // zig fmt: on 7786 }); 7787 return rvalue(gz, rl, result, node); 7788 } 7789 7790 fn bitBuiltin( 7791 gz: *GenZir, 7792 scope: *Scope, 7793 rl: ResultLoc, 7794 node: Ast.Node.Index, 7795 int_type_node: Ast.Node.Index, 7796 operand_node: Ast.Node.Index, 7797 tag: Zir.Inst.Tag, 7798 ) InnerError!Zir.Inst.Ref { 7799 // The accepted proposal https://github.com/ziglang/zig/issues/6835 7800 // tells us to remove the type parameter from these builtins. To stay 7801 // source-compatible with stage1, we still observe the parameter here, 7802 // but we do not encode it into the ZIR. To implement this proposal in 7803 // stage2, only AstGen code will need to be changed. 7804 _ = try typeExpr(gz, scope, int_type_node); 7805 7806 const operand = try expr(gz, scope, .none, operand_node); 7807 const result = try gz.addUnNode(tag, operand, node); 7808 return rvalue(gz, rl, result, node); 7809 } 7810 7811 fn divBuiltin( 7812 gz: *GenZir, 7813 scope: *Scope, 7814 rl: ResultLoc, 7815 node: Ast.Node.Index, 7816 lhs_node: Ast.Node.Index, 7817 rhs_node: Ast.Node.Index, 7818 tag: Zir.Inst.Tag, 7819 ) InnerError!Zir.Inst.Ref { 7820 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 7821 .lhs = try expr(gz, scope, .none, lhs_node), 7822 .rhs = try expr(gz, scope, .none, rhs_node), 7823 }); 7824 return rvalue(gz, rl, result, node); 7825 } 7826 7827 fn simpleCBuiltin( 7828 gz: *GenZir, 7829 scope: *Scope, 7830 rl: ResultLoc, 7831 node: Ast.Node.Index, 7832 operand_node: Ast.Node.Index, 7833 tag: Zir.Inst.Extended, 7834 ) InnerError!Zir.Inst.Ref { 7835 const name: []const u8 = if (tag == .c_undef) "C undef" else "C include"; 7836 if (!gz.c_import) return gz.astgen.failNode(node, "{s} valid only inside C import block", .{name}); 7837 const operand = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, operand_node); 7838 _ = try gz.addExtendedPayload(tag, Zir.Inst.UnNode{ 7839 .node = gz.nodeIndexToRelative(node), 7840 .operand = operand, 7841 }); 7842 return rvalue(gz, rl, .void_value, node); 7843 } 7844 7845 fn offsetOf( 7846 gz: *GenZir, 7847 scope: *Scope, 7848 rl: ResultLoc, 7849 node: Ast.Node.Index, 7850 lhs_node: Ast.Node.Index, 7851 rhs_node: Ast.Node.Index, 7852 tag: Zir.Inst.Tag, 7853 ) InnerError!Zir.Inst.Ref { 7854 const type_inst = try typeExpr(gz, scope, lhs_node); 7855 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, rhs_node); 7856 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 7857 .lhs = type_inst, 7858 .rhs = field_name, 7859 }); 7860 return rvalue(gz, rl, result, node); 7861 } 7862 7863 fn shiftOp( 7864 gz: *GenZir, 7865 scope: *Scope, 7866 rl: ResultLoc, 7867 node: Ast.Node.Index, 7868 lhs_node: Ast.Node.Index, 7869 rhs_node: Ast.Node.Index, 7870 tag: Zir.Inst.Tag, 7871 ) InnerError!Zir.Inst.Ref { 7872 const lhs = try expr(gz, scope, .none, lhs_node); 7873 const log2_int_type = try gz.addUnNode(.typeof_log2_int_type, lhs, lhs_node); 7874 const rhs = try expr(gz, scope, .{ .ty = log2_int_type }, rhs_node); 7875 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 7876 .lhs = lhs, 7877 .rhs = rhs, 7878 }); 7879 return rvalue(gz, rl, result, node); 7880 } 7881 7882 fn cImport( 7883 gz: *GenZir, 7884 scope: *Scope, 7885 node: Ast.Node.Index, 7886 body_node: Ast.Node.Index, 7887 ) InnerError!Zir.Inst.Ref { 7888 const astgen = gz.astgen; 7889 const gpa = astgen.gpa; 7890 7891 var block_scope = gz.makeSubBlock(scope); 7892 block_scope.force_comptime = true; 7893 block_scope.c_import = true; 7894 defer block_scope.unstack(); 7895 7896 const block_inst = try gz.makeBlockInst(.c_import, node); 7897 const block_result = try expr(&block_scope, &block_scope.base, .none, body_node); 7898 _ = try gz.addUnNode(.ensure_result_used, block_result, node); 7899 if (!gz.refIsNoReturn(block_result)) { 7900 _ = try block_scope.addBreak(.break_inline, block_inst, .void_value); 7901 } 7902 try block_scope.setBlockBody(block_inst); 7903 // block_scope unstacked now, can add new instructions to gz 7904 try gz.instructions.append(gpa, block_inst); 7905 7906 return indexToRef(block_inst); 7907 } 7908 7909 fn overflowArithmetic( 7910 gz: *GenZir, 7911 scope: *Scope, 7912 rl: ResultLoc, 7913 node: Ast.Node.Index, 7914 params: []const Ast.Node.Index, 7915 tag: Zir.Inst.Extended, 7916 ) InnerError!Zir.Inst.Ref { 7917 const int_type = try typeExpr(gz, scope, params[0]); 7918 const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ 7919 .ptr_type_simple = .{ 7920 .is_allowzero = false, 7921 .is_mutable = true, 7922 .is_volatile = false, 7923 .size = .One, 7924 .elem_type = int_type, 7925 }, 7926 } }); 7927 const lhs = try expr(gz, scope, .{ .ty = int_type }, params[1]); 7928 const rhs = try expr(gz, scope, .{ .ty = int_type }, params[2]); 7929 const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[3]); 7930 const result = try gz.addExtendedPayload(tag, Zir.Inst.OverflowArithmetic{ 7931 .node = gz.nodeIndexToRelative(node), 7932 .lhs = lhs, 7933 .rhs = rhs, 7934 .ptr = ptr, 7935 }); 7936 return rvalue(gz, rl, result, node); 7937 } 7938 7939 fn callExpr( 7940 gz: *GenZir, 7941 scope: *Scope, 7942 rl: ResultLoc, 7943 node: Ast.Node.Index, 7944 call: Ast.full.Call, 7945 ) InnerError!Zir.Inst.Ref { 7946 const astgen = gz.astgen; 7947 7948 const callee = try calleeExpr(gz, scope, call.ast.fn_expr); 7949 const modifier: std.builtin.CallOptions.Modifier = blk: { 7950 if (gz.force_comptime) { 7951 break :blk .compile_time; 7952 } 7953 if (call.async_token != null) { 7954 break :blk .async_kw; 7955 } 7956 if (gz.nosuspend_node != 0) { 7957 break :blk .no_async; 7958 } 7959 break :blk .auto; 7960 }; 7961 7962 { 7963 astgen.advanceSourceCursor(astgen.tree.tokens.items(.start)[call.ast.lparen]); 7964 const line = astgen.source_line - gz.decl_line; 7965 const column = astgen.source_column; 7966 7967 _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{ 7968 .dbg_stmt = .{ 7969 .line = line, 7970 .column = column, 7971 }, 7972 } }); 7973 } 7974 7975 assert(callee != .none); 7976 assert(node != 0); 7977 7978 const payload_index = try addExtra(astgen, Zir.Inst.Call{ 7979 .callee = callee, 7980 .flags = .{ 7981 .packed_modifier = @intCast(Zir.Inst.Call.Flags.PackedModifier, @enumToInt(modifier)), 7982 .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len), 7983 }, 7984 }); 7985 var extra_index = try reserveExtra(astgen, call.ast.params.len); 7986 7987 for (call.ast.params) |param_node, i| { 7988 const param_type = try gz.add(.{ 7989 .tag = .param_type, 7990 .data = .{ .param_type = .{ 7991 .callee = callee, 7992 .param_index = @intCast(u32, i), 7993 } }, 7994 }); 7995 const arg_ref = try expr(gz, scope, .{ .coerced_ty = param_type }, param_node); 7996 astgen.extra.items[extra_index] = @enumToInt(arg_ref); 7997 extra_index += 1; 7998 } 7999 8000 const call_inst = try gz.addPlNodePayloadIndex(.call, node, payload_index); 8001 return rvalue(gz, rl, call_inst, node); // TODO function call with result location 8002 } 8003 8004 /// calleeExpr generates the function part of a call expression (f in f(x)), or the 8005 /// callee argument to the @call() builtin. If the lhs is a field access or the 8006 /// @field() builtin, we need to generate a special field_call_bind instruction 8007 /// instead of the normal field_val or field_ptr. If this is a inst.func() call, 8008 /// this instruction will capture the value of the first argument before evaluating 8009 /// the other arguments. We need to use .ref here to guarantee we will be able to 8010 /// promote an lvalue to an address if the first parameter requires it. This 8011 /// unfortunately also means we need to take a reference to any types on the lhs. 8012 fn calleeExpr( 8013 gz: *GenZir, 8014 scope: *Scope, 8015 node: Ast.Node.Index, 8016 ) InnerError!Zir.Inst.Ref { 8017 const astgen = gz.astgen; 8018 const tree = astgen.tree; 8019 8020 const tag = tree.nodes.items(.tag)[node]; 8021 switch (tag) { 8022 .field_access => return addFieldAccess(.field_call_bind, gz, scope, .ref, node), 8023 8024 .builtin_call_two, 8025 .builtin_call_two_comma, 8026 .builtin_call, 8027 .builtin_call_comma, 8028 => { 8029 const node_datas = tree.nodes.items(.data); 8030 const main_tokens = tree.nodes.items(.main_token); 8031 const builtin_token = main_tokens[node]; 8032 const builtin_name = tree.tokenSlice(builtin_token); 8033 8034 var inline_params: [2]Ast.Node.Index = undefined; 8035 var params: []Ast.Node.Index = switch (tag) { 8036 .builtin_call, 8037 .builtin_call_comma, 8038 => tree.extra_data[node_datas[node].lhs..node_datas[node].rhs], 8039 8040 .builtin_call_two, 8041 .builtin_call_two_comma, 8042 => blk: { 8043 inline_params = .{ node_datas[node].lhs, node_datas[node].rhs }; 8044 const len: usize = if (inline_params[0] == 0) @as(usize, 0) else if (inline_params[1] == 0) @as(usize, 1) else @as(usize, 2); 8045 break :blk inline_params[0..len]; 8046 }, 8047 8048 else => unreachable, 8049 }; 8050 8051 // If anything is wrong, fall back to builtinCall. 8052 // It will emit any necessary compile errors and notes. 8053 if (std.mem.eql(u8, builtin_name, "@field") and params.len == 2) { 8054 const lhs = try expr(gz, scope, .ref, params[0]); 8055 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); 8056 return gz.addExtendedPayload(.field_call_bind_named, Zir.Inst.FieldNamedNode{ 8057 .node = gz.nodeIndexToRelative(node), 8058 .lhs = lhs, 8059 .field_name = field_name, 8060 }); 8061 } 8062 8063 return builtinCall(gz, scope, .none, node, params); 8064 }, 8065 else => return expr(gz, scope, .none, node), 8066 } 8067 } 8068 8069 const primitives = std.ComptimeStringMap(Zir.Inst.Ref, .{ 8070 .{ "anyerror", .anyerror_type }, 8071 .{ "anyframe", .anyframe_type }, 8072 .{ "anyopaque", .anyopaque_type }, 8073 .{ "bool", .bool_type }, 8074 .{ "c_int", .c_int_type }, 8075 .{ "c_long", .c_long_type }, 8076 .{ "c_longdouble", .c_longdouble_type }, 8077 .{ "c_longlong", .c_longlong_type }, 8078 .{ "c_short", .c_short_type }, 8079 .{ "c_uint", .c_uint_type }, 8080 .{ "c_ulong", .c_ulong_type }, 8081 .{ "c_ulonglong", .c_ulonglong_type }, 8082 .{ "c_ushort", .c_ushort_type }, 8083 .{ "comptime_float", .comptime_float_type }, 8084 .{ "comptime_int", .comptime_int_type }, 8085 .{ "f128", .f128_type }, 8086 .{ "f16", .f16_type }, 8087 .{ "f32", .f32_type }, 8088 .{ "f64", .f64_type }, 8089 .{ "f80", .f80_type }, 8090 .{ "false", .bool_false }, 8091 .{ "i16", .i16_type }, 8092 .{ "i32", .i32_type }, 8093 .{ "i64", .i64_type }, 8094 .{ "i128", .i128_type }, 8095 .{ "i8", .i8_type }, 8096 .{ "isize", .isize_type }, 8097 .{ "noreturn", .noreturn_type }, 8098 .{ "null", .null_value }, 8099 .{ "true", .bool_true }, 8100 .{ "type", .type_type }, 8101 .{ "u16", .u16_type }, 8102 .{ "u29", .u29_type }, 8103 .{ "u32", .u32_type }, 8104 .{ "u64", .u64_type }, 8105 .{ "u128", .u128_type }, 8106 .{ "u1", .u1_type }, 8107 .{ "u8", .u8_type }, 8108 .{ "undefined", .undef }, 8109 .{ "usize", .usize_type }, 8110 .{ "void", .void_type }, 8111 }); 8112 8113 fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index, have_res_ty: bool) bool { 8114 const node_tags = tree.nodes.items(.tag); 8115 const node_datas = tree.nodes.items(.data); 8116 const main_tokens = tree.nodes.items(.main_token); 8117 const token_tags = tree.tokens.items(.tag); 8118 8119 var node = start_node; 8120 while (true) { 8121 switch (node_tags[node]) { 8122 .root, 8123 .@"usingnamespace", 8124 .test_decl, 8125 .switch_case, 8126 .switch_case_one, 8127 .container_field_init, 8128 .container_field_align, 8129 .container_field, 8130 .asm_output, 8131 .asm_input, 8132 => unreachable, 8133 8134 .@"return", 8135 .@"break", 8136 .@"continue", 8137 .bit_not, 8138 .bool_not, 8139 .global_var_decl, 8140 .local_var_decl, 8141 .simple_var_decl, 8142 .aligned_var_decl, 8143 .@"defer", 8144 .@"errdefer", 8145 .address_of, 8146 .optional_type, 8147 .negation, 8148 .negation_wrap, 8149 .@"resume", 8150 .array_type, 8151 .array_type_sentinel, 8152 .ptr_type_aligned, 8153 .ptr_type_sentinel, 8154 .ptr_type, 8155 .ptr_type_bit_range, 8156 .@"suspend", 8157 .fn_proto_simple, 8158 .fn_proto_multi, 8159 .fn_proto_one, 8160 .fn_proto, 8161 .fn_decl, 8162 .anyframe_type, 8163 .anyframe_literal, 8164 .integer_literal, 8165 .float_literal, 8166 .enum_literal, 8167 .string_literal, 8168 .multiline_string_literal, 8169 .char_literal, 8170 .unreachable_literal, 8171 .identifier, 8172 .error_set_decl, 8173 .container_decl, 8174 .container_decl_trailing, 8175 .container_decl_two, 8176 .container_decl_two_trailing, 8177 .container_decl_arg, 8178 .container_decl_arg_trailing, 8179 .tagged_union, 8180 .tagged_union_trailing, 8181 .tagged_union_two, 8182 .tagged_union_two_trailing, 8183 .tagged_union_enum_tag, 8184 .tagged_union_enum_tag_trailing, 8185 .@"asm", 8186 .asm_simple, 8187 .add, 8188 .add_wrap, 8189 .add_sat, 8190 .array_cat, 8191 .array_mult, 8192 .assign, 8193 .assign_bit_and, 8194 .assign_bit_or, 8195 .assign_shl, 8196 .assign_shl_sat, 8197 .assign_shr, 8198 .assign_bit_xor, 8199 .assign_div, 8200 .assign_sub, 8201 .assign_sub_wrap, 8202 .assign_sub_sat, 8203 .assign_mod, 8204 .assign_add, 8205 .assign_add_wrap, 8206 .assign_add_sat, 8207 .assign_mul, 8208 .assign_mul_wrap, 8209 .assign_mul_sat, 8210 .bang_equal, 8211 .bit_and, 8212 .bit_or, 8213 .shl, 8214 .shl_sat, 8215 .shr, 8216 .bit_xor, 8217 .bool_and, 8218 .bool_or, 8219 .div, 8220 .equal_equal, 8221 .error_union, 8222 .greater_or_equal, 8223 .greater_than, 8224 .less_or_equal, 8225 .less_than, 8226 .merge_error_sets, 8227 .mod, 8228 .mul, 8229 .mul_wrap, 8230 .mul_sat, 8231 .switch_range, 8232 .field_access, 8233 .sub, 8234 .sub_wrap, 8235 .sub_sat, 8236 .slice, 8237 .slice_open, 8238 .slice_sentinel, 8239 .deref, 8240 .array_access, 8241 .error_value, 8242 .while_simple, // This variant cannot have an else expression. 8243 .while_cont, // This variant cannot have an else expression. 8244 .for_simple, // This variant cannot have an else expression. 8245 .if_simple, // This variant cannot have an else expression. 8246 => return false, 8247 8248 // Forward the question to the LHS sub-expression. 8249 .grouped_expression, 8250 .@"try", 8251 .@"await", 8252 .@"comptime", 8253 .@"nosuspend", 8254 .unwrap_optional, 8255 => node = node_datas[node].lhs, 8256 8257 // Forward the question to the RHS sub-expression. 8258 .@"catch", 8259 .@"orelse", 8260 => node = node_datas[node].rhs, 8261 8262 // Array and struct init exprs write to result locs, but anon literals do not. 8263 .array_init_one, 8264 .array_init_one_comma, 8265 .struct_init_one, 8266 .struct_init_one_comma, 8267 .array_init, 8268 .array_init_comma, 8269 .struct_init, 8270 .struct_init_comma, 8271 => return have_res_ty or node_datas[node].lhs != 0, 8272 8273 // Anon literals do not need result location. 8274 .array_init_dot_two, 8275 .array_init_dot_two_comma, 8276 .array_init_dot, 8277 .array_init_dot_comma, 8278 .struct_init_dot_two, 8279 .struct_init_dot_two_comma, 8280 .struct_init_dot, 8281 .struct_init_dot_comma, 8282 => return have_res_ty, 8283 8284 // True because depending on comptime conditions, sub-expressions 8285 // may be the kind that need memory locations. 8286 .@"while", // This variant always has an else expression. 8287 .@"if", // This variant always has an else expression. 8288 .@"for", // This variant always has an else expression. 8289 .@"switch", 8290 .switch_comma, 8291 .call_one, 8292 .call_one_comma, 8293 .async_call_one, 8294 .async_call_one_comma, 8295 .call, 8296 .call_comma, 8297 .async_call, 8298 .async_call_comma, 8299 => return true, 8300 8301 .block_two, 8302 .block_two_semicolon, 8303 .block, 8304 .block_semicolon, 8305 => { 8306 const lbrace = main_tokens[node]; 8307 if (token_tags[lbrace - 1] == .colon) { 8308 // Labeled blocks may need a memory location to forward 8309 // to their break statements. 8310 return true; 8311 } else { 8312 return false; 8313 } 8314 }, 8315 8316 .builtin_call_two, .builtin_call_two_comma => { 8317 const builtin_token = main_tokens[node]; 8318 const builtin_name = tree.tokenSlice(builtin_token); 8319 // If the builtin is an invalid name, we don't cause an error here; instead 8320 // let it pass, and the error will be "invalid builtin function" later. 8321 const builtin_info = BuiltinFn.list.get(builtin_name) orelse return false; 8322 switch (builtin_info.needs_mem_loc) { 8323 .never => return false, 8324 .always => return true, 8325 .forward1 => node = node_datas[node].rhs, 8326 } 8327 }, 8328 8329 .builtin_call, .builtin_call_comma => { 8330 const params = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs]; 8331 const builtin_token = main_tokens[node]; 8332 const builtin_name = tree.tokenSlice(builtin_token); 8333 // If the builtin is an invalid name, we don't cause an error here; instead 8334 // let it pass, and the error will be "invalid builtin function" later. 8335 const builtin_info = BuiltinFn.list.get(builtin_name) orelse return false; 8336 switch (builtin_info.needs_mem_loc) { 8337 .never => return false, 8338 .always => return true, 8339 .forward1 => node = params[1], 8340 } 8341 }, 8342 } 8343 } 8344 } 8345 8346 fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.EvalToError { 8347 const node_tags = tree.nodes.items(.tag); 8348 const node_datas = tree.nodes.items(.data); 8349 const main_tokens = tree.nodes.items(.main_token); 8350 const token_tags = tree.tokens.items(.tag); 8351 8352 var node = start_node; 8353 while (true) { 8354 switch (node_tags[node]) { 8355 .root, 8356 .@"usingnamespace", 8357 .test_decl, 8358 .switch_case, 8359 .switch_case_one, 8360 .container_field_init, 8361 .container_field_align, 8362 .container_field, 8363 .asm_output, 8364 .asm_input, 8365 => unreachable, 8366 8367 .error_value => return .always, 8368 8369 .@"asm", 8370 .asm_simple, 8371 .identifier, 8372 .field_access, 8373 .deref, 8374 .array_access, 8375 .while_simple, 8376 .while_cont, 8377 .for_simple, 8378 .if_simple, 8379 .@"while", 8380 .@"if", 8381 .@"for", 8382 .@"switch", 8383 .switch_comma, 8384 .call_one, 8385 .call_one_comma, 8386 .async_call_one, 8387 .async_call_one_comma, 8388 .call, 8389 .call_comma, 8390 .async_call, 8391 .async_call_comma, 8392 => return .maybe, 8393 8394 .@"return", 8395 .@"break", 8396 .@"continue", 8397 .bit_not, 8398 .bool_not, 8399 .global_var_decl, 8400 .local_var_decl, 8401 .simple_var_decl, 8402 .aligned_var_decl, 8403 .@"defer", 8404 .@"errdefer", 8405 .address_of, 8406 .optional_type, 8407 .negation, 8408 .negation_wrap, 8409 .@"resume", 8410 .array_type, 8411 .array_type_sentinel, 8412 .ptr_type_aligned, 8413 .ptr_type_sentinel, 8414 .ptr_type, 8415 .ptr_type_bit_range, 8416 .@"suspend", 8417 .fn_proto_simple, 8418 .fn_proto_multi, 8419 .fn_proto_one, 8420 .fn_proto, 8421 .fn_decl, 8422 .anyframe_type, 8423 .anyframe_literal, 8424 .integer_literal, 8425 .float_literal, 8426 .enum_literal, 8427 .string_literal, 8428 .multiline_string_literal, 8429 .char_literal, 8430 .unreachable_literal, 8431 .error_set_decl, 8432 .container_decl, 8433 .container_decl_trailing, 8434 .container_decl_two, 8435 .container_decl_two_trailing, 8436 .container_decl_arg, 8437 .container_decl_arg_trailing, 8438 .tagged_union, 8439 .tagged_union_trailing, 8440 .tagged_union_two, 8441 .tagged_union_two_trailing, 8442 .tagged_union_enum_tag, 8443 .tagged_union_enum_tag_trailing, 8444 .add, 8445 .add_wrap, 8446 .add_sat, 8447 .array_cat, 8448 .array_mult, 8449 .assign, 8450 .assign_bit_and, 8451 .assign_bit_or, 8452 .assign_shl, 8453 .assign_shl_sat, 8454 .assign_shr, 8455 .assign_bit_xor, 8456 .assign_div, 8457 .assign_sub, 8458 .assign_sub_wrap, 8459 .assign_sub_sat, 8460 .assign_mod, 8461 .assign_add, 8462 .assign_add_wrap, 8463 .assign_add_sat, 8464 .assign_mul, 8465 .assign_mul_wrap, 8466 .assign_mul_sat, 8467 .bang_equal, 8468 .bit_and, 8469 .bit_or, 8470 .shl, 8471 .shl_sat, 8472 .shr, 8473 .bit_xor, 8474 .bool_and, 8475 .bool_or, 8476 .div, 8477 .equal_equal, 8478 .error_union, 8479 .greater_or_equal, 8480 .greater_than, 8481 .less_or_equal, 8482 .less_than, 8483 .merge_error_sets, 8484 .mod, 8485 .mul, 8486 .mul_wrap, 8487 .mul_sat, 8488 .switch_range, 8489 .sub, 8490 .sub_wrap, 8491 .sub_sat, 8492 .slice, 8493 .slice_open, 8494 .slice_sentinel, 8495 .array_init_one, 8496 .array_init_one_comma, 8497 .array_init_dot_two, 8498 .array_init_dot_two_comma, 8499 .array_init_dot, 8500 .array_init_dot_comma, 8501 .array_init, 8502 .array_init_comma, 8503 .struct_init_one, 8504 .struct_init_one_comma, 8505 .struct_init_dot_two, 8506 .struct_init_dot_two_comma, 8507 .struct_init_dot, 8508 .struct_init_dot_comma, 8509 .struct_init, 8510 .struct_init_comma, 8511 => return .never, 8512 8513 // Forward the question to the LHS sub-expression. 8514 .grouped_expression, 8515 .@"try", 8516 .@"await", 8517 .@"comptime", 8518 .@"nosuspend", 8519 .unwrap_optional, 8520 => node = node_datas[node].lhs, 8521 8522 // LHS sub-expression may still be an error under the outer optional or error union 8523 .@"catch", 8524 .@"orelse", 8525 => return .maybe, 8526 8527 .block_two, 8528 .block_two_semicolon, 8529 .block, 8530 .block_semicolon, 8531 => { 8532 const lbrace = main_tokens[node]; 8533 if (token_tags[lbrace - 1] == .colon) { 8534 // Labeled blocks may need a memory location to forward 8535 // to their break statements. 8536 return .maybe; 8537 } else { 8538 return .never; 8539 } 8540 }, 8541 8542 .builtin_call, 8543 .builtin_call_comma, 8544 .builtin_call_two, 8545 .builtin_call_two_comma, 8546 => { 8547 const builtin_token = main_tokens[node]; 8548 const builtin_name = tree.tokenSlice(builtin_token); 8549 // If the builtin is an invalid name, we don't cause an error here; instead 8550 // let it pass, and the error will be "invalid builtin function" later. 8551 const builtin_info = BuiltinFn.list.get(builtin_name) orelse return .maybe; 8552 return builtin_info.eval_to_error; 8553 }, 8554 } 8555 } 8556 } 8557 8558 /// Returns `true` if it is known the type expression has more than one possible value; 8559 /// `false` otherwise. 8560 fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.Index) bool { 8561 const node_tags = tree.nodes.items(.tag); 8562 const node_datas = tree.nodes.items(.data); 8563 8564 var node = start_node; 8565 while (true) { 8566 switch (node_tags[node]) { 8567 .root, 8568 .@"usingnamespace", 8569 .test_decl, 8570 .switch_case, 8571 .switch_case_one, 8572 .container_field_init, 8573 .container_field_align, 8574 .container_field, 8575 .asm_output, 8576 .asm_input, 8577 .global_var_decl, 8578 .local_var_decl, 8579 .simple_var_decl, 8580 .aligned_var_decl, 8581 => unreachable, 8582 8583 .@"return", 8584 .@"break", 8585 .@"continue", 8586 .bit_not, 8587 .bool_not, 8588 .@"defer", 8589 .@"errdefer", 8590 .address_of, 8591 .negation, 8592 .negation_wrap, 8593 .@"resume", 8594 .array_type, 8595 .@"suspend", 8596 .fn_decl, 8597 .anyframe_literal, 8598 .integer_literal, 8599 .float_literal, 8600 .enum_literal, 8601 .string_literal, 8602 .multiline_string_literal, 8603 .char_literal, 8604 .unreachable_literal, 8605 .error_set_decl, 8606 .container_decl, 8607 .container_decl_trailing, 8608 .container_decl_two, 8609 .container_decl_two_trailing, 8610 .container_decl_arg, 8611 .container_decl_arg_trailing, 8612 .tagged_union, 8613 .tagged_union_trailing, 8614 .tagged_union_two, 8615 .tagged_union_two_trailing, 8616 .tagged_union_enum_tag, 8617 .tagged_union_enum_tag_trailing, 8618 .@"asm", 8619 .asm_simple, 8620 .add, 8621 .add_wrap, 8622 .add_sat, 8623 .array_cat, 8624 .array_mult, 8625 .assign, 8626 .assign_bit_and, 8627 .assign_bit_or, 8628 .assign_shl, 8629 .assign_shl_sat, 8630 .assign_shr, 8631 .assign_bit_xor, 8632 .assign_div, 8633 .assign_sub, 8634 .assign_sub_wrap, 8635 .assign_sub_sat, 8636 .assign_mod, 8637 .assign_add, 8638 .assign_add_wrap, 8639 .assign_add_sat, 8640 .assign_mul, 8641 .assign_mul_wrap, 8642 .assign_mul_sat, 8643 .bang_equal, 8644 .bit_and, 8645 .bit_or, 8646 .shl, 8647 .shl_sat, 8648 .shr, 8649 .bit_xor, 8650 .bool_and, 8651 .bool_or, 8652 .div, 8653 .equal_equal, 8654 .error_union, 8655 .greater_or_equal, 8656 .greater_than, 8657 .less_or_equal, 8658 .less_than, 8659 .merge_error_sets, 8660 .mod, 8661 .mul, 8662 .mul_wrap, 8663 .mul_sat, 8664 .switch_range, 8665 .field_access, 8666 .sub, 8667 .sub_wrap, 8668 .sub_sat, 8669 .slice, 8670 .slice_open, 8671 .slice_sentinel, 8672 .deref, 8673 .array_access, 8674 .error_value, 8675 .while_simple, 8676 .while_cont, 8677 .for_simple, 8678 .if_simple, 8679 .@"catch", 8680 .@"orelse", 8681 .array_init_one, 8682 .array_init_one_comma, 8683 .array_init_dot_two, 8684 .array_init_dot_two_comma, 8685 .array_init_dot, 8686 .array_init_dot_comma, 8687 .array_init, 8688 .array_init_comma, 8689 .struct_init_one, 8690 .struct_init_one_comma, 8691 .struct_init_dot_two, 8692 .struct_init_dot_two_comma, 8693 .struct_init_dot, 8694 .struct_init_dot_comma, 8695 .struct_init, 8696 .struct_init_comma, 8697 .@"while", 8698 .@"if", 8699 .@"for", 8700 .@"switch", 8701 .switch_comma, 8702 .call_one, 8703 .call_one_comma, 8704 .async_call_one, 8705 .async_call_one_comma, 8706 .call, 8707 .call_comma, 8708 .async_call, 8709 .async_call_comma, 8710 .block_two, 8711 .block_two_semicolon, 8712 .block, 8713 .block_semicolon, 8714 .builtin_call, 8715 .builtin_call_comma, 8716 .builtin_call_two, 8717 .builtin_call_two_comma, 8718 // these are function bodies, not pointers 8719 .fn_proto_simple, 8720 .fn_proto_multi, 8721 .fn_proto_one, 8722 .fn_proto, 8723 => return false, 8724 8725 // Forward the question to the LHS sub-expression. 8726 .grouped_expression, 8727 .@"try", 8728 .@"await", 8729 .@"comptime", 8730 .@"nosuspend", 8731 .unwrap_optional, 8732 => node = node_datas[node].lhs, 8733 8734 .ptr_type_aligned, 8735 .ptr_type_sentinel, 8736 .ptr_type, 8737 .ptr_type_bit_range, 8738 .optional_type, 8739 .anyframe_type, 8740 .array_type_sentinel, 8741 => return true, 8742 8743 .identifier => { 8744 const main_tokens = tree.nodes.items(.main_token); 8745 const ident_bytes = tree.tokenSlice(main_tokens[node]); 8746 if (primitives.get(ident_bytes)) |primitive| switch (primitive) { 8747 .anyerror_type, 8748 .anyframe_type, 8749 .anyopaque_type, 8750 .bool_type, 8751 .c_int_type, 8752 .c_long_type, 8753 .c_longdouble_type, 8754 .c_longlong_type, 8755 .c_short_type, 8756 .c_uint_type, 8757 .c_ulong_type, 8758 .c_ulonglong_type, 8759 .c_ushort_type, 8760 .comptime_float_type, 8761 .comptime_int_type, 8762 .f16_type, 8763 .f32_type, 8764 .f64_type, 8765 .f80_type, 8766 .f128_type, 8767 .i16_type, 8768 .i32_type, 8769 .i64_type, 8770 .i128_type, 8771 .i8_type, 8772 .isize_type, 8773 .type_type, 8774 .u16_type, 8775 .u29_type, 8776 .u32_type, 8777 .u64_type, 8778 .u128_type, 8779 .u1_type, 8780 .u8_type, 8781 .usize_type, 8782 => return true, 8783 8784 .void_type, 8785 .bool_false, 8786 .bool_true, 8787 .null_value, 8788 .undef, 8789 .noreturn_type, 8790 => return false, 8791 8792 else => unreachable, // that's all the values from `primitives`. 8793 } else { 8794 return false; 8795 } 8796 }, 8797 } 8798 } 8799 } 8800 8801 /// Returns `true` if it is known the expression is a type that cannot be used at runtime; 8802 /// `false` otherwise. 8803 fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool { 8804 const node_tags = tree.nodes.items(.tag); 8805 const node_datas = tree.nodes.items(.data); 8806 8807 var node = start_node; 8808 while (true) { 8809 switch (node_tags[node]) { 8810 .root, 8811 .@"usingnamespace", 8812 .test_decl, 8813 .switch_case, 8814 .switch_case_one, 8815 .container_field_init, 8816 .container_field_align, 8817 .container_field, 8818 .asm_output, 8819 .asm_input, 8820 .global_var_decl, 8821 .local_var_decl, 8822 .simple_var_decl, 8823 .aligned_var_decl, 8824 => unreachable, 8825 8826 .@"return", 8827 .@"break", 8828 .@"continue", 8829 .bit_not, 8830 .bool_not, 8831 .@"defer", 8832 .@"errdefer", 8833 .address_of, 8834 .negation, 8835 .negation_wrap, 8836 .@"resume", 8837 .array_type, 8838 .@"suspend", 8839 .fn_decl, 8840 .anyframe_literal, 8841 .integer_literal, 8842 .float_literal, 8843 .enum_literal, 8844 .string_literal, 8845 .multiline_string_literal, 8846 .char_literal, 8847 .unreachable_literal, 8848 .error_set_decl, 8849 .container_decl, 8850 .container_decl_trailing, 8851 .container_decl_two, 8852 .container_decl_two_trailing, 8853 .container_decl_arg, 8854 .container_decl_arg_trailing, 8855 .tagged_union, 8856 .tagged_union_trailing, 8857 .tagged_union_two, 8858 .tagged_union_two_trailing, 8859 .tagged_union_enum_tag, 8860 .tagged_union_enum_tag_trailing, 8861 .@"asm", 8862 .asm_simple, 8863 .add, 8864 .add_wrap, 8865 .add_sat, 8866 .array_cat, 8867 .array_mult, 8868 .assign, 8869 .assign_bit_and, 8870 .assign_bit_or, 8871 .assign_shl, 8872 .assign_shl_sat, 8873 .assign_shr, 8874 .assign_bit_xor, 8875 .assign_div, 8876 .assign_sub, 8877 .assign_sub_wrap, 8878 .assign_sub_sat, 8879 .assign_mod, 8880 .assign_add, 8881 .assign_add_wrap, 8882 .assign_add_sat, 8883 .assign_mul, 8884 .assign_mul_wrap, 8885 .assign_mul_sat, 8886 .bang_equal, 8887 .bit_and, 8888 .bit_or, 8889 .shl, 8890 .shl_sat, 8891 .shr, 8892 .bit_xor, 8893 .bool_and, 8894 .bool_or, 8895 .div, 8896 .equal_equal, 8897 .error_union, 8898 .greater_or_equal, 8899 .greater_than, 8900 .less_or_equal, 8901 .less_than, 8902 .merge_error_sets, 8903 .mod, 8904 .mul, 8905 .mul_wrap, 8906 .mul_sat, 8907 .switch_range, 8908 .field_access, 8909 .sub, 8910 .sub_wrap, 8911 .sub_sat, 8912 .slice, 8913 .slice_open, 8914 .slice_sentinel, 8915 .deref, 8916 .array_access, 8917 .error_value, 8918 .while_simple, 8919 .while_cont, 8920 .for_simple, 8921 .if_simple, 8922 .@"catch", 8923 .@"orelse", 8924 .array_init_one, 8925 .array_init_one_comma, 8926 .array_init_dot_two, 8927 .array_init_dot_two_comma, 8928 .array_init_dot, 8929 .array_init_dot_comma, 8930 .array_init, 8931 .array_init_comma, 8932 .struct_init_one, 8933 .struct_init_one_comma, 8934 .struct_init_dot_two, 8935 .struct_init_dot_two_comma, 8936 .struct_init_dot, 8937 .struct_init_dot_comma, 8938 .struct_init, 8939 .struct_init_comma, 8940 .@"while", 8941 .@"if", 8942 .@"for", 8943 .@"switch", 8944 .switch_comma, 8945 .call_one, 8946 .call_one_comma, 8947 .async_call_one, 8948 .async_call_one_comma, 8949 .call, 8950 .call_comma, 8951 .async_call, 8952 .async_call_comma, 8953 .block_two, 8954 .block_two_semicolon, 8955 .block, 8956 .block_semicolon, 8957 .builtin_call, 8958 .builtin_call_comma, 8959 .builtin_call_two, 8960 .builtin_call_two_comma, 8961 .ptr_type_aligned, 8962 .ptr_type_sentinel, 8963 .ptr_type, 8964 .ptr_type_bit_range, 8965 .optional_type, 8966 .anyframe_type, 8967 .array_type_sentinel, 8968 => return false, 8969 8970 // these are function bodies, not pointers 8971 .fn_proto_simple, 8972 .fn_proto_multi, 8973 .fn_proto_one, 8974 .fn_proto, 8975 => return true, 8976 8977 // Forward the question to the LHS sub-expression. 8978 .grouped_expression, 8979 .@"try", 8980 .@"await", 8981 .@"comptime", 8982 .@"nosuspend", 8983 .unwrap_optional, 8984 => node = node_datas[node].lhs, 8985 8986 .identifier => { 8987 const main_tokens = tree.nodes.items(.main_token); 8988 const ident_bytes = tree.tokenSlice(main_tokens[node]); 8989 if (primitives.get(ident_bytes)) |primitive| switch (primitive) { 8990 .anyerror_type, 8991 .anyframe_type, 8992 .anyopaque_type, 8993 .bool_type, 8994 .c_int_type, 8995 .c_long_type, 8996 .c_longdouble_type, 8997 .c_longlong_type, 8998 .c_short_type, 8999 .c_uint_type, 9000 .c_ulong_type, 9001 .c_ulonglong_type, 9002 .c_ushort_type, 9003 .f16_type, 9004 .f32_type, 9005 .f64_type, 9006 .f80_type, 9007 .f128_type, 9008 .i16_type, 9009 .i32_type, 9010 .i64_type, 9011 .i128_type, 9012 .i8_type, 9013 .isize_type, 9014 .u16_type, 9015 .u29_type, 9016 .u32_type, 9017 .u64_type, 9018 .u128_type, 9019 .u1_type, 9020 .u8_type, 9021 .usize_type, 9022 .void_type, 9023 .bool_false, 9024 .bool_true, 9025 .null_value, 9026 .undef, 9027 .noreturn_type, 9028 => return false, 9029 9030 .comptime_float_type, 9031 .comptime_int_type, 9032 .type_type, 9033 => return true, 9034 9035 else => unreachable, // that's all the values from `primitives`. 9036 } else { 9037 return false; 9038 } 9039 }, 9040 } 9041 } 9042 } 9043 9044 /// Applies `rl` semantics to `result`. Expressions which do not do their own handling of 9045 /// result locations must call this function on their result. 9046 /// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer. 9047 /// If the `ResultLoc` is `ty`, it will coerce the result to the type. 9048 /// Assumes nothing stacked on `gz`. 9049 fn rvalue( 9050 gz: *GenZir, 9051 rl: ResultLoc, 9052 raw_result: Zir.Inst.Ref, 9053 src_node: Ast.Node.Index, 9054 ) InnerError!Zir.Inst.Ref { 9055 const result = r: { 9056 if (refToIndex(raw_result)) |result_index| { 9057 const zir_tags = gz.astgen.instructions.items(.tag); 9058 const data = gz.astgen.instructions.items(.data)[result_index]; 9059 if (zir_tags[result_index].isAlwaysVoid(data)) { 9060 break :r Zir.Inst.Ref.void_value; 9061 } 9062 } 9063 break :r raw_result; 9064 }; 9065 if (gz.endsWithNoReturn()) return result; 9066 switch (rl) { 9067 .none, .coerced_ty => return result, 9068 .discard => { 9069 // Emit a compile error for discarding error values. 9070 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node); 9071 return result; 9072 }, 9073 .ref => { 9074 // We need a pointer but we have a value. 9075 // Unfortunately it's not quite as simple as directly emitting a ref 9076 // instruction here because we need subsequent address-of operator on 9077 // const locals to return the same address. 9078 const astgen = gz.astgen; 9079 const tree = astgen.tree; 9080 const src_token = tree.firstToken(src_node); 9081 const result_index = refToIndex(result) orelse 9082 return gz.addUnTok(.ref, result, src_token); 9083 const zir_tags = gz.astgen.instructions.items(.tag); 9084 if (zir_tags[result_index].isParam()) 9085 return gz.addUnTok(.ref, result, src_token); 9086 const gop = try astgen.ref_table.getOrPut(astgen.gpa, result_index); 9087 if (!gop.found_existing) { 9088 gop.value_ptr.* = try gz.makeUnTok(.ref, result, src_token); 9089 } 9090 return indexToRef(gop.value_ptr.*); 9091 }, 9092 .ty => |ty_inst| { 9093 // Quickly eliminate some common, unnecessary type coercion. 9094 const as_ty = @as(u64, @enumToInt(Zir.Inst.Ref.type_type)) << 32; 9095 const as_comptime_int = @as(u64, @enumToInt(Zir.Inst.Ref.comptime_int_type)) << 32; 9096 const as_bool = @as(u64, @enumToInt(Zir.Inst.Ref.bool_type)) << 32; 9097 const as_usize = @as(u64, @enumToInt(Zir.Inst.Ref.usize_type)) << 32; 9098 const as_void = @as(u64, @enumToInt(Zir.Inst.Ref.void_type)) << 32; 9099 switch ((@as(u64, @enumToInt(ty_inst)) << 32) | @as(u64, @enumToInt(result))) { 9100 as_ty | @enumToInt(Zir.Inst.Ref.u1_type), 9101 as_ty | @enumToInt(Zir.Inst.Ref.u8_type), 9102 as_ty | @enumToInt(Zir.Inst.Ref.i8_type), 9103 as_ty | @enumToInt(Zir.Inst.Ref.u16_type), 9104 as_ty | @enumToInt(Zir.Inst.Ref.u29_type), 9105 as_ty | @enumToInt(Zir.Inst.Ref.i16_type), 9106 as_ty | @enumToInt(Zir.Inst.Ref.u32_type), 9107 as_ty | @enumToInt(Zir.Inst.Ref.i32_type), 9108 as_ty | @enumToInt(Zir.Inst.Ref.u64_type), 9109 as_ty | @enumToInt(Zir.Inst.Ref.i64_type), 9110 as_ty | @enumToInt(Zir.Inst.Ref.usize_type), 9111 as_ty | @enumToInt(Zir.Inst.Ref.isize_type), 9112 as_ty | @enumToInt(Zir.Inst.Ref.c_short_type), 9113 as_ty | @enumToInt(Zir.Inst.Ref.c_ushort_type), 9114 as_ty | @enumToInt(Zir.Inst.Ref.c_int_type), 9115 as_ty | @enumToInt(Zir.Inst.Ref.c_uint_type), 9116 as_ty | @enumToInt(Zir.Inst.Ref.c_long_type), 9117 as_ty | @enumToInt(Zir.Inst.Ref.c_ulong_type), 9118 as_ty | @enumToInt(Zir.Inst.Ref.c_longlong_type), 9119 as_ty | @enumToInt(Zir.Inst.Ref.c_ulonglong_type), 9120 as_ty | @enumToInt(Zir.Inst.Ref.c_longdouble_type), 9121 as_ty | @enumToInt(Zir.Inst.Ref.f16_type), 9122 as_ty | @enumToInt(Zir.Inst.Ref.f32_type), 9123 as_ty | @enumToInt(Zir.Inst.Ref.f64_type), 9124 as_ty | @enumToInt(Zir.Inst.Ref.f80_type), 9125 as_ty | @enumToInt(Zir.Inst.Ref.f128_type), 9126 as_ty | @enumToInt(Zir.Inst.Ref.anyopaque_type), 9127 as_ty | @enumToInt(Zir.Inst.Ref.bool_type), 9128 as_ty | @enumToInt(Zir.Inst.Ref.void_type), 9129 as_ty | @enumToInt(Zir.Inst.Ref.type_type), 9130 as_ty | @enumToInt(Zir.Inst.Ref.anyerror_type), 9131 as_ty | @enumToInt(Zir.Inst.Ref.comptime_int_type), 9132 as_ty | @enumToInt(Zir.Inst.Ref.comptime_float_type), 9133 as_ty | @enumToInt(Zir.Inst.Ref.noreturn_type), 9134 as_ty | @enumToInt(Zir.Inst.Ref.null_type), 9135 as_ty | @enumToInt(Zir.Inst.Ref.undefined_type), 9136 as_ty | @enumToInt(Zir.Inst.Ref.fn_noreturn_no_args_type), 9137 as_ty | @enumToInt(Zir.Inst.Ref.fn_void_no_args_type), 9138 as_ty | @enumToInt(Zir.Inst.Ref.fn_naked_noreturn_no_args_type), 9139 as_ty | @enumToInt(Zir.Inst.Ref.fn_ccc_void_no_args_type), 9140 as_ty | @enumToInt(Zir.Inst.Ref.single_const_pointer_to_comptime_int_type), 9141 as_ty | @enumToInt(Zir.Inst.Ref.const_slice_u8_type), 9142 as_ty | @enumToInt(Zir.Inst.Ref.enum_literal_type), 9143 as_comptime_int | @enumToInt(Zir.Inst.Ref.zero), 9144 as_comptime_int | @enumToInt(Zir.Inst.Ref.one), 9145 as_bool | @enumToInt(Zir.Inst.Ref.bool_true), 9146 as_bool | @enumToInt(Zir.Inst.Ref.bool_false), 9147 as_usize | @enumToInt(Zir.Inst.Ref.zero_usize), 9148 as_usize | @enumToInt(Zir.Inst.Ref.one_usize), 9149 as_void | @enumToInt(Zir.Inst.Ref.void_value), 9150 => return result, // type of result is already correct 9151 9152 // Need an explicit type coercion instruction. 9153 else => return gz.addPlNode(.as_node, src_node, Zir.Inst.As{ 9154 .dest_type = ty_inst, 9155 .operand = result, 9156 }), 9157 } 9158 }, 9159 .ptr => |ptr_inst| { 9160 if (gz.rvalue_noresult != ptr_inst) { 9161 _ = try gz.addPlNode(.store_node, src_node, Zir.Inst.Bin{ 9162 .lhs = ptr_inst, 9163 .rhs = result, 9164 }); 9165 } 9166 return result; 9167 }, 9168 .inferred_ptr => |alloc| { 9169 if (gz.rvalue_noresult != alloc) { 9170 _ = try gz.addBin(.store_to_inferred_ptr, alloc, result); 9171 } 9172 return result; 9173 }, 9174 .block_ptr => |block_scope| { 9175 if (gz.rvalue_noresult != block_scope.rl_ptr) { 9176 block_scope.rvalue_rl_count += 1; 9177 _ = try gz.addBin(.store_to_block_ptr, block_scope.rl_ptr, result); 9178 } 9179 return result; 9180 }, 9181 } 9182 } 9183 9184 /// Given an identifier token, obtain the string for it. 9185 /// If the token uses @"" syntax, parses as a string, reports errors if applicable, 9186 /// and allocates the result within `astgen.arena`. 9187 /// Otherwise, returns a reference to the source code bytes directly. 9188 /// See also `appendIdentStr` and `parseStrLit`. 9189 fn identifierTokenString(astgen: *AstGen, token: Ast.TokenIndex) InnerError![]const u8 { 9190 const tree = astgen.tree; 9191 const token_tags = tree.tokens.items(.tag); 9192 assert(token_tags[token] == .identifier); 9193 const ident_name = tree.tokenSlice(token); 9194 if (!mem.startsWith(u8, ident_name, "@")) { 9195 return ident_name; 9196 } 9197 var buf: ArrayListUnmanaged(u8) = .{}; 9198 defer buf.deinit(astgen.gpa); 9199 try astgen.parseStrLit(token, &buf, ident_name, 1); 9200 const duped = try astgen.arena.dupe(u8, buf.items); 9201 return duped; 9202 } 9203 9204 /// Given an identifier token, obtain the string for it (possibly parsing as a string 9205 /// literal if it is @"" syntax), and append the string to `buf`. 9206 /// See also `identifierTokenString` and `parseStrLit`. 9207 fn appendIdentStr( 9208 astgen: *AstGen, 9209 token: Ast.TokenIndex, 9210 buf: *ArrayListUnmanaged(u8), 9211 ) InnerError!void { 9212 const tree = astgen.tree; 9213 const token_tags = tree.tokens.items(.tag); 9214 assert(token_tags[token] == .identifier); 9215 const ident_name = tree.tokenSlice(token); 9216 if (!mem.startsWith(u8, ident_name, "@")) { 9217 return buf.appendSlice(astgen.gpa, ident_name); 9218 } else { 9219 return astgen.parseStrLit(token, buf, ident_name, 1); 9220 } 9221 } 9222 9223 /// Appends the result to `buf`. 9224 fn parseStrLit( 9225 astgen: *AstGen, 9226 token: Ast.TokenIndex, 9227 buf: *ArrayListUnmanaged(u8), 9228 bytes: []const u8, 9229 offset: u32, 9230 ) InnerError!void { 9231 const raw_string = bytes[offset..]; 9232 var buf_managed = buf.toManaged(astgen.gpa); 9233 const result = std.zig.string_literal.parseAppend(&buf_managed, raw_string); 9234 buf.* = buf_managed.moveToUnmanaged(); 9235 switch (try result) { 9236 .success => return, 9237 .failure => |err| return astgen.failWithStrLitError(err, token, bytes, offset), 9238 } 9239 } 9240 9241 fn failWithStrLitError(astgen: *AstGen, err: std.zig.string_literal.Error, token: Ast.TokenIndex, bytes: []const u8, offset: u32) InnerError { 9242 const raw_string = bytes[offset..]; 9243 switch (err) { 9244 .invalid_escape_character => |bad_index| { 9245 return astgen.failOff( 9246 token, 9247 offset + @intCast(u32, bad_index), 9248 "invalid escape character: '{c}'", 9249 .{raw_string[bad_index]}, 9250 ); 9251 }, 9252 .expected_hex_digit => |bad_index| { 9253 return astgen.failOff( 9254 token, 9255 offset + @intCast(u32, bad_index), 9256 "expected hex digit, found '{c}'", 9257 .{raw_string[bad_index]}, 9258 ); 9259 }, 9260 .empty_unicode_escape_sequence => |bad_index| { 9261 return astgen.failOff( 9262 token, 9263 offset + @intCast(u32, bad_index), 9264 "empty unicode escape sequence", 9265 .{}, 9266 ); 9267 }, 9268 .expected_hex_digit_or_rbrace => |bad_index| { 9269 return astgen.failOff( 9270 token, 9271 offset + @intCast(u32, bad_index), 9272 "expected hex digit or '}}', found '{c}'", 9273 .{raw_string[bad_index]}, 9274 ); 9275 }, 9276 .invalid_unicode_codepoint => |bad_index| { 9277 return astgen.failOff( 9278 token, 9279 offset + @intCast(u32, bad_index), 9280 "unicode escape does not correspond to a valid codepoint", 9281 .{}, 9282 ); 9283 }, 9284 .expected_lbrace => |bad_index| { 9285 return astgen.failOff( 9286 token, 9287 offset + @intCast(u32, bad_index), 9288 "expected '{{', found '{c}", 9289 .{raw_string[bad_index]}, 9290 ); 9291 }, 9292 .expected_rbrace => |bad_index| { 9293 return astgen.failOff( 9294 token, 9295 offset + @intCast(u32, bad_index), 9296 "expected '}}', found '{c}", 9297 .{raw_string[bad_index]}, 9298 ); 9299 }, 9300 .expected_single_quote => |bad_index| { 9301 return astgen.failOff( 9302 token, 9303 offset + @intCast(u32, bad_index), 9304 "expected single quote ('), found '{c}", 9305 .{raw_string[bad_index]}, 9306 ); 9307 }, 9308 .invalid_character => |bad_index| { 9309 return astgen.failOff( 9310 token, 9311 offset + @intCast(u32, bad_index), 9312 "invalid byte in string or character literal: '{c}'", 9313 .{raw_string[bad_index]}, 9314 ); 9315 }, 9316 } 9317 } 9318 9319 fn failNode( 9320 astgen: *AstGen, 9321 node: Ast.Node.Index, 9322 comptime format: []const u8, 9323 args: anytype, 9324 ) InnerError { 9325 return astgen.failNodeNotes(node, format, args, &[0]u32{}); 9326 } 9327 9328 fn appendErrorNode( 9329 astgen: *AstGen, 9330 node: Ast.Node.Index, 9331 comptime format: []const u8, 9332 args: anytype, 9333 ) Allocator.Error!void { 9334 try astgen.appendErrorNodeNotes(node, format, args, &[0]u32{}); 9335 } 9336 9337 fn appendErrorNodeNotes( 9338 astgen: *AstGen, 9339 node: Ast.Node.Index, 9340 comptime format: []const u8, 9341 args: anytype, 9342 notes: []const u32, 9343 ) Allocator.Error!void { 9344 @setCold(true); 9345 const string_bytes = &astgen.string_bytes; 9346 const msg = @intCast(u32, string_bytes.items.len); 9347 try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); 9348 const notes_index: u32 = if (notes.len != 0) blk: { 9349 const notes_start = astgen.extra.items.len; 9350 try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len); 9351 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len)); 9352 astgen.extra.appendSliceAssumeCapacity(notes); 9353 break :blk @intCast(u32, notes_start); 9354 } else 0; 9355 try astgen.compile_errors.append(astgen.gpa, .{ 9356 .msg = msg, 9357 .node = node, 9358 .token = 0, 9359 .byte_offset = 0, 9360 .notes = notes_index, 9361 }); 9362 } 9363 9364 fn failNodeNotes( 9365 astgen: *AstGen, 9366 node: Ast.Node.Index, 9367 comptime format: []const u8, 9368 args: anytype, 9369 notes: []const u32, 9370 ) InnerError { 9371 try appendErrorNodeNotes(astgen, node, format, args, notes); 9372 return error.AnalysisFail; 9373 } 9374 9375 fn failTok( 9376 astgen: *AstGen, 9377 token: Ast.TokenIndex, 9378 comptime format: []const u8, 9379 args: anytype, 9380 ) InnerError { 9381 return astgen.failTokNotes(token, format, args, &[0]u32{}); 9382 } 9383 9384 fn appendErrorTok( 9385 astgen: *AstGen, 9386 token: Ast.TokenIndex, 9387 comptime format: []const u8, 9388 args: anytype, 9389 ) !void { 9390 try astgen.appendErrorTokNotes(token, format, args, &[0]u32{}); 9391 } 9392 9393 fn failTokNotes( 9394 astgen: *AstGen, 9395 token: Ast.TokenIndex, 9396 comptime format: []const u8, 9397 args: anytype, 9398 notes: []const u32, 9399 ) InnerError { 9400 try appendErrorTokNotes(astgen, token, format, args, notes); 9401 return error.AnalysisFail; 9402 } 9403 9404 fn appendErrorTokNotes( 9405 astgen: *AstGen, 9406 token: Ast.TokenIndex, 9407 comptime format: []const u8, 9408 args: anytype, 9409 notes: []const u32, 9410 ) !void { 9411 @setCold(true); 9412 const string_bytes = &astgen.string_bytes; 9413 const msg = @intCast(u32, string_bytes.items.len); 9414 try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); 9415 const notes_index: u32 = if (notes.len != 0) blk: { 9416 const notes_start = astgen.extra.items.len; 9417 try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len); 9418 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len)); 9419 astgen.extra.appendSliceAssumeCapacity(notes); 9420 break :blk @intCast(u32, notes_start); 9421 } else 0; 9422 try astgen.compile_errors.append(astgen.gpa, .{ 9423 .msg = msg, 9424 .node = 0, 9425 .token = token, 9426 .byte_offset = 0, 9427 .notes = notes_index, 9428 }); 9429 } 9430 9431 /// Same as `fail`, except given an absolute byte offset. 9432 fn failOff( 9433 astgen: *AstGen, 9434 token: Ast.TokenIndex, 9435 byte_offset: u32, 9436 comptime format: []const u8, 9437 args: anytype, 9438 ) InnerError { 9439 try appendErrorOff(astgen, token, byte_offset, format, args); 9440 return error.AnalysisFail; 9441 } 9442 9443 fn appendErrorOff( 9444 astgen: *AstGen, 9445 token: Ast.TokenIndex, 9446 byte_offset: u32, 9447 comptime format: []const u8, 9448 args: anytype, 9449 ) Allocator.Error!void { 9450 @setCold(true); 9451 const string_bytes = &astgen.string_bytes; 9452 const msg = @intCast(u32, string_bytes.items.len); 9453 try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); 9454 try astgen.compile_errors.append(astgen.gpa, .{ 9455 .msg = msg, 9456 .node = 0, 9457 .token = token, 9458 .byte_offset = byte_offset, 9459 .notes = 0, 9460 }); 9461 } 9462 9463 fn errNoteTok( 9464 astgen: *AstGen, 9465 token: Ast.TokenIndex, 9466 comptime format: []const u8, 9467 args: anytype, 9468 ) Allocator.Error!u32 { 9469 @setCold(true); 9470 const string_bytes = &astgen.string_bytes; 9471 const msg = @intCast(u32, string_bytes.items.len); 9472 try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); 9473 return astgen.addExtra(Zir.Inst.CompileErrors.Item{ 9474 .msg = msg, 9475 .node = 0, 9476 .token = token, 9477 .byte_offset = 0, 9478 .notes = 0, 9479 }); 9480 } 9481 9482 fn errNoteNode( 9483 astgen: *AstGen, 9484 node: Ast.Node.Index, 9485 comptime format: []const u8, 9486 args: anytype, 9487 ) Allocator.Error!u32 { 9488 @setCold(true); 9489 const string_bytes = &astgen.string_bytes; 9490 const msg = @intCast(u32, string_bytes.items.len); 9491 try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); 9492 return astgen.addExtra(Zir.Inst.CompileErrors.Item{ 9493 .msg = msg, 9494 .node = node, 9495 .token = 0, 9496 .byte_offset = 0, 9497 .notes = 0, 9498 }); 9499 } 9500 9501 fn identAsString(astgen: *AstGen, ident_token: Ast.TokenIndex) !u32 { 9502 const gpa = astgen.gpa; 9503 const string_bytes = &astgen.string_bytes; 9504 const str_index = @intCast(u32, string_bytes.items.len); 9505 try astgen.appendIdentStr(ident_token, string_bytes); 9506 const key = string_bytes.items[str_index..]; 9507 const gop = try astgen.string_table.getOrPutContextAdapted(gpa, @as([]const u8, key), StringIndexAdapter{ 9508 .bytes = string_bytes, 9509 }, StringIndexContext{ 9510 .bytes = string_bytes, 9511 }); 9512 if (gop.found_existing) { 9513 string_bytes.shrinkRetainingCapacity(str_index); 9514 return gop.key_ptr.*; 9515 } else { 9516 gop.key_ptr.* = str_index; 9517 try string_bytes.append(gpa, 0); 9518 return str_index; 9519 } 9520 } 9521 9522 /// Adds a doc comment block to `string_bytes` by walking backwards from `end_token`. 9523 /// `end_token` must point at the first token after the last doc coment line. 9524 /// Returns 0 if no doc comment is present. 9525 fn docCommentAsString(astgen: *AstGen, end_token: Ast.TokenIndex) !u32 { 9526 if (end_token == 0) return @as(u32, 0); 9527 9528 const token_tags = astgen.tree.tokens.items(.tag); 9529 9530 var tok = end_token - 1; 9531 while (token_tags[tok] == .doc_comment) { 9532 if (tok == 0) break; 9533 tok -= 1; 9534 } else { 9535 tok += 1; 9536 } 9537 return docCommentAsStringFromFirst(astgen, end_token, tok); 9538 } 9539 9540 /// end_token must be > the index of the last doc comment. 9541 fn docCommentAsStringFromFirst( 9542 astgen: *AstGen, 9543 end_token: Ast.TokenIndex, 9544 start_token: Ast.TokenIndex, 9545 ) !u32 { 9546 if (start_token == end_token) return 0; 9547 9548 const gpa = astgen.gpa; 9549 const string_bytes = &astgen.string_bytes; 9550 const str_index = @intCast(u32, string_bytes.items.len); 9551 const token_starts = astgen.tree.tokens.items(.start); 9552 const token_tags = astgen.tree.tokens.items(.tag); 9553 9554 const total_bytes = token_starts[end_token] - token_starts[start_token]; 9555 try string_bytes.ensureUnusedCapacity(gpa, total_bytes); 9556 9557 var current_token = start_token; 9558 while (current_token < end_token) : (current_token += 1) { 9559 switch (token_tags[current_token]) { 9560 .doc_comment => { 9561 const tok_bytes = astgen.tree.tokenSlice(current_token)[3..]; 9562 string_bytes.appendSliceAssumeCapacity(tok_bytes); 9563 if (current_token != end_token - 1) { 9564 string_bytes.appendAssumeCapacity('\n'); 9565 } 9566 }, 9567 else => break, 9568 } 9569 } 9570 9571 const key = string_bytes.items[str_index..]; 9572 const gop = try astgen.string_table.getOrPutContextAdapted(gpa, @as([]const u8, key), StringIndexAdapter{ 9573 .bytes = string_bytes, 9574 }, StringIndexContext{ 9575 .bytes = string_bytes, 9576 }); 9577 9578 if (gop.found_existing) { 9579 string_bytes.shrinkRetainingCapacity(str_index); 9580 return gop.key_ptr.*; 9581 } else { 9582 gop.key_ptr.* = str_index; 9583 try string_bytes.append(gpa, 0); 9584 return str_index; 9585 } 9586 } 9587 9588 const IndexSlice = struct { index: u32, len: u32 }; 9589 9590 fn strLitAsString(astgen: *AstGen, str_lit_token: Ast.TokenIndex) !IndexSlice { 9591 const gpa = astgen.gpa; 9592 const string_bytes = &astgen.string_bytes; 9593 const str_index = @intCast(u32, string_bytes.items.len); 9594 const token_bytes = astgen.tree.tokenSlice(str_lit_token); 9595 try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0); 9596 const key = string_bytes.items[str_index..]; 9597 const gop = try astgen.string_table.getOrPutContextAdapted(gpa, @as([]const u8, key), StringIndexAdapter{ 9598 .bytes = string_bytes, 9599 }, StringIndexContext{ 9600 .bytes = string_bytes, 9601 }); 9602 if (gop.found_existing) { 9603 string_bytes.shrinkRetainingCapacity(str_index); 9604 return IndexSlice{ 9605 .index = gop.key_ptr.*, 9606 .len = @intCast(u32, key.len), 9607 }; 9608 } else { 9609 gop.key_ptr.* = str_index; 9610 // Still need a null byte because we are using the same table 9611 // to lookup null terminated strings, so if we get a match, it has to 9612 // be null terminated for that to work. 9613 try string_bytes.append(gpa, 0); 9614 return IndexSlice{ 9615 .index = str_index, 9616 .len = @intCast(u32, key.len), 9617 }; 9618 } 9619 } 9620 9621 fn strLitNodeAsString(astgen: *AstGen, node: Ast.Node.Index) !IndexSlice { 9622 const tree = astgen.tree; 9623 const node_datas = tree.nodes.items(.data); 9624 9625 const start = node_datas[node].lhs; 9626 const end = node_datas[node].rhs; 9627 9628 const gpa = astgen.gpa; 9629 const string_bytes = &astgen.string_bytes; 9630 const str_index = string_bytes.items.len; 9631 9632 // First line: do not append a newline. 9633 var tok_i = start; 9634 { 9635 const slice = tree.tokenSlice(tok_i); 9636 const line_bytes = slice[2 .. slice.len - 1]; 9637 try string_bytes.appendSlice(gpa, line_bytes); 9638 tok_i += 1; 9639 } 9640 // Following lines: each line prepends a newline. 9641 while (tok_i <= end) : (tok_i += 1) { 9642 const slice = tree.tokenSlice(tok_i); 9643 const line_bytes = slice[2 .. slice.len - 1]; 9644 try string_bytes.ensureUnusedCapacity(gpa, line_bytes.len + 1); 9645 string_bytes.appendAssumeCapacity('\n'); 9646 string_bytes.appendSliceAssumeCapacity(line_bytes); 9647 } 9648 const len = string_bytes.items.len - str_index; 9649 try string_bytes.append(gpa, 0); 9650 return IndexSlice{ 9651 .index = @intCast(u32, str_index), 9652 .len = @intCast(u32, len), 9653 }; 9654 } 9655 9656 fn testNameString(astgen: *AstGen, str_lit_token: Ast.TokenIndex) !u32 { 9657 const gpa = astgen.gpa; 9658 const string_bytes = &astgen.string_bytes; 9659 const str_index = @intCast(u32, string_bytes.items.len); 9660 const token_bytes = astgen.tree.tokenSlice(str_lit_token); 9661 try string_bytes.append(gpa, 0); // Indicates this is a test. 9662 try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0); 9663 try string_bytes.append(gpa, 0); 9664 return str_index; 9665 } 9666 9667 const Scope = struct { 9668 tag: Tag, 9669 9670 fn cast(base: *Scope, comptime T: type) ?*T { 9671 if (T == Defer) { 9672 switch (base.tag) { 9673 .defer_normal, .defer_error => return @fieldParentPtr(T, "base", base), 9674 else => return null, 9675 } 9676 } 9677 if (base.tag != T.base_tag) 9678 return null; 9679 9680 return @fieldParentPtr(T, "base", base); 9681 } 9682 9683 fn parent(base: *Scope) ?*Scope { 9684 return switch (base.tag) { 9685 .gen_zir => base.cast(GenZir).?.parent, 9686 .local_val => base.cast(LocalVal).?.parent, 9687 .local_ptr => base.cast(LocalPtr).?.parent, 9688 .defer_normal, .defer_error => base.cast(Defer).?.parent, 9689 .namespace => base.cast(Namespace).?.parent, 9690 .top => null, 9691 }; 9692 } 9693 9694 const Tag = enum { 9695 gen_zir, 9696 local_val, 9697 local_ptr, 9698 defer_normal, 9699 defer_error, 9700 namespace, 9701 top, 9702 }; 9703 9704 /// The category of identifier. These tag names are user-visible in compile errors. 9705 const IdCat = enum { 9706 @"function parameter", 9707 @"local constant", 9708 @"local variable", 9709 @"loop index capture", 9710 @"capture", 9711 }; 9712 9713 /// This is always a `const` local and importantly the `inst` is a value type, not a pointer. 9714 /// This structure lives as long as the AST generation of the Block 9715 /// node that contains the variable. 9716 const LocalVal = struct { 9717 const base_tag: Tag = .local_val; 9718 base: Scope = Scope{ .tag = base_tag }, 9719 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`. 9720 parent: *Scope, 9721 gen_zir: *GenZir, 9722 inst: Zir.Inst.Ref, 9723 /// Source location of the corresponding variable declaration. 9724 token_src: Ast.TokenIndex, 9725 /// String table index. 9726 name: u32, 9727 id_cat: IdCat, 9728 /// Track whether the name has been referenced. 9729 used: bool = false, 9730 }; 9731 9732 /// This could be a `const` or `var` local. It has a pointer instead of a value. 9733 /// This structure lives as long as the AST generation of the Block 9734 /// node that contains the variable. 9735 const LocalPtr = struct { 9736 const base_tag: Tag = .local_ptr; 9737 base: Scope = Scope{ .tag = base_tag }, 9738 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`. 9739 parent: *Scope, 9740 gen_zir: *GenZir, 9741 ptr: Zir.Inst.Ref, 9742 /// Source location of the corresponding variable declaration. 9743 token_src: Ast.TokenIndex, 9744 /// String table index. 9745 name: u32, 9746 id_cat: IdCat, 9747 /// true means we find out during Sema whether the value is comptime. 9748 /// false means it is already known at AstGen the value is runtime-known. 9749 maybe_comptime: bool, 9750 /// Track whether the name has been referenced. 9751 used: bool = false, 9752 }; 9753 9754 const Defer = struct { 9755 base: Scope, 9756 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`. 9757 parent: *Scope, 9758 defer_node: Ast.Node.Index, 9759 source_offset: u32, 9760 source_line: u32, 9761 source_column: u32, 9762 }; 9763 9764 /// Represents a global scope that has any number of declarations in it. 9765 /// Each declaration has this as the parent scope. 9766 const Namespace = struct { 9767 const base_tag: Tag = .namespace; 9768 base: Scope = Scope{ .tag = base_tag }, 9769 9770 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`. 9771 parent: *Scope, 9772 /// Maps string table index to the source location of declaration, 9773 /// for the purposes of reporting name shadowing compile errors. 9774 decls: std.AutoHashMapUnmanaged(u32, Ast.Node.Index) = .{}, 9775 node: Ast.Node.Index, 9776 inst: Zir.Inst.Index, 9777 9778 /// The astgen scope containing this namespace. 9779 /// Only valid during astgen. 9780 declaring_gz: ?*GenZir, 9781 9782 /// Map from the raw captured value to the instruction 9783 /// ref of the capture for decls in this namespace 9784 captures: std.AutoArrayHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}, 9785 9786 pub fn deinit(self: *Namespace, gpa: Allocator) void { 9787 self.decls.deinit(gpa); 9788 self.captures.deinit(gpa); 9789 self.* = undefined; 9790 } 9791 }; 9792 9793 const Top = struct { 9794 const base_tag: Scope.Tag = .top; 9795 base: Scope = Scope{ .tag = base_tag }, 9796 }; 9797 }; 9798 9799 /// This is a temporary structure; references to it are valid only 9800 /// while constructing a `Zir`. 9801 const GenZir = struct { 9802 const base_tag: Scope.Tag = .gen_zir; 9803 base: Scope = Scope{ .tag = base_tag }, 9804 force_comptime: bool, 9805 /// This is set to true for inline loops; false otherwise. 9806 is_inline: bool = false, 9807 in_defer: bool, 9808 c_import: bool = false, 9809 /// How decls created in this scope should be named. 9810 anon_name_strategy: Zir.Inst.NameStrategy = .anon, 9811 /// The containing decl AST node. 9812 decl_node_index: Ast.Node.Index, 9813 /// The containing decl line index, absolute. 9814 decl_line: u32, 9815 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`. 9816 parent: *Scope, 9817 /// All `GenZir` scopes for the same ZIR share this. 9818 astgen: *AstGen, 9819 /// Keeps track of the list of instructions in this scope. Possibly shared. 9820 /// Indexes to instructions in `astgen`. 9821 instructions: *ArrayListUnmanaged(Zir.Inst.Index), 9822 /// A sub-block may share its instructions ArrayList with containing GenZir, 9823 /// if use is strictly nested. This saves prior size of list for unstacking. 9824 instructions_top: usize, 9825 label: ?Label = null, 9826 break_block: Zir.Inst.Index = 0, 9827 continue_block: Zir.Inst.Index = 0, 9828 /// Only valid when setBreakResultLoc is called. 9829 break_result_loc: AstGen.ResultLoc = undefined, 9830 /// When a block has a pointer result location, here it is. 9831 rl_ptr: Zir.Inst.Ref = .none, 9832 /// When a block has a type result location, here it is. 9833 rl_ty_inst: Zir.Inst.Ref = .none, 9834 rvalue_noresult: Zir.Inst.Ref = .none, 9835 /// Keeps track of how many branches of a block did not actually 9836 /// consume the result location. astgen uses this to figure out 9837 /// whether to rely on break instructions or writing to the result 9838 /// pointer for the result instruction. 9839 rvalue_rl_count: usize = 0, 9840 /// Keeps track of how many break instructions there are. When astgen is finished 9841 /// with a block, it can check this against rvalue_rl_count to find out whether 9842 /// the break instructions should be downgraded to break_void. 9843 break_count: usize = 0, 9844 /// Tracks `break :foo bar` instructions so they can possibly be elided later if 9845 /// the labeled block ends up not needing a result location pointer. 9846 labeled_breaks: ArrayListUnmanaged(struct { br: Zir.Inst.Index, search: Zir.Inst.Index }) = .{}, 9847 9848 suspend_node: Ast.Node.Index = 0, 9849 nosuspend_node: Ast.Node.Index = 0, 9850 9851 /// Namespace members are lazy. When executing a decl within a namespace, 9852 /// any references to external instructions need to be treated specially. 9853 /// This list tracks those references. See also .closure_capture and .closure_get. 9854 /// Keys are the raw instruction index, values are the closure_capture instruction. 9855 captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}, 9856 9857 const unstacked_top = std.math.maxInt(usize); 9858 /// Call unstack before adding any new instructions to containing GenZir. 9859 fn unstack(self: *GenZir) void { 9860 if (self.instructions_top != unstacked_top) { 9861 self.instructions.items.len = self.instructions_top; 9862 self.instructions_top = unstacked_top; 9863 } 9864 } 9865 9866 fn isEmpty(self: *const GenZir) bool { 9867 return (self.instructions_top == unstacked_top) or 9868 (self.instructions.items.len == self.instructions_top); 9869 } 9870 9871 fn instructionsSlice(self: *const GenZir) []Zir.Inst.Index { 9872 return if (self.instructions_top == unstacked_top) 9873 &[0]Zir.Inst.Index{} 9874 else 9875 self.instructions.items[self.instructions_top..]; 9876 } 9877 9878 fn instructionsSliceUpto(self: *const GenZir, stacked_gz: *GenZir) []Zir.Inst.Index { 9879 return if (self.instructions_top == unstacked_top) 9880 &[0]Zir.Inst.Index{} 9881 else if (self.instructions == stacked_gz.instructions and stacked_gz.instructions_top != unstacked_top) 9882 self.instructions.items[self.instructions_top..stacked_gz.instructions_top] 9883 else 9884 self.instructions.items[self.instructions_top..]; 9885 } 9886 9887 fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir { 9888 return .{ 9889 .force_comptime = gz.force_comptime, 9890 .in_defer = gz.in_defer, 9891 .c_import = gz.c_import, 9892 .decl_node_index = gz.decl_node_index, 9893 .decl_line = gz.decl_line, 9894 .parent = scope, 9895 .rl_ty_inst = gz.rl_ty_inst, 9896 .astgen = gz.astgen, 9897 .suspend_node = gz.suspend_node, 9898 .nosuspend_node = gz.nosuspend_node, 9899 .instructions = gz.instructions, 9900 .instructions_top = gz.instructions.items.len, 9901 }; 9902 } 9903 9904 fn makeCoercionScope( 9905 parent_gz: *GenZir, 9906 scope: *Scope, 9907 dest_type: Zir.Inst.Ref, 9908 result_ptr: Zir.Inst.Ref, 9909 src_node: Ast.Node.Index, 9910 ) !GenZir { 9911 // Detect whether this expr() call goes into rvalue() to store the result into the 9912 // result location. If it does, elide the coerce_result_ptr instruction 9913 // as well as the store instruction, instead passing the result as an rvalue. 9914 var as_scope = parent_gz.makeSubBlock(scope); 9915 errdefer as_scope.unstack(); 9916 as_scope.rl_ptr = try as_scope.addPlNode(.coerce_result_ptr, src_node, Zir.Inst.Bin{ .lhs = dest_type, .rhs = result_ptr }); 9917 9918 // `rl_ty_inst` needs to be set in case the stores to `rl_ptr` are eliminated. 9919 as_scope.rl_ty_inst = dest_type; 9920 9921 return as_scope; 9922 } 9923 9924 /// Assumes `as_scope` is stacked immediately on top of `parent_gz`. Unstacks `as_scope`. 9925 fn finishCoercion( 9926 as_scope: *GenZir, 9927 parent_gz: *GenZir, 9928 rl: ResultLoc, 9929 src_node: Ast.Node.Index, 9930 result: Zir.Inst.Ref, 9931 dest_type: Zir.Inst.Ref, 9932 ) InnerError!Zir.Inst.Ref { 9933 assert(as_scope.instructions == parent_gz.instructions); 9934 const astgen = as_scope.astgen; 9935 if (as_scope.rvalue_rl_count == 1) { 9936 // Busted! This expression didn't actually need a pointer. 9937 const zir_tags = astgen.instructions.items(.tag); 9938 const zir_datas = astgen.instructions.items(.data); 9939 var src: usize = as_scope.instructions_top; 9940 var dst: usize = src; 9941 while (src < as_scope.instructions.items.len) : (src += 1) { 9942 const src_inst = as_scope.instructions.items[src]; 9943 if (indexToRef(src_inst) == as_scope.rl_ptr) continue; 9944 if (zir_tags[src_inst] == .store_to_block_ptr) { 9945 if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue; 9946 } 9947 as_scope.instructions.items[dst] = src_inst; 9948 dst += 1; 9949 } 9950 parent_gz.instructions.items.len -= src - dst; 9951 as_scope.instructions_top = GenZir.unstacked_top; 9952 // as_scope now unstacked, can add new instructions to parent_gz 9953 const casted_result = try parent_gz.addBin(.as, dest_type, result); 9954 return rvalue(parent_gz, rl, casted_result, src_node); 9955 } else { 9956 // implicitly move all as_scope instructions to parent_gz 9957 as_scope.instructions_top = GenZir.unstacked_top; 9958 return result; 9959 } 9960 } 9961 9962 const Label = struct { 9963 token: Ast.TokenIndex, 9964 block_inst: Zir.Inst.Index, 9965 used: bool = false, 9966 }; 9967 9968 /// Assumes nothing stacked on `gz`. 9969 fn endsWithNoReturn(gz: GenZir) bool { 9970 if (gz.isEmpty()) return false; 9971 const tags = gz.astgen.instructions.items(.tag); 9972 const last_inst = gz.instructions.items[gz.instructions.items.len - 1]; 9973 return tags[last_inst].isNoReturn(); 9974 } 9975 9976 /// TODO all uses of this should be replaced with uses of `endsWithNoReturn`. 9977 fn refIsNoReturn(gz: GenZir, inst_ref: Zir.Inst.Ref) bool { 9978 if (inst_ref == .unreachable_value) return true; 9979 if (refToIndex(inst_ref)) |inst_index| { 9980 return gz.astgen.instructions.items(.tag)[inst_index].isNoReturn(); 9981 } 9982 return false; 9983 } 9984 9985 fn nodeIndexToRelative(gz: GenZir, node_index: Ast.Node.Index) i32 { 9986 return @bitCast(i32, node_index) - @bitCast(i32, gz.decl_node_index); 9987 } 9988 9989 fn tokenIndexToRelative(gz: GenZir, token: Ast.TokenIndex) u32 { 9990 return token - gz.srcToken(); 9991 } 9992 9993 fn srcToken(gz: GenZir) Ast.TokenIndex { 9994 return gz.astgen.tree.firstToken(gz.decl_node_index); 9995 } 9996 9997 fn setBreakResultLoc(gz: *GenZir, parent_rl: AstGen.ResultLoc) void { 9998 // Depending on whether the result location is a pointer or value, different 9999 // ZIR needs to be generated. In the former case we rely on storing to the 10000 // pointer to communicate the result, and use breakvoid; in the latter case 10001 // the block break instructions will have the result values. 10002 // One more complication: when the result location is a pointer, we detect 10003 // the scenario where the result location is not consumed. In this case 10004 // we emit ZIR for the block break instructions to have the result values, 10005 // and then rvalue() on that to pass the value to the result location. 10006 switch (parent_rl) { 10007 .ty, .coerced_ty => |ty_inst| { 10008 gz.rl_ty_inst = ty_inst; 10009 gz.break_result_loc = parent_rl; 10010 }, 10011 10012 .discard, .none, .ptr, .ref => { 10013 gz.rl_ty_inst = .none; 10014 gz.break_result_loc = parent_rl; 10015 }, 10016 10017 .inferred_ptr => |ptr| { 10018 gz.rl_ty_inst = .none; 10019 gz.rl_ptr = ptr; 10020 gz.break_result_loc = .{ .block_ptr = gz }; 10021 }, 10022 10023 .block_ptr => |parent_block_scope| { 10024 gz.rl_ty_inst = parent_block_scope.rl_ty_inst; 10025 gz.rl_ptr = parent_block_scope.rl_ptr; 10026 gz.break_result_loc = .{ .block_ptr = gz }; 10027 }, 10028 } 10029 } 10030 10031 /// Assumes nothing stacked on `gz`. Unstacks `gz`. 10032 fn setBoolBrBody(gz: *GenZir, inst: Zir.Inst.Index) !void { 10033 const astgen = gz.astgen; 10034 const gpa = astgen.gpa; 10035 const body = gz.instructionsSlice(); 10036 const body_len = astgen.countBodyLenAfterFixups(body); 10037 try astgen.extra.ensureUnusedCapacity( 10038 gpa, 10039 @typeInfo(Zir.Inst.Block).Struct.fields.len + body_len, 10040 ); 10041 const zir_datas = astgen.instructions.items(.data); 10042 zir_datas[inst].bool_br.payload_index = astgen.addExtraAssumeCapacity( 10043 Zir.Inst.Block{ .body_len = body_len }, 10044 ); 10045 astgen.appendBodyWithFixups(body); 10046 gz.unstack(); 10047 } 10048 10049 /// Assumes nothing stacked on `gz`. Unstacks `gz`. 10050 fn setBlockBody(gz: *GenZir, inst: Zir.Inst.Index) !void { 10051 const astgen = gz.astgen; 10052 const gpa = astgen.gpa; 10053 const body = gz.instructionsSlice(); 10054 const body_len = astgen.countBodyLenAfterFixups(body); 10055 try astgen.extra.ensureUnusedCapacity( 10056 gpa, 10057 @typeInfo(Zir.Inst.Block).Struct.fields.len + body_len, 10058 ); 10059 const zir_datas = astgen.instructions.items(.data); 10060 zir_datas[inst].pl_node.payload_index = astgen.addExtraAssumeCapacity( 10061 Zir.Inst.Block{ .body_len = body_len }, 10062 ); 10063 astgen.appendBodyWithFixups(body); 10064 gz.unstack(); 10065 } 10066 10067 /// Assumes nothing stacked on `gz`. Unstacks `gz`. 10068 fn setTryBody(gz: *GenZir, inst: Zir.Inst.Index, operand: Zir.Inst.Ref) !void { 10069 const astgen = gz.astgen; 10070 const gpa = astgen.gpa; 10071 const body = gz.instructionsSlice(); 10072 const body_len = astgen.countBodyLenAfterFixups(body); 10073 try astgen.extra.ensureUnusedCapacity( 10074 gpa, 10075 @typeInfo(Zir.Inst.Try).Struct.fields.len + body_len, 10076 ); 10077 const zir_datas = astgen.instructions.items(.data); 10078 zir_datas[inst].pl_node.payload_index = astgen.addExtraAssumeCapacity( 10079 Zir.Inst.Try{ 10080 .operand = operand, 10081 .body_len = body_len, 10082 }, 10083 ); 10084 astgen.appendBodyWithFixups(body); 10085 gz.unstack(); 10086 } 10087 10088 /// Must be called with the following stack set up: 10089 /// * gz (bottom) 10090 /// * align_gz 10091 /// * addrspace_gz 10092 /// * section_gz 10093 /// * cc_gz 10094 /// * ret_gz 10095 /// * body_gz (top) 10096 /// Unstacks all of those except for `gz`. 10097 fn addFunc(gz: *GenZir, args: struct { 10098 src_node: Ast.Node.Index, 10099 lbrace_line: u32 = 0, 10100 lbrace_column: u32 = 0, 10101 param_block: Zir.Inst.Index, 10102 10103 align_gz: ?*GenZir, 10104 addrspace_gz: ?*GenZir, 10105 section_gz: ?*GenZir, 10106 cc_gz: ?*GenZir, 10107 ret_gz: ?*GenZir, 10108 body_gz: ?*GenZir, 10109 10110 align_ref: Zir.Inst.Ref, 10111 addrspace_ref: Zir.Inst.Ref, 10112 section_ref: Zir.Inst.Ref, 10113 cc_ref: Zir.Inst.Ref, 10114 ret_ref: Zir.Inst.Ref, 10115 10116 lib_name: u32, 10117 noalias_bits: u32, 10118 is_var_args: bool, 10119 is_inferred_error: bool, 10120 is_test: bool, 10121 is_extern: bool, 10122 }) !Zir.Inst.Ref { 10123 assert(args.src_node != 0); 10124 const astgen = gz.astgen; 10125 const gpa = astgen.gpa; 10126 const ret_ref = if (args.ret_ref == .void_type) .none else args.ret_ref; 10127 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 10128 10129 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 10130 10131 var body: []Zir.Inst.Index = &[0]Zir.Inst.Index{}; 10132 var ret_body: []Zir.Inst.Index = &[0]Zir.Inst.Index{}; 10133 var src_locs_buffer: [3]u32 = undefined; 10134 var src_locs: []u32 = src_locs_buffer[0..0]; 10135 if (args.body_gz) |body_gz| { 10136 const tree = astgen.tree; 10137 const node_tags = tree.nodes.items(.tag); 10138 const node_datas = tree.nodes.items(.data); 10139 const token_starts = tree.tokens.items(.start); 10140 const fn_decl = args.src_node; 10141 assert(node_tags[fn_decl] == .fn_decl or node_tags[fn_decl] == .test_decl); 10142 const block = node_datas[fn_decl].rhs; 10143 const rbrace_start = token_starts[tree.lastToken(block)]; 10144 astgen.advanceSourceCursor(rbrace_start); 10145 const rbrace_line = @intCast(u32, astgen.source_line - gz.decl_line); 10146 const rbrace_column = @intCast(u32, astgen.source_column); 10147 10148 const columns = args.lbrace_column | (rbrace_column << 16); 10149 src_locs_buffer[0] = args.lbrace_line; 10150 src_locs_buffer[1] = rbrace_line; 10151 src_locs_buffer[2] = columns; 10152 src_locs = &src_locs_buffer; 10153 10154 body = body_gz.instructionsSlice(); 10155 if (args.ret_gz) |ret_gz| 10156 ret_body = ret_gz.instructionsSliceUpto(body_gz); 10157 } else { 10158 if (args.ret_gz) |ret_gz| 10159 ret_body = ret_gz.instructionsSlice(); 10160 } 10161 const body_len = astgen.countBodyLenAfterFixups(body); 10162 10163 if (args.cc_ref != .none or args.lib_name != 0 or 10164 args.is_var_args or args.is_test or args.is_extern or 10165 args.align_ref != .none or args.section_ref != .none or 10166 args.addrspace_ref != .none or args.noalias_bits != 0) 10167 { 10168 var align_body: []Zir.Inst.Index = &.{}; 10169 var addrspace_body: []Zir.Inst.Index = &.{}; 10170 var section_body: []Zir.Inst.Index = &.{}; 10171 var cc_body: []Zir.Inst.Index = &.{}; 10172 if (args.ret_gz != null) { 10173 align_body = args.align_gz.?.instructionsSliceUpto(args.addrspace_gz.?); 10174 addrspace_body = args.addrspace_gz.?.instructionsSliceUpto(args.section_gz.?); 10175 section_body = args.section_gz.?.instructionsSliceUpto(args.cc_gz.?); 10176 cc_body = args.cc_gz.?.instructionsSliceUpto(args.ret_gz.?); 10177 } 10178 10179 try astgen.extra.ensureUnusedCapacity( 10180 gpa, 10181 @typeInfo(Zir.Inst.FuncFancy).Struct.fields.len + 10182 fancyFnExprExtraLen(align_body, args.align_ref) + 10183 fancyFnExprExtraLen(addrspace_body, args.addrspace_ref) + 10184 fancyFnExprExtraLen(section_body, args.section_ref) + 10185 fancyFnExprExtraLen(cc_body, args.cc_ref) + 10186 fancyFnExprExtraLen(ret_body, ret_ref) + 10187 body_len + src_locs.len + 10188 @boolToInt(args.lib_name != 0) + 10189 @boolToInt(args.noalias_bits != 0), 10190 ); 10191 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.FuncFancy{ 10192 .param_block = args.param_block, 10193 .body_len = body_len, 10194 .bits = .{ 10195 .is_var_args = args.is_var_args, 10196 .is_inferred_error = args.is_inferred_error, 10197 .is_test = args.is_test, 10198 .is_extern = args.is_extern, 10199 .has_lib_name = args.lib_name != 0, 10200 .has_any_noalias = args.noalias_bits != 0, 10201 10202 .has_align_ref = args.align_ref != .none, 10203 .has_addrspace_ref = args.addrspace_ref != .none, 10204 .has_section_ref = args.section_ref != .none, 10205 .has_cc_ref = args.cc_ref != .none, 10206 .has_ret_ty_ref = ret_ref != .none, 10207 10208 .has_align_body = align_body.len != 0, 10209 .has_addrspace_body = addrspace_body.len != 0, 10210 .has_section_body = section_body.len != 0, 10211 .has_cc_body = cc_body.len != 0, 10212 .has_ret_ty_body = ret_body.len != 0, 10213 }, 10214 }); 10215 if (args.lib_name != 0) { 10216 astgen.extra.appendAssumeCapacity(args.lib_name); 10217 } 10218 10219 const zir_datas = astgen.instructions.items(.data); 10220 if (align_body.len != 0) { 10221 astgen.extra.appendAssumeCapacity(@intCast(u32, align_body.len)); 10222 astgen.extra.appendSliceAssumeCapacity(align_body); 10223 zir_datas[align_body[align_body.len - 1]].@"break".block_inst = new_index; 10224 } else if (args.align_ref != .none) { 10225 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_ref)); 10226 } 10227 if (addrspace_body.len != 0) { 10228 astgen.extra.appendAssumeCapacity(@intCast(u32, addrspace_body.len)); 10229 astgen.extra.appendSliceAssumeCapacity(addrspace_body); 10230 zir_datas[addrspace_body[addrspace_body.len - 1]].@"break".block_inst = new_index; 10231 } else if (args.addrspace_ref != .none) { 10232 astgen.extra.appendAssumeCapacity(@enumToInt(args.addrspace_ref)); 10233 } 10234 if (section_body.len != 0) { 10235 astgen.extra.appendAssumeCapacity(@intCast(u32, section_body.len)); 10236 astgen.extra.appendSliceAssumeCapacity(section_body); 10237 zir_datas[section_body[section_body.len - 1]].@"break".block_inst = new_index; 10238 } else if (args.section_ref != .none) { 10239 astgen.extra.appendAssumeCapacity(@enumToInt(args.section_ref)); 10240 } 10241 if (cc_body.len != 0) { 10242 astgen.extra.appendAssumeCapacity(@intCast(u32, cc_body.len)); 10243 astgen.extra.appendSliceAssumeCapacity(cc_body); 10244 zir_datas[cc_body[cc_body.len - 1]].@"break".block_inst = new_index; 10245 } else if (args.cc_ref != .none) { 10246 astgen.extra.appendAssumeCapacity(@enumToInt(args.cc_ref)); 10247 } 10248 if (ret_body.len != 0) { 10249 astgen.extra.appendAssumeCapacity(@intCast(u32, ret_body.len)); 10250 astgen.extra.appendSliceAssumeCapacity(ret_body); 10251 zir_datas[ret_body[ret_body.len - 1]].@"break".block_inst = new_index; 10252 } else if (ret_ref != .none) { 10253 astgen.extra.appendAssumeCapacity(@enumToInt(ret_ref)); 10254 } 10255 10256 if (args.noalias_bits != 0) { 10257 astgen.extra.appendAssumeCapacity(args.noalias_bits); 10258 } 10259 10260 astgen.appendBodyWithFixups(body); 10261 astgen.extra.appendSliceAssumeCapacity(src_locs); 10262 10263 // Order is important when unstacking. 10264 if (args.body_gz) |body_gz| body_gz.unstack(); 10265 if (args.ret_gz != null) { 10266 args.ret_gz.?.unstack(); 10267 args.cc_gz.?.unstack(); 10268 args.section_gz.?.unstack(); 10269 args.addrspace_gz.?.unstack(); 10270 args.align_gz.?.unstack(); 10271 } 10272 10273 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10274 10275 astgen.instructions.appendAssumeCapacity(.{ 10276 .tag = .func_fancy, 10277 .data = .{ .pl_node = .{ 10278 .src_node = gz.nodeIndexToRelative(args.src_node), 10279 .payload_index = payload_index, 10280 } }, 10281 }); 10282 gz.instructions.appendAssumeCapacity(new_index); 10283 return indexToRef(new_index); 10284 } else { 10285 try astgen.extra.ensureUnusedCapacity( 10286 gpa, 10287 @typeInfo(Zir.Inst.Func).Struct.fields.len + 1 + 10288 @maximum(ret_body.len, @boolToInt(ret_ref != .none)) + 10289 body_len + src_locs.len, 10290 ); 10291 const ret_body_len = if (ret_body.len != 0) 10292 @intCast(u32, ret_body.len) 10293 else 10294 @boolToInt(ret_ref != .none); 10295 10296 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.Func{ 10297 .param_block = args.param_block, 10298 .ret_body_len = ret_body_len, 10299 .body_len = body_len, 10300 }); 10301 const zir_datas = astgen.instructions.items(.data); 10302 if (ret_body.len != 0) { 10303 astgen.extra.appendSliceAssumeCapacity(ret_body); 10304 zir_datas[ret_body[ret_body.len - 1]].@"break".block_inst = new_index; 10305 } else if (ret_ref != .none) { 10306 astgen.extra.appendAssumeCapacity(@enumToInt(ret_ref)); 10307 } 10308 astgen.appendBodyWithFixups(body); 10309 astgen.extra.appendSliceAssumeCapacity(src_locs); 10310 10311 // Order is important when unstacking. 10312 if (args.body_gz) |body_gz| body_gz.unstack(); 10313 if (args.ret_gz) |ret_gz| ret_gz.unstack(); 10314 if (args.cc_gz) |cc_gz| cc_gz.unstack(); 10315 if (args.section_gz) |section_gz| section_gz.unstack(); 10316 if (args.addrspace_gz) |addrspace_gz| addrspace_gz.unstack(); 10317 if (args.align_gz) |align_gz| align_gz.unstack(); 10318 10319 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10320 10321 const tag: Zir.Inst.Tag = if (args.is_inferred_error) .func_inferred else .func; 10322 astgen.instructions.appendAssumeCapacity(.{ 10323 .tag = tag, 10324 .data = .{ .pl_node = .{ 10325 .src_node = gz.nodeIndexToRelative(args.src_node), 10326 .payload_index = payload_index, 10327 } }, 10328 }); 10329 gz.instructions.appendAssumeCapacity(new_index); 10330 return indexToRef(new_index); 10331 } 10332 } 10333 10334 fn fancyFnExprExtraLen(body: []Zir.Inst.Index, ref: Zir.Inst.Ref) usize { 10335 // In the case of non-empty body, there is one for the body length, 10336 // and then one for each instruction. 10337 return body.len + @boolToInt(ref != .none); 10338 } 10339 10340 fn addVar(gz: *GenZir, args: struct { 10341 align_inst: Zir.Inst.Ref, 10342 lib_name: u32, 10343 var_type: Zir.Inst.Ref, 10344 init: Zir.Inst.Ref, 10345 is_extern: bool, 10346 is_threadlocal: bool, 10347 }) !Zir.Inst.Ref { 10348 const astgen = gz.astgen; 10349 const gpa = astgen.gpa; 10350 10351 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10352 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 10353 10354 try astgen.extra.ensureUnusedCapacity( 10355 gpa, 10356 @typeInfo(Zir.Inst.ExtendedVar).Struct.fields.len + 10357 @boolToInt(args.lib_name != 0) + 10358 @boolToInt(args.align_inst != .none) + 10359 @boolToInt(args.init != .none), 10360 ); 10361 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedVar{ 10362 .var_type = args.var_type, 10363 }); 10364 if (args.lib_name != 0) { 10365 astgen.extra.appendAssumeCapacity(args.lib_name); 10366 } 10367 if (args.align_inst != .none) { 10368 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); 10369 } 10370 if (args.init != .none) { 10371 astgen.extra.appendAssumeCapacity(@enumToInt(args.init)); 10372 } 10373 10374 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 10375 astgen.instructions.appendAssumeCapacity(.{ 10376 .tag = .extended, 10377 .data = .{ .extended = .{ 10378 .opcode = .variable, 10379 .small = @bitCast(u16, Zir.Inst.ExtendedVar.Small{ 10380 .has_lib_name = args.lib_name != 0, 10381 .has_align = args.align_inst != .none, 10382 .has_init = args.init != .none, 10383 .is_extern = args.is_extern, 10384 .is_threadlocal = args.is_threadlocal, 10385 }), 10386 .operand = payload_index, 10387 } }, 10388 }); 10389 gz.instructions.appendAssumeCapacity(new_index); 10390 return indexToRef(new_index); 10391 } 10392 10393 /// Note that this returns a `Zir.Inst.Index` not a ref. 10394 /// Leaves the `payload_index` field undefined. 10395 fn addBoolBr( 10396 gz: *GenZir, 10397 tag: Zir.Inst.Tag, 10398 lhs: Zir.Inst.Ref, 10399 ) !Zir.Inst.Index { 10400 assert(lhs != .none); 10401 const gpa = gz.astgen.gpa; 10402 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10403 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 10404 10405 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 10406 gz.astgen.instructions.appendAssumeCapacity(.{ 10407 .tag = tag, 10408 .data = .{ .bool_br = .{ 10409 .lhs = lhs, 10410 .payload_index = undefined, 10411 } }, 10412 }); 10413 gz.instructions.appendAssumeCapacity(new_index); 10414 return new_index; 10415 } 10416 10417 fn addInt(gz: *GenZir, integer: u64) !Zir.Inst.Ref { 10418 return gz.add(.{ 10419 .tag = .int, 10420 .data = .{ .int = integer }, 10421 }); 10422 } 10423 10424 fn addIntBig(gz: *GenZir, limbs: []const std.math.big.Limb) !Zir.Inst.Ref { 10425 const astgen = gz.astgen; 10426 const gpa = astgen.gpa; 10427 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10428 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 10429 try astgen.string_bytes.ensureUnusedCapacity(gpa, @sizeOf(std.math.big.Limb) * limbs.len); 10430 10431 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 10432 astgen.instructions.appendAssumeCapacity(.{ 10433 .tag = .int_big, 10434 .data = .{ .str = .{ 10435 .start = @intCast(u32, astgen.string_bytes.items.len), 10436 .len = @intCast(u32, limbs.len), 10437 } }, 10438 }); 10439 gz.instructions.appendAssumeCapacity(new_index); 10440 astgen.string_bytes.appendSliceAssumeCapacity(mem.sliceAsBytes(limbs)); 10441 return indexToRef(new_index); 10442 } 10443 10444 fn addFloat(gz: *GenZir, number: f64) !Zir.Inst.Ref { 10445 return gz.add(.{ 10446 .tag = .float, 10447 .data = .{ .float = number }, 10448 }); 10449 } 10450 10451 fn addUnNode( 10452 gz: *GenZir, 10453 tag: Zir.Inst.Tag, 10454 operand: Zir.Inst.Ref, 10455 /// Absolute node index. This function does the conversion to offset from Decl. 10456 src_node: Ast.Node.Index, 10457 ) !Zir.Inst.Ref { 10458 assert(operand != .none); 10459 return gz.add(.{ 10460 .tag = tag, 10461 .data = .{ .un_node = .{ 10462 .operand = operand, 10463 .src_node = gz.nodeIndexToRelative(src_node), 10464 } }, 10465 }); 10466 } 10467 10468 fn makeUnNode( 10469 gz: *GenZir, 10470 tag: Zir.Inst.Tag, 10471 operand: Zir.Inst.Ref, 10472 /// Absolute node index. This function does the conversion to offset from Decl. 10473 src_node: Ast.Node.Index, 10474 ) !Zir.Inst.Index { 10475 assert(operand != .none); 10476 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 10477 try gz.astgen.instructions.append(gz.astgen.gpa, .{ 10478 .tag = tag, 10479 .data = .{ .un_node = .{ 10480 .operand = operand, 10481 .src_node = gz.nodeIndexToRelative(src_node), 10482 } }, 10483 }); 10484 return new_index; 10485 } 10486 10487 fn addPlNode( 10488 gz: *GenZir, 10489 tag: Zir.Inst.Tag, 10490 /// Absolute node index. This function does the conversion to offset from Decl. 10491 src_node: Ast.Node.Index, 10492 extra: anytype, 10493 ) !Zir.Inst.Ref { 10494 const gpa = gz.astgen.gpa; 10495 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10496 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 10497 10498 const payload_index = try gz.astgen.addExtra(extra); 10499 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 10500 gz.astgen.instructions.appendAssumeCapacity(.{ 10501 .tag = tag, 10502 .data = .{ .pl_node = .{ 10503 .src_node = gz.nodeIndexToRelative(src_node), 10504 .payload_index = payload_index, 10505 } }, 10506 }); 10507 gz.instructions.appendAssumeCapacity(new_index); 10508 return indexToRef(new_index); 10509 } 10510 10511 fn addPlNodePayloadIndex( 10512 gz: *GenZir, 10513 tag: Zir.Inst.Tag, 10514 /// Absolute node index. This function does the conversion to offset from Decl. 10515 src_node: Ast.Node.Index, 10516 payload_index: u32, 10517 ) !Zir.Inst.Ref { 10518 return try gz.add(.{ 10519 .tag = tag, 10520 .data = .{ .pl_node = .{ 10521 .src_node = gz.nodeIndexToRelative(src_node), 10522 .payload_index = payload_index, 10523 } }, 10524 }); 10525 } 10526 10527 /// Supports `param_gz` stacked on `gz`. Assumes nothing stacked on `param_gz`. Unstacks `param_gz`. 10528 fn addParam( 10529 gz: *GenZir, 10530 param_gz: *GenZir, 10531 tag: Zir.Inst.Tag, 10532 /// Absolute token index. This function does the conversion to Decl offset. 10533 abs_tok_index: Ast.TokenIndex, 10534 name: u32, 10535 first_doc_comment: ?Ast.TokenIndex, 10536 ) !Zir.Inst.Index { 10537 const gpa = gz.astgen.gpa; 10538 const param_body = param_gz.instructionsSlice(); 10539 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 10540 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Param).Struct.fields.len + 10541 param_body.len); 10542 10543 const doc_comment_index = if (first_doc_comment) |first| 10544 try gz.astgen.docCommentAsStringFromFirst(abs_tok_index, first) 10545 else 10546 0; 10547 10548 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Param{ 10549 .name = name, 10550 .doc_comment = doc_comment_index, 10551 .body_len = @intCast(u32, param_body.len), 10552 }); 10553 gz.astgen.extra.appendSliceAssumeCapacity(param_body); 10554 param_gz.unstack(); 10555 10556 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 10557 gz.astgen.instructions.appendAssumeCapacity(.{ 10558 .tag = tag, 10559 .data = .{ .pl_tok = .{ 10560 .src_tok = gz.tokenIndexToRelative(abs_tok_index), 10561 .payload_index = payload_index, 10562 } }, 10563 }); 10564 gz.instructions.appendAssumeCapacity(new_index); 10565 return new_index; 10566 } 10567 10568 fn addExtendedPayload( 10569 gz: *GenZir, 10570 opcode: Zir.Inst.Extended, 10571 extra: anytype, 10572 ) !Zir.Inst.Ref { 10573 const gpa = gz.astgen.gpa; 10574 10575 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10576 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 10577 10578 const payload_index = try gz.astgen.addExtra(extra); 10579 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 10580 gz.astgen.instructions.appendAssumeCapacity(.{ 10581 .tag = .extended, 10582 .data = .{ .extended = .{ 10583 .opcode = opcode, 10584 .small = undefined, 10585 .operand = payload_index, 10586 } }, 10587 }); 10588 gz.instructions.appendAssumeCapacity(new_index); 10589 return indexToRef(new_index); 10590 } 10591 10592 fn addExtendedMultiOp( 10593 gz: *GenZir, 10594 opcode: Zir.Inst.Extended, 10595 node: Ast.Node.Index, 10596 operands: []const Zir.Inst.Ref, 10597 ) !Zir.Inst.Ref { 10598 const astgen = gz.astgen; 10599 const gpa = astgen.gpa; 10600 10601 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10602 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 10603 try astgen.extra.ensureUnusedCapacity( 10604 gpa, 10605 @typeInfo(Zir.Inst.NodeMultiOp).Struct.fields.len + operands.len, 10606 ); 10607 10608 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.NodeMultiOp{ 10609 .src_node = gz.nodeIndexToRelative(node), 10610 }); 10611 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 10612 astgen.instructions.appendAssumeCapacity(.{ 10613 .tag = .extended, 10614 .data = .{ .extended = .{ 10615 .opcode = opcode, 10616 .small = @intCast(u16, operands.len), 10617 .operand = payload_index, 10618 } }, 10619 }); 10620 gz.instructions.appendAssumeCapacity(new_index); 10621 astgen.appendRefsAssumeCapacity(operands); 10622 return indexToRef(new_index); 10623 } 10624 10625 fn addExtendedMultiOpPayloadIndex( 10626 gz: *GenZir, 10627 opcode: Zir.Inst.Extended, 10628 payload_index: u32, 10629 trailing_len: usize, 10630 ) !Zir.Inst.Ref { 10631 const astgen = gz.astgen; 10632 const gpa = astgen.gpa; 10633 10634 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10635 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 10636 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 10637 astgen.instructions.appendAssumeCapacity(.{ 10638 .tag = .extended, 10639 .data = .{ .extended = .{ 10640 .opcode = opcode, 10641 .small = @intCast(u16, trailing_len), 10642 .operand = payload_index, 10643 } }, 10644 }); 10645 gz.instructions.appendAssumeCapacity(new_index); 10646 return indexToRef(new_index); 10647 } 10648 10649 fn addUnTok( 10650 gz: *GenZir, 10651 tag: Zir.Inst.Tag, 10652 operand: Zir.Inst.Ref, 10653 /// Absolute token index. This function does the conversion to Decl offset. 10654 abs_tok_index: Ast.TokenIndex, 10655 ) !Zir.Inst.Ref { 10656 assert(operand != .none); 10657 return gz.add(.{ 10658 .tag = tag, 10659 .data = .{ .un_tok = .{ 10660 .operand = operand, 10661 .src_tok = gz.tokenIndexToRelative(abs_tok_index), 10662 } }, 10663 }); 10664 } 10665 10666 fn makeUnTok( 10667 gz: *GenZir, 10668 tag: Zir.Inst.Tag, 10669 operand: Zir.Inst.Ref, 10670 /// Absolute token index. This function does the conversion to Decl offset. 10671 abs_tok_index: Ast.TokenIndex, 10672 ) !Zir.Inst.Index { 10673 const astgen = gz.astgen; 10674 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 10675 assert(operand != .none); 10676 try astgen.instructions.append(astgen.gpa, .{ 10677 .tag = tag, 10678 .data = .{ .un_tok = .{ 10679 .operand = operand, 10680 .src_tok = gz.tokenIndexToRelative(abs_tok_index), 10681 } }, 10682 }); 10683 return new_index; 10684 } 10685 10686 fn addStrTok( 10687 gz: *GenZir, 10688 tag: Zir.Inst.Tag, 10689 str_index: u32, 10690 /// Absolute token index. This function does the conversion to Decl offset. 10691 abs_tok_index: Ast.TokenIndex, 10692 ) !Zir.Inst.Ref { 10693 return gz.add(.{ 10694 .tag = tag, 10695 .data = .{ .str_tok = .{ 10696 .start = str_index, 10697 .src_tok = gz.tokenIndexToRelative(abs_tok_index), 10698 } }, 10699 }); 10700 } 10701 10702 fn addBreak( 10703 gz: *GenZir, 10704 tag: Zir.Inst.Tag, 10705 break_block: Zir.Inst.Index, 10706 operand: Zir.Inst.Ref, 10707 ) !Zir.Inst.Index { 10708 return gz.addAsIndex(.{ 10709 .tag = tag, 10710 .data = .{ .@"break" = .{ 10711 .block_inst = break_block, 10712 .operand = operand, 10713 } }, 10714 }); 10715 } 10716 10717 fn makeBreak( 10718 gz: *GenZir, 10719 tag: Zir.Inst.Tag, 10720 break_block: Zir.Inst.Index, 10721 operand: Zir.Inst.Ref, 10722 ) !Zir.Inst.Index { 10723 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 10724 try gz.astgen.instructions.append(gz.astgen.gpa, .{ 10725 .tag = tag, 10726 .data = .{ .@"break" = .{ 10727 .block_inst = break_block, 10728 .operand = operand, 10729 } }, 10730 }); 10731 return new_index; 10732 } 10733 10734 fn addBin( 10735 gz: *GenZir, 10736 tag: Zir.Inst.Tag, 10737 lhs: Zir.Inst.Ref, 10738 rhs: Zir.Inst.Ref, 10739 ) !Zir.Inst.Ref { 10740 assert(lhs != .none); 10741 assert(rhs != .none); 10742 return gz.add(.{ 10743 .tag = tag, 10744 .data = .{ .bin = .{ 10745 .lhs = lhs, 10746 .rhs = rhs, 10747 } }, 10748 }); 10749 } 10750 10751 fn addDecl( 10752 gz: *GenZir, 10753 tag: Zir.Inst.Tag, 10754 decl_index: u32, 10755 src_node: Ast.Node.Index, 10756 ) !Zir.Inst.Ref { 10757 return gz.add(.{ 10758 .tag = tag, 10759 .data = .{ .pl_node = .{ 10760 .src_node = gz.nodeIndexToRelative(src_node), 10761 .payload_index = decl_index, 10762 } }, 10763 }); 10764 } 10765 10766 fn addNode( 10767 gz: *GenZir, 10768 tag: Zir.Inst.Tag, 10769 /// Absolute node index. This function does the conversion to offset from Decl. 10770 src_node: Ast.Node.Index, 10771 ) !Zir.Inst.Ref { 10772 return gz.add(.{ 10773 .tag = tag, 10774 .data = .{ .node = gz.nodeIndexToRelative(src_node) }, 10775 }); 10776 } 10777 10778 fn addInstNode( 10779 gz: *GenZir, 10780 tag: Zir.Inst.Tag, 10781 inst: Zir.Inst.Index, 10782 /// Absolute node index. This function does the conversion to offset from Decl. 10783 src_node: Ast.Node.Index, 10784 ) !Zir.Inst.Ref { 10785 return gz.add(.{ 10786 .tag = tag, 10787 .data = .{ .inst_node = .{ 10788 .inst = inst, 10789 .src_node = gz.nodeIndexToRelative(src_node), 10790 } }, 10791 }); 10792 } 10793 10794 fn addNodeExtended( 10795 gz: *GenZir, 10796 opcode: Zir.Inst.Extended, 10797 /// Absolute node index. This function does the conversion to offset from Decl. 10798 src_node: Ast.Node.Index, 10799 ) !Zir.Inst.Ref { 10800 return gz.add(.{ 10801 .tag = .extended, 10802 .data = .{ .extended = .{ 10803 .opcode = opcode, 10804 .small = undefined, 10805 .operand = @bitCast(u32, gz.nodeIndexToRelative(src_node)), 10806 } }, 10807 }); 10808 } 10809 10810 fn addAllocExtended( 10811 gz: *GenZir, 10812 args: struct { 10813 /// Absolute node index. This function does the conversion to offset from Decl. 10814 node: Ast.Node.Index, 10815 type_inst: Zir.Inst.Ref, 10816 align_inst: Zir.Inst.Ref, 10817 is_const: bool, 10818 is_comptime: bool, 10819 }, 10820 ) !Zir.Inst.Ref { 10821 const astgen = gz.astgen; 10822 const gpa = astgen.gpa; 10823 10824 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10825 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 10826 try astgen.extra.ensureUnusedCapacity( 10827 gpa, 10828 @typeInfo(Zir.Inst.AllocExtended).Struct.fields.len + 10829 @as(usize, @boolToInt(args.type_inst != .none)) + 10830 @as(usize, @boolToInt(args.align_inst != .none)), 10831 ); 10832 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.AllocExtended{ 10833 .src_node = gz.nodeIndexToRelative(args.node), 10834 }); 10835 if (args.type_inst != .none) { 10836 astgen.extra.appendAssumeCapacity(@enumToInt(args.type_inst)); 10837 } 10838 if (args.align_inst != .none) { 10839 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); 10840 } 10841 10842 const has_type: u4 = @boolToInt(args.type_inst != .none); 10843 const has_align: u4 = @boolToInt(args.align_inst != .none); 10844 const is_const: u4 = @boolToInt(args.is_const); 10845 const is_comptime: u4 = @boolToInt(args.is_comptime); 10846 const small: u16 = has_type | (has_align << 1) | (is_const << 2) | (is_comptime << 3); 10847 10848 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 10849 astgen.instructions.appendAssumeCapacity(.{ 10850 .tag = .extended, 10851 .data = .{ .extended = .{ 10852 .opcode = .alloc, 10853 .small = small, 10854 .operand = payload_index, 10855 } }, 10856 }); 10857 gz.instructions.appendAssumeCapacity(new_index); 10858 return indexToRef(new_index); 10859 } 10860 10861 fn addAsm( 10862 gz: *GenZir, 10863 args: struct { 10864 /// Absolute node index. This function does the conversion to offset from Decl. 10865 node: Ast.Node.Index, 10866 asm_source: u32, 10867 output_type_bits: u32, 10868 is_volatile: bool, 10869 outputs: []const Zir.Inst.Asm.Output, 10870 inputs: []const Zir.Inst.Asm.Input, 10871 clobbers: []const u32, 10872 }, 10873 ) !Zir.Inst.Ref { 10874 const astgen = gz.astgen; 10875 const gpa = astgen.gpa; 10876 10877 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10878 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 10879 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Asm).Struct.fields.len + 10880 args.outputs.len * @typeInfo(Zir.Inst.Asm.Output).Struct.fields.len + 10881 args.inputs.len * @typeInfo(Zir.Inst.Asm.Input).Struct.fields.len + 10882 args.clobbers.len); 10883 10884 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Asm{ 10885 .src_node = gz.nodeIndexToRelative(args.node), 10886 .asm_source = args.asm_source, 10887 .output_type_bits = args.output_type_bits, 10888 }); 10889 for (args.outputs) |output| { 10890 _ = gz.astgen.addExtraAssumeCapacity(output); 10891 } 10892 for (args.inputs) |input| { 10893 _ = gz.astgen.addExtraAssumeCapacity(input); 10894 } 10895 gz.astgen.extra.appendSliceAssumeCapacity(args.clobbers); 10896 10897 // * 0b00000000_000XXXXX - `outputs_len`. 10898 // * 0b000000XX_XXX00000 - `inputs_len`. 10899 // * 0b0XXXXX00_00000000 - `clobbers_len`. 10900 // * 0bX0000000_00000000 - is volatile 10901 const small: u16 = @intCast(u16, args.outputs.len) | 10902 @intCast(u16, args.inputs.len << 5) | 10903 @intCast(u16, args.clobbers.len << 10) | 10904 (@as(u16, @boolToInt(args.is_volatile)) << 15); 10905 10906 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 10907 astgen.instructions.appendAssumeCapacity(.{ 10908 .tag = .extended, 10909 .data = .{ .extended = .{ 10910 .opcode = .@"asm", 10911 .small = small, 10912 .operand = payload_index, 10913 } }, 10914 }); 10915 gz.instructions.appendAssumeCapacity(new_index); 10916 return indexToRef(new_index); 10917 } 10918 10919 /// Note that this returns a `Zir.Inst.Index` not a ref. 10920 /// Does *not* append the block instruction to the scope. 10921 /// Leaves the `payload_index` field undefined. 10922 fn makeBlockInst(gz: *GenZir, tag: Zir.Inst.Tag, node: Ast.Node.Index) !Zir.Inst.Index { 10923 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 10924 const gpa = gz.astgen.gpa; 10925 try gz.astgen.instructions.append(gpa, .{ 10926 .tag = tag, 10927 .data = .{ .pl_node = .{ 10928 .src_node = gz.nodeIndexToRelative(node), 10929 .payload_index = undefined, 10930 } }, 10931 }); 10932 return new_index; 10933 } 10934 10935 /// Note that this returns a `Zir.Inst.Index` not a ref. 10936 /// Leaves the `payload_index` field undefined. 10937 fn addCondBr(gz: *GenZir, tag: Zir.Inst.Tag, node: Ast.Node.Index) !Zir.Inst.Index { 10938 const gpa = gz.astgen.gpa; 10939 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10940 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 10941 try gz.astgen.instructions.append(gpa, .{ 10942 .tag = tag, 10943 .data = .{ .pl_node = .{ 10944 .src_node = gz.nodeIndexToRelative(node), 10945 .payload_index = undefined, 10946 } }, 10947 }); 10948 gz.instructions.appendAssumeCapacity(new_index); 10949 return new_index; 10950 } 10951 10952 fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct { 10953 src_node: Ast.Node.Index, 10954 body_len: u32, 10955 fields_len: u32, 10956 decls_len: u32, 10957 layout: std.builtin.Type.ContainerLayout, 10958 known_non_opv: bool, 10959 known_comptime_only: bool, 10960 }) !void { 10961 const astgen = gz.astgen; 10962 const gpa = astgen.gpa; 10963 10964 try astgen.extra.ensureUnusedCapacity(gpa, 4); 10965 const payload_index = @intCast(u32, astgen.extra.items.len); 10966 10967 if (args.src_node != 0) { 10968 const node_offset = gz.nodeIndexToRelative(args.src_node); 10969 astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset)); 10970 } 10971 if (args.body_len != 0) { 10972 astgen.extra.appendAssumeCapacity(args.body_len); 10973 } 10974 if (args.fields_len != 0) { 10975 astgen.extra.appendAssumeCapacity(args.fields_len); 10976 } 10977 if (args.decls_len != 0) { 10978 astgen.extra.appendAssumeCapacity(args.decls_len); 10979 } 10980 astgen.instructions.set(inst, .{ 10981 .tag = .extended, 10982 .data = .{ .extended = .{ 10983 .opcode = .struct_decl, 10984 .small = @bitCast(u16, Zir.Inst.StructDecl.Small{ 10985 .has_src_node = args.src_node != 0, 10986 .has_body_len = args.body_len != 0, 10987 .has_fields_len = args.fields_len != 0, 10988 .has_decls_len = args.decls_len != 0, 10989 .known_non_opv = args.known_non_opv, 10990 .known_comptime_only = args.known_comptime_only, 10991 .name_strategy = gz.anon_name_strategy, 10992 .layout = args.layout, 10993 }), 10994 .operand = payload_index, 10995 } }, 10996 }); 10997 } 10998 10999 fn setUnion(gz: *GenZir, inst: Zir.Inst.Index, args: struct { 11000 src_node: Ast.Node.Index, 11001 tag_type: Zir.Inst.Ref, 11002 body_len: u32, 11003 fields_len: u32, 11004 decls_len: u32, 11005 layout: std.builtin.Type.ContainerLayout, 11006 auto_enum_tag: bool, 11007 }) !void { 11008 const astgen = gz.astgen; 11009 const gpa = astgen.gpa; 11010 11011 try astgen.extra.ensureUnusedCapacity(gpa, 5); 11012 const payload_index = @intCast(u32, astgen.extra.items.len); 11013 11014 if (args.src_node != 0) { 11015 const node_offset = gz.nodeIndexToRelative(args.src_node); 11016 astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset)); 11017 } 11018 if (args.tag_type != .none) { 11019 astgen.extra.appendAssumeCapacity(@enumToInt(args.tag_type)); 11020 } 11021 if (args.body_len != 0) { 11022 astgen.extra.appendAssumeCapacity(args.body_len); 11023 } 11024 if (args.fields_len != 0) { 11025 astgen.extra.appendAssumeCapacity(args.fields_len); 11026 } 11027 if (args.decls_len != 0) { 11028 astgen.extra.appendAssumeCapacity(args.decls_len); 11029 } 11030 astgen.instructions.set(inst, .{ 11031 .tag = .extended, 11032 .data = .{ .extended = .{ 11033 .opcode = .union_decl, 11034 .small = @bitCast(u16, Zir.Inst.UnionDecl.Small{ 11035 .has_src_node = args.src_node != 0, 11036 .has_tag_type = args.tag_type != .none, 11037 .has_body_len = args.body_len != 0, 11038 .has_fields_len = args.fields_len != 0, 11039 .has_decls_len = args.decls_len != 0, 11040 .name_strategy = gz.anon_name_strategy, 11041 .layout = args.layout, 11042 .auto_enum_tag = args.auto_enum_tag, 11043 }), 11044 .operand = payload_index, 11045 } }, 11046 }); 11047 } 11048 11049 fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct { 11050 src_node: Ast.Node.Index, 11051 tag_type: Zir.Inst.Ref, 11052 body_len: u32, 11053 fields_len: u32, 11054 decls_len: u32, 11055 nonexhaustive: bool, 11056 }) !void { 11057 const astgen = gz.astgen; 11058 const gpa = astgen.gpa; 11059 11060 try astgen.extra.ensureUnusedCapacity(gpa, 5); 11061 const payload_index = @intCast(u32, astgen.extra.items.len); 11062 11063 if (args.src_node != 0) { 11064 const node_offset = gz.nodeIndexToRelative(args.src_node); 11065 astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset)); 11066 } 11067 if (args.tag_type != .none) { 11068 astgen.extra.appendAssumeCapacity(@enumToInt(args.tag_type)); 11069 } 11070 if (args.body_len != 0) { 11071 astgen.extra.appendAssumeCapacity(args.body_len); 11072 } 11073 if (args.fields_len != 0) { 11074 astgen.extra.appendAssumeCapacity(args.fields_len); 11075 } 11076 if (args.decls_len != 0) { 11077 astgen.extra.appendAssumeCapacity(args.decls_len); 11078 } 11079 astgen.instructions.set(inst, .{ 11080 .tag = .extended, 11081 .data = .{ .extended = .{ 11082 .opcode = .enum_decl, 11083 .small = @bitCast(u16, Zir.Inst.EnumDecl.Small{ 11084 .has_src_node = args.src_node != 0, 11085 .has_tag_type = args.tag_type != .none, 11086 .has_body_len = args.body_len != 0, 11087 .has_fields_len = args.fields_len != 0, 11088 .has_decls_len = args.decls_len != 0, 11089 .name_strategy = gz.anon_name_strategy, 11090 .nonexhaustive = args.nonexhaustive, 11091 }), 11092 .operand = payload_index, 11093 } }, 11094 }); 11095 } 11096 11097 fn setOpaque(gz: *GenZir, inst: Zir.Inst.Index, args: struct { 11098 src_node: Ast.Node.Index, 11099 decls_len: u32, 11100 }) !void { 11101 const astgen = gz.astgen; 11102 const gpa = astgen.gpa; 11103 11104 try astgen.extra.ensureUnusedCapacity(gpa, 2); 11105 const payload_index = @intCast(u32, astgen.extra.items.len); 11106 11107 if (args.src_node != 0) { 11108 const node_offset = gz.nodeIndexToRelative(args.src_node); 11109 astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset)); 11110 } 11111 if (args.decls_len != 0) { 11112 astgen.extra.appendAssumeCapacity(args.decls_len); 11113 } 11114 astgen.instructions.set(inst, .{ 11115 .tag = .extended, 11116 .data = .{ .extended = .{ 11117 .opcode = .opaque_decl, 11118 .small = @bitCast(u16, Zir.Inst.OpaqueDecl.Small{ 11119 .has_src_node = args.src_node != 0, 11120 .has_decls_len = args.decls_len != 0, 11121 .name_strategy = gz.anon_name_strategy, 11122 }), 11123 .operand = payload_index, 11124 } }, 11125 }); 11126 } 11127 11128 fn add(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Ref { 11129 return indexToRef(try gz.addAsIndex(inst)); 11130 } 11131 11132 fn addAsIndex(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Index { 11133 const gpa = gz.astgen.gpa; 11134 try gz.instructions.ensureUnusedCapacity(gpa, 1); 11135 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 11136 11137 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 11138 gz.astgen.instructions.appendAssumeCapacity(inst); 11139 gz.instructions.appendAssumeCapacity(new_index); 11140 return new_index; 11141 } 11142 11143 fn reserveInstructionIndex(gz: *GenZir) !Zir.Inst.Index { 11144 const gpa = gz.astgen.gpa; 11145 try gz.instructions.ensureUnusedCapacity(gpa, 1); 11146 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 11147 11148 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 11149 gz.astgen.instructions.len += 1; 11150 gz.instructions.appendAssumeCapacity(new_index); 11151 return new_index; 11152 } 11153 11154 fn addRet(gz: *GenZir, rl: ResultLoc, operand: Zir.Inst.Ref, node: Ast.Node.Index) !void { 11155 switch (rl) { 11156 .ptr => |ret_ptr| _ = try gz.addUnNode(.ret_load, ret_ptr, node), 11157 .ty => _ = try gz.addUnNode(.ret_node, operand, node), 11158 else => unreachable, 11159 } 11160 } 11161 11162 fn addNamespaceCaptures(gz: *GenZir, namespace: *Scope.Namespace) !void { 11163 if (namespace.captures.count() > 0) { 11164 try gz.instructions.ensureUnusedCapacity(gz.astgen.gpa, namespace.captures.count()); 11165 for (namespace.captures.values()) |capture| { 11166 gz.instructions.appendAssumeCapacity(capture); 11167 } 11168 } 11169 } 11170 11171 fn addDbgVar(gz: *GenZir, tag: Zir.Inst.Tag, name: u32, inst: Zir.Inst.Ref) !void { 11172 if (gz.force_comptime) return; 11173 11174 _ = try gz.add(.{ .tag = tag, .data = .{ 11175 .str_op = .{ 11176 .str = name, 11177 .operand = inst, 11178 }, 11179 } }); 11180 } 11181 11182 fn addDbgBlockBegin(gz: *GenZir) !void { 11183 if (gz.force_comptime) return; 11184 11185 _ = try gz.add(.{ .tag = .dbg_block_begin, .data = undefined }); 11186 } 11187 11188 fn addDbgBlockEnd(gz: *GenZir) !void { 11189 if (gz.force_comptime) return; 11190 const gpa = gz.astgen.gpa; 11191 11192 const tags = gz.astgen.instructions.items(.tag); 11193 const last_inst = gz.instructions.items[gz.instructions.items.len - 1]; 11194 // remove dbg_block_begin immediately followed by dbg_block_end 11195 if (tags[last_inst] == .dbg_block_begin) { 11196 _ = gz.instructions.pop(); 11197 return; 11198 } 11199 11200 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 11201 try gz.astgen.instructions.append(gpa, .{ .tag = .dbg_block_end, .data = undefined }); 11202 try gz.instructions.insert(gpa, gz.instructions.items.len - 1, new_index); 11203 } 11204 11205 /// Control flow does not fall through the "then" block of a loop; it continues 11206 /// back to the while condition. This prevents `rvalue` from 11207 /// adding an invalid store to the result location of `then_scope`. 11208 fn markAsLoopBody(gz: *GenZir, loop_scope: GenZir) void { 11209 gz.rvalue_noresult = switch (loop_scope.break_result_loc) { 11210 .ptr, .inferred_ptr => |ptr| ptr, 11211 .block_ptr => |block| block.rl_ptr, 11212 else => .none, 11213 }; 11214 } 11215 }; 11216 11217 /// This can only be for short-lived references; the memory becomes invalidated 11218 /// when another string is added. 11219 fn nullTerminatedString(astgen: AstGen, index: usize) [*:0]const u8 { 11220 return @ptrCast([*:0]const u8, astgen.string_bytes.items.ptr) + index; 11221 } 11222 11223 pub fn isPrimitive(name: []const u8) bool { 11224 if (primitives.get(name) != null) return true; 11225 if (name.len < 2) return false; 11226 const first_c = name[0]; 11227 if (first_c != 'i' and first_c != 'u') return false; 11228 if (parseBitCount(name[1..])) |_| { 11229 return true; 11230 } else |err| switch (err) { 11231 error.Overflow => return true, 11232 error.InvalidCharacter => return false, 11233 } 11234 } 11235 11236 /// Local variables shadowing detection, including function parameters. 11237 fn detectLocalShadowing( 11238 astgen: *AstGen, 11239 scope: *Scope, 11240 ident_name: u32, 11241 name_token: Ast.TokenIndex, 11242 token_bytes: []const u8, 11243 ) !void { 11244 const gpa = astgen.gpa; 11245 if (token_bytes[0] != '@' and isPrimitive(token_bytes)) { 11246 return astgen.failTokNotes(name_token, "name shadows primitive '{s}'", .{ 11247 token_bytes, 11248 }, &[_]u32{ 11249 try astgen.errNoteTok(name_token, "consider using @\"{s}\" to disambiguate", .{ 11250 token_bytes, 11251 }), 11252 }); 11253 } 11254 11255 var s = scope; 11256 while (true) switch (s.tag) { 11257 .local_val => { 11258 const local_val = s.cast(Scope.LocalVal).?; 11259 if (local_val.name == ident_name) { 11260 const name_slice = mem.span(astgen.nullTerminatedString(ident_name)); 11261 const name = try gpa.dupe(u8, name_slice); 11262 defer gpa.free(name); 11263 return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{ 11264 @tagName(local_val.id_cat), name, 11265 }, &[_]u32{ 11266 try astgen.errNoteTok( 11267 local_val.token_src, 11268 "previous declaration here", 11269 .{}, 11270 ), 11271 }); 11272 } 11273 s = local_val.parent; 11274 }, 11275 .local_ptr => { 11276 const local_ptr = s.cast(Scope.LocalPtr).?; 11277 if (local_ptr.name == ident_name) { 11278 const name_slice = mem.span(astgen.nullTerminatedString(ident_name)); 11279 const name = try gpa.dupe(u8, name_slice); 11280 defer gpa.free(name); 11281 return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{ 11282 @tagName(local_ptr.id_cat), name, 11283 }, &[_]u32{ 11284 try astgen.errNoteTok( 11285 local_ptr.token_src, 11286 "previous declaration here", 11287 .{}, 11288 ), 11289 }); 11290 } 11291 s = local_ptr.parent; 11292 }, 11293 .namespace => { 11294 const ns = s.cast(Scope.Namespace).?; 11295 const decl_node = ns.decls.get(ident_name) orelse { 11296 s = ns.parent; 11297 continue; 11298 }; 11299 const name_slice = mem.span(astgen.nullTerminatedString(ident_name)); 11300 const name = try gpa.dupe(u8, name_slice); 11301 defer gpa.free(name); 11302 return astgen.failTokNotes(name_token, "local shadows declaration of '{s}'", .{ 11303 name, 11304 }, &[_]u32{ 11305 try astgen.errNoteNode(decl_node, "declared here", .{}), 11306 }); 11307 }, 11308 .gen_zir => s = s.cast(GenZir).?.parent, 11309 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, 11310 .top => break, 11311 }; 11312 } 11313 11314 /// Advances the source cursor to the beginning of `node`. 11315 fn advanceSourceCursorToNode(astgen: *AstGen, node: Ast.Node.Index) void { 11316 const tree = astgen.tree; 11317 const token_starts = tree.tokens.items(.start); 11318 const node_start = token_starts[tree.firstToken(node)]; 11319 astgen.advanceSourceCursor(node_start); 11320 } 11321 11322 /// Advances the source cursor to an absolute byte offset `end` in the file. 11323 fn advanceSourceCursor(astgen: *AstGen, end: usize) void { 11324 const source = astgen.tree.source; 11325 var i = astgen.source_offset; 11326 var line = astgen.source_line; 11327 var column = astgen.source_column; 11328 assert(i <= end); 11329 while (i < end) : (i += 1) { 11330 if (source[i] == '\n') { 11331 line += 1; 11332 column = 0; 11333 } else { 11334 column += 1; 11335 } 11336 } 11337 astgen.source_offset = i; 11338 astgen.source_line = line; 11339 astgen.source_column = column; 11340 } 11341 11342 fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.Node.Index) !u32 { 11343 const gpa = astgen.gpa; 11344 const tree = astgen.tree; 11345 const node_tags = tree.nodes.items(.tag); 11346 const main_tokens = tree.nodes.items(.main_token); 11347 const token_tags = tree.tokens.items(.tag); 11348 var decl_count: u32 = 0; 11349 for (members) |member_node| { 11350 const name_token = switch (node_tags[member_node]) { 11351 .fn_proto_simple, 11352 .fn_proto_multi, 11353 .fn_proto_one, 11354 .fn_proto, 11355 .global_var_decl, 11356 .local_var_decl, 11357 .simple_var_decl, 11358 .aligned_var_decl, 11359 => blk: { 11360 decl_count += 1; 11361 break :blk main_tokens[member_node] + 1; 11362 }, 11363 11364 .fn_decl => blk: { 11365 decl_count += 1; 11366 const ident = main_tokens[member_node] + 1; 11367 if (token_tags[ident] != .identifier) { 11368 switch (astgen.failNode(member_node, "missing function name", .{})) { 11369 error.AnalysisFail => continue, 11370 error.OutOfMemory => return error.OutOfMemory, 11371 } 11372 } 11373 break :blk ident; 11374 }, 11375 11376 .@"comptime", .@"usingnamespace", .test_decl => { 11377 decl_count += 1; 11378 continue; 11379 }, 11380 11381 else => continue, 11382 }; 11383 11384 const token_bytes = astgen.tree.tokenSlice(name_token); 11385 if (token_bytes[0] != '@' and isPrimitive(token_bytes)) { 11386 switch (astgen.failTokNotes(name_token, "name shadows primitive '{s}'", .{ 11387 token_bytes, 11388 }, &[_]u32{ 11389 try astgen.errNoteTok(name_token, "consider using @\"{s}\" to disambiguate", .{ 11390 token_bytes, 11391 }), 11392 })) { 11393 error.AnalysisFail => continue, 11394 error.OutOfMemory => return error.OutOfMemory, 11395 } 11396 } 11397 11398 const name_str_index = try astgen.identAsString(name_token); 11399 const gop = try namespace.decls.getOrPut(gpa, name_str_index); 11400 if (gop.found_existing) { 11401 const name = try gpa.dupe(u8, mem.span(astgen.nullTerminatedString(name_str_index))); 11402 defer gpa.free(name); 11403 switch (astgen.failNodeNotes(member_node, "redeclaration of '{s}'", .{ 11404 name, 11405 }, &[_]u32{ 11406 try astgen.errNoteNode(gop.value_ptr.*, "other declaration here", .{}), 11407 })) { 11408 error.AnalysisFail => continue, 11409 error.OutOfMemory => return error.OutOfMemory, 11410 } 11411 } 11412 gop.value_ptr.* = member_node; 11413 } 11414 return decl_count; 11415 } 11416 11417 fn isInferred(astgen: *AstGen, ref: Zir.Inst.Ref) bool { 11418 const inst = refToIndex(ref) orelse return false; 11419 const zir_tags = astgen.instructions.items(.tag); 11420 return switch (zir_tags[inst]) { 11421 .alloc_inferred, 11422 .alloc_inferred_mut, 11423 .alloc_inferred_comptime, 11424 .alloc_inferred_comptime_mut, 11425 => true, 11426 11427 else => false, 11428 }; 11429 } 11430 11431 /// Assumes capacity for body has already been added. Needed capacity taking into 11432 /// account fixups can be found with `countBodyLenAfterFixups`. 11433 fn appendBodyWithFixups(astgen: *AstGen, body: []const Zir.Inst.Index) void { 11434 return appendBodyWithFixupsArrayList(astgen, &astgen.extra, body); 11435 } 11436 11437 fn appendBodyWithFixupsArrayList( 11438 astgen: *AstGen, 11439 list: *std.ArrayListUnmanaged(u32), 11440 body: []const Zir.Inst.Index, 11441 ) void { 11442 for (body) |body_inst| { 11443 appendPossiblyRefdBodyInst(astgen, list, body_inst); 11444 } 11445 } 11446 11447 fn appendPossiblyRefdBodyInst( 11448 astgen: *AstGen, 11449 list: *std.ArrayListUnmanaged(u32), 11450 body_inst: Zir.Inst.Index, 11451 ) void { 11452 list.appendAssumeCapacity(body_inst); 11453 const kv = astgen.ref_table.fetchRemove(body_inst) orelse return; 11454 const ref_inst = kv.value; 11455 return appendPossiblyRefdBodyInst(astgen, list, ref_inst); 11456 } 11457 11458 fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 { 11459 var count = body.len; 11460 for (body) |body_inst| { 11461 var check_inst = body_inst; 11462 while (astgen.ref_table.get(check_inst)) |ref_inst| { 11463 count += 1; 11464 check_inst = ref_inst; 11465 } 11466 } 11467 return @intCast(u32, count); 11468 }