blob af0fac04 (449374B) - 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.addUnNode(.validate_deref, lhs, 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.addPlNode(.array_type, array_init.ast.type_expr, Zir.Inst.Bin{ 1324 .lhs = len_inst, 1325 .rhs = elem_type, 1326 }); 1327 break :inst .{ 1328 .array = array_type_inst, 1329 .elem = elem_type, 1330 }; 1331 } else { 1332 const sentinel = try comptimeExpr(gz, scope, .{ .ty = elem_type }, array_type.ast.sentinel); 1333 const array_type_inst = try gz.addPlNode( 1334 .array_type_sentinel, 1335 array_init.ast.type_expr, 1336 Zir.Inst.ArrayTypeSentinel{ 1337 .len = len_inst, 1338 .elem_type = elem_type, 1339 .sentinel = sentinel, 1340 }, 1341 ); 1342 break :inst .{ 1343 .array = array_type_inst, 1344 .elem = elem_type, 1345 }; 1346 } 1347 } 1348 } 1349 const array_type_inst = try typeExpr(gz, scope, array_init.ast.type_expr); 1350 _ = try gz.addUnNode(.validate_array_init_ty, array_type_inst, array_init.ast.type_expr); 1351 break :inst .{ 1352 .array = array_type_inst, 1353 .elem = .none, 1354 }; 1355 }; 1356 1357 switch (rl) { 1358 .discard => { 1359 // TODO elements should still be coerced if type is provided 1360 for (array_init.ast.elements) |elem_init| { 1361 _ = try expr(gz, scope, .discard, elem_init); 1362 } 1363 return Zir.Inst.Ref.void_value; 1364 }, 1365 .ref => { 1366 const tag: Zir.Inst.Tag = if (types.array != .none) .array_init_ref else .array_init_anon_ref; 1367 return arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag); 1368 }, 1369 .none => { 1370 const tag: Zir.Inst.Tag = if (types.array != .none) .array_init else .array_init_anon; 1371 return arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag); 1372 }, 1373 .ty, .coerced_ty => { 1374 const tag: Zir.Inst.Tag = if (types.array != .none) .array_init else .array_init_anon; 1375 const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag); 1376 return rvalue(gz, rl, result, node); 1377 }, 1378 .ptr => |ptr_inst| { 1379 return arrayInitExprRlPtr(gz, scope, rl, node, ptr_inst, array_init.ast.elements, types.array); 1380 }, 1381 .inferred_ptr => |ptr_inst| { 1382 if (types.array == .none) { 1383 // We treat this case differently so that we don't get a crash when 1384 // analyzing array_base_ptr against an alloc_inferred_mut. 1385 // See corresponding logic in structInitExpr. 1386 const result = try arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon); 1387 return rvalue(gz, rl, result, node); 1388 } else { 1389 return arrayInitExprRlPtr(gz, scope, rl, node, ptr_inst, array_init.ast.elements, types.array); 1390 } 1391 }, 1392 .block_ptr => |block_gz| { 1393 // This condition is here for the same reason as the above condition in `inferred_ptr`. 1394 // See corresponding logic in structInitExpr. 1395 if (types.array == .none and astgen.isInferred(block_gz.rl_ptr)) { 1396 const result = try arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon); 1397 return rvalue(gz, rl, result, node); 1398 } 1399 return arrayInitExprRlPtr(gz, scope, rl, node, block_gz.rl_ptr, array_init.ast.elements, types.array); 1400 }, 1401 } 1402 } 1403 1404 fn arrayInitExprRlNone( 1405 gz: *GenZir, 1406 scope: *Scope, 1407 node: Ast.Node.Index, 1408 elements: []const Ast.Node.Index, 1409 tag: Zir.Inst.Tag, 1410 ) InnerError!Zir.Inst.Ref { 1411 const astgen = gz.astgen; 1412 1413 const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{ 1414 .operands_len = @intCast(u32, elements.len), 1415 }); 1416 var extra_index = try reserveExtra(astgen, elements.len); 1417 1418 for (elements) |elem_init| { 1419 const elem_ref = try expr(gz, scope, .none, elem_init); 1420 astgen.extra.items[extra_index] = @enumToInt(elem_ref); 1421 extra_index += 1; 1422 } 1423 return try gz.addPlNodePayloadIndex(tag, node, payload_index); 1424 } 1425 1426 fn arrayInitExprInner( 1427 gz: *GenZir, 1428 scope: *Scope, 1429 node: Ast.Node.Index, 1430 elements: []const Ast.Node.Index, 1431 array_ty_inst: Zir.Inst.Ref, 1432 elem_ty: Zir.Inst.Ref, 1433 tag: Zir.Inst.Tag, 1434 ) InnerError!Zir.Inst.Ref { 1435 const astgen = gz.astgen; 1436 1437 const len = elements.len + @boolToInt(array_ty_inst != .none); 1438 const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{ 1439 .operands_len = @intCast(u32, len), 1440 }); 1441 var extra_index = try reserveExtra(astgen, len); 1442 if (array_ty_inst != .none) { 1443 astgen.extra.items[extra_index] = @enumToInt(array_ty_inst); 1444 extra_index += 1; 1445 } 1446 1447 for (elements) |elem_init, i| { 1448 const rl = if (elem_ty != .none) 1449 ResultLoc{ .coerced_ty = elem_ty } 1450 else if (array_ty_inst != .none and nodeMayNeedMemoryLocation(astgen.tree, elem_init, true)) rl: { 1451 const ty_expr = try gz.add(.{ 1452 .tag = .elem_type_index, 1453 .data = .{ .bin = .{ 1454 .lhs = array_ty_inst, 1455 .rhs = @intToEnum(Zir.Inst.Ref, i), 1456 } }, 1457 }); 1458 break :rl ResultLoc{ .coerced_ty = ty_expr }; 1459 } else ResultLoc{ .none = {} }; 1460 1461 const elem_ref = try expr(gz, scope, rl, elem_init); 1462 astgen.extra.items[extra_index] = @enumToInt(elem_ref); 1463 extra_index += 1; 1464 } 1465 1466 return try gz.addPlNodePayloadIndex(tag, node, payload_index); 1467 } 1468 1469 fn arrayInitExprRlPtr( 1470 gz: *GenZir, 1471 scope: *Scope, 1472 rl: ResultLoc, 1473 node: Ast.Node.Index, 1474 result_ptr: Zir.Inst.Ref, 1475 elements: []const Ast.Node.Index, 1476 array_ty: Zir.Inst.Ref, 1477 ) InnerError!Zir.Inst.Ref { 1478 if (array_ty == .none) { 1479 const base_ptr = try gz.addUnNode(.array_base_ptr, result_ptr, node); 1480 return arrayInitExprRlPtrInner(gz, scope, node, base_ptr, elements); 1481 } 1482 1483 var as_scope = try gz.makeCoercionScope(scope, array_ty, result_ptr, node); 1484 defer as_scope.unstack(); 1485 1486 const result = try arrayInitExprRlPtrInner(&as_scope, scope, node, as_scope.rl_ptr, elements); 1487 return as_scope.finishCoercion(gz, rl, node, result, array_ty); 1488 } 1489 1490 fn arrayInitExprRlPtrInner( 1491 gz: *GenZir, 1492 scope: *Scope, 1493 node: Ast.Node.Index, 1494 result_ptr: Zir.Inst.Ref, 1495 elements: []const Ast.Node.Index, 1496 ) InnerError!Zir.Inst.Ref { 1497 const astgen = gz.astgen; 1498 1499 const payload_index = try addExtra(astgen, Zir.Inst.Block{ 1500 .body_len = @intCast(u32, elements.len), 1501 }); 1502 var extra_index = try reserveExtra(astgen, elements.len); 1503 1504 for (elements) |elem_init, i| { 1505 const elem_ptr = try gz.addPlNode(.elem_ptr_imm, elem_init, Zir.Inst.ElemPtrImm{ 1506 .ptr = result_ptr, 1507 .index = @intCast(u32, i), 1508 }); 1509 astgen.extra.items[extra_index] = refToIndex(elem_ptr).?; 1510 extra_index += 1; 1511 _ = try expr(gz, scope, .{ .ptr = elem_ptr }, elem_init); 1512 } 1513 1514 const tag: Zir.Inst.Tag = if (gz.force_comptime) 1515 .validate_array_init_comptime 1516 else 1517 .validate_array_init; 1518 1519 _ = try gz.addPlNodePayloadIndex(tag, node, payload_index); 1520 return .void_value; 1521 } 1522 1523 fn structInitExpr( 1524 gz: *GenZir, 1525 scope: *Scope, 1526 rl: ResultLoc, 1527 node: Ast.Node.Index, 1528 struct_init: Ast.full.StructInit, 1529 ) InnerError!Zir.Inst.Ref { 1530 const astgen = gz.astgen; 1531 const tree = astgen.tree; 1532 1533 if (struct_init.ast.type_expr == 0) { 1534 if (struct_init.ast.fields.len == 0) { 1535 return rvalue(gz, rl, .empty_struct, node); 1536 } 1537 } else array: { 1538 const node_tags = tree.nodes.items(.tag); 1539 const main_tokens = tree.nodes.items(.main_token); 1540 const array_type: Ast.full.ArrayType = switch (node_tags[struct_init.ast.type_expr]) { 1541 .array_type => tree.arrayType(struct_init.ast.type_expr), 1542 .array_type_sentinel => tree.arrayTypeSentinel(struct_init.ast.type_expr), 1543 else => { 1544 if (struct_init.ast.fields.len == 0) { 1545 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1546 const result = try gz.addUnNode(.struct_init_empty, ty_inst, node); 1547 return rvalue(gz, rl, result, node); 1548 } 1549 break :array; 1550 }, 1551 }; 1552 const is_inferred_array_len = node_tags[array_type.ast.elem_count] == .identifier and 1553 // This intentionally does not support `@"_"` syntax. 1554 mem.eql(u8, tree.tokenSlice(main_tokens[array_type.ast.elem_count]), "_"); 1555 if (struct_init.ast.fields.len == 0) { 1556 if (is_inferred_array_len) { 1557 const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type); 1558 const array_type_inst = if (array_type.ast.sentinel == 0) blk: { 1559 break :blk try gz.addPlNode(.array_type, struct_init.ast.type_expr, Zir.Inst.Bin{ 1560 .lhs = .zero_usize, 1561 .rhs = elem_type, 1562 }); 1563 } else blk: { 1564 const sentinel = try comptimeExpr(gz, scope, .{ .ty = elem_type }, array_type.ast.sentinel); 1565 break :blk try gz.addPlNode( 1566 .array_type_sentinel, 1567 struct_init.ast.type_expr, 1568 Zir.Inst.ArrayTypeSentinel{ 1569 .len = .zero_usize, 1570 .elem_type = elem_type, 1571 .sentinel = sentinel, 1572 }, 1573 ); 1574 }; 1575 const result = try gz.addUnNode(.struct_init_empty, array_type_inst, node); 1576 return rvalue(gz, rl, result, node); 1577 } 1578 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1579 const result = try gz.addUnNode(.struct_init_empty, ty_inst, node); 1580 return rvalue(gz, rl, result, node); 1581 } else { 1582 return astgen.failNode( 1583 struct_init.ast.type_expr, 1584 "initializing array with struct syntax", 1585 .{}, 1586 ); 1587 } 1588 } 1589 1590 switch (rl) { 1591 .discard => { 1592 // TODO if a type expr is given the fields should be validated for that type 1593 if (struct_init.ast.type_expr != 0) { 1594 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1595 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); 1596 } 1597 for (struct_init.ast.fields) |field_init| { 1598 _ = try expr(gz, scope, .discard, field_init); 1599 } 1600 return Zir.Inst.Ref.void_value; 1601 }, 1602 .ref => { 1603 if (struct_init.ast.type_expr != 0) { 1604 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1605 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); 1606 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init_ref); 1607 } else { 1608 return structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon_ref); 1609 } 1610 }, 1611 .none => { 1612 if (struct_init.ast.type_expr != 0) { 1613 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1614 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); 1615 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init); 1616 } else { 1617 return structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon); 1618 } 1619 }, 1620 .ty, .coerced_ty => |ty_inst| { 1621 if (struct_init.ast.type_expr == 0) { 1622 const result = try structInitExprRlNone(gz, scope, node, struct_init, ty_inst, .struct_init_anon); 1623 return rvalue(gz, rl, result, node); 1624 } 1625 const inner_ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1626 _ = try gz.addUnNode(.validate_struct_init_ty, inner_ty_inst, node); 1627 const result = try structInitExprRlTy(gz, scope, node, struct_init, inner_ty_inst, .struct_init); 1628 return rvalue(gz, rl, result, node); 1629 }, 1630 .ptr => |ptr_inst| return structInitExprRlPtr(gz, scope, rl, node, struct_init, ptr_inst), 1631 .inferred_ptr => |ptr_inst| { 1632 if (struct_init.ast.type_expr == 0) { 1633 // We treat this case differently so that we don't get a crash when 1634 // analyzing field_base_ptr against an alloc_inferred_mut. 1635 // See corresponding logic in arrayInitExpr. 1636 const result = try structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon); 1637 return rvalue(gz, rl, result, node); 1638 } else { 1639 return structInitExprRlPtr(gz, scope, rl, node, struct_init, ptr_inst); 1640 } 1641 }, 1642 .block_ptr => |block_gz| { 1643 // This condition is here for the same reason as the above condition in `inferred_ptr`. 1644 // See corresponding logic in arrayInitExpr. 1645 if (struct_init.ast.type_expr == 0 and astgen.isInferred(block_gz.rl_ptr)) { 1646 const result = try structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon); 1647 return rvalue(gz, rl, result, node); 1648 } 1649 1650 return structInitExprRlPtr(gz, scope, rl, node, struct_init, block_gz.rl_ptr); 1651 }, 1652 } 1653 } 1654 1655 fn structInitExprRlNone( 1656 gz: *GenZir, 1657 scope: *Scope, 1658 node: Ast.Node.Index, 1659 struct_init: Ast.full.StructInit, 1660 ty_inst: Zir.Inst.Ref, 1661 tag: Zir.Inst.Tag, 1662 ) InnerError!Zir.Inst.Ref { 1663 const astgen = gz.astgen; 1664 const tree = astgen.tree; 1665 1666 const payload_index = try addExtra(astgen, Zir.Inst.StructInitAnon{ 1667 .fields_len = @intCast(u32, struct_init.ast.fields.len), 1668 }); 1669 const field_size = @typeInfo(Zir.Inst.StructInitAnon.Item).Struct.fields.len; 1670 var extra_index: usize = try reserveExtra(astgen, struct_init.ast.fields.len * field_size); 1671 1672 for (struct_init.ast.fields) |field_init| { 1673 const name_token = tree.firstToken(field_init) - 2; 1674 const str_index = try astgen.identAsString(name_token); 1675 const sub_rl: ResultLoc = if (ty_inst != .none) 1676 ResultLoc{ .ty = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{ 1677 .container_type = ty_inst, 1678 .name_start = str_index, 1679 }) } 1680 else 1681 .none; 1682 setExtra(astgen, extra_index, Zir.Inst.StructInitAnon.Item{ 1683 .field_name = str_index, 1684 .init = try expr(gz, scope, sub_rl, field_init), 1685 }); 1686 extra_index += field_size; 1687 } 1688 1689 return try gz.addPlNodePayloadIndex(tag, node, payload_index); 1690 } 1691 1692 fn structInitExprRlPtr( 1693 gz: *GenZir, 1694 scope: *Scope, 1695 rl: ResultLoc, 1696 node: Ast.Node.Index, 1697 struct_init: Ast.full.StructInit, 1698 result_ptr: Zir.Inst.Ref, 1699 ) InnerError!Zir.Inst.Ref { 1700 if (struct_init.ast.type_expr == 0) { 1701 const base_ptr = try gz.addUnNode(.field_base_ptr, result_ptr, node); 1702 return structInitExprRlPtrInner(gz, scope, node, struct_init, base_ptr); 1703 } 1704 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1705 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); 1706 1707 var as_scope = try gz.makeCoercionScope(scope, ty_inst, result_ptr, node); 1708 defer as_scope.unstack(); 1709 1710 const result = try structInitExprRlPtrInner(&as_scope, scope, node, struct_init, as_scope.rl_ptr); 1711 return as_scope.finishCoercion(gz, rl, node, result, ty_inst); 1712 } 1713 1714 fn structInitExprRlPtrInner( 1715 gz: *GenZir, 1716 scope: *Scope, 1717 node: Ast.Node.Index, 1718 struct_init: Ast.full.StructInit, 1719 result_ptr: Zir.Inst.Ref, 1720 ) InnerError!Zir.Inst.Ref { 1721 const astgen = gz.astgen; 1722 const tree = astgen.tree; 1723 1724 const payload_index = try addExtra(astgen, Zir.Inst.Block{ 1725 .body_len = @intCast(u32, struct_init.ast.fields.len), 1726 }); 1727 var extra_index = try reserveExtra(astgen, struct_init.ast.fields.len); 1728 1729 for (struct_init.ast.fields) |field_init| { 1730 const name_token = tree.firstToken(field_init) - 2; 1731 const str_index = try astgen.identAsString(name_token); 1732 const field_ptr = try gz.addPlNode(.field_ptr, field_init, Zir.Inst.Field{ 1733 .lhs = result_ptr, 1734 .field_name_start = str_index, 1735 }); 1736 astgen.extra.items[extra_index] = refToIndex(field_ptr).?; 1737 extra_index += 1; 1738 _ = try expr(gz, scope, .{ .ptr = field_ptr }, field_init); 1739 } 1740 1741 const tag: Zir.Inst.Tag = if (gz.force_comptime) 1742 .validate_struct_init_comptime 1743 else 1744 .validate_struct_init; 1745 1746 _ = try gz.addPlNodePayloadIndex(tag, node, payload_index); 1747 return Zir.Inst.Ref.void_value; 1748 } 1749 1750 fn structInitExprRlTy( 1751 gz: *GenZir, 1752 scope: *Scope, 1753 node: Ast.Node.Index, 1754 struct_init: Ast.full.StructInit, 1755 ty_inst: Zir.Inst.Ref, 1756 tag: Zir.Inst.Tag, 1757 ) InnerError!Zir.Inst.Ref { 1758 const astgen = gz.astgen; 1759 const tree = astgen.tree; 1760 1761 const payload_index = try addExtra(astgen, Zir.Inst.StructInit{ 1762 .fields_len = @intCast(u32, struct_init.ast.fields.len), 1763 }); 1764 const field_size = @typeInfo(Zir.Inst.StructInit.Item).Struct.fields.len; 1765 var extra_index: usize = try reserveExtra(astgen, struct_init.ast.fields.len * field_size); 1766 1767 for (struct_init.ast.fields) |field_init| { 1768 const name_token = tree.firstToken(field_init) - 2; 1769 const str_index = try astgen.identAsString(name_token); 1770 const field_ty_inst = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{ 1771 .container_type = ty_inst, 1772 .name_start = str_index, 1773 }); 1774 setExtra(astgen, extra_index, Zir.Inst.StructInit.Item{ 1775 .field_type = refToIndex(field_ty_inst).?, 1776 .init = try expr(gz, scope, .{ .ty = field_ty_inst }, field_init), 1777 }); 1778 extra_index += field_size; 1779 } 1780 1781 return try gz.addPlNodePayloadIndex(tag, node, payload_index); 1782 } 1783 1784 /// This calls expr in a comptime scope, and is intended to be called as a helper function. 1785 /// The one that corresponds to `comptime` expression syntax is `comptimeExprAst`. 1786 fn comptimeExpr( 1787 gz: *GenZir, 1788 scope: *Scope, 1789 rl: ResultLoc, 1790 node: Ast.Node.Index, 1791 ) InnerError!Zir.Inst.Ref { 1792 const prev_force_comptime = gz.force_comptime; 1793 gz.force_comptime = true; 1794 defer gz.force_comptime = prev_force_comptime; 1795 1796 return expr(gz, scope, rl, node); 1797 } 1798 1799 /// This one is for an actual `comptime` syntax, and will emit a compile error if 1800 /// the scope already has `force_comptime=true`. 1801 /// See `comptimeExpr` for the helper function for calling expr in a comptime scope. 1802 fn comptimeExprAst( 1803 gz: *GenZir, 1804 scope: *Scope, 1805 rl: ResultLoc, 1806 node: Ast.Node.Index, 1807 ) InnerError!Zir.Inst.Ref { 1808 const astgen = gz.astgen; 1809 if (gz.force_comptime) { 1810 return astgen.failNode(node, "redundant comptime keyword in already comptime scope", .{}); 1811 } 1812 const tree = astgen.tree; 1813 const node_datas = tree.nodes.items(.data); 1814 const body_node = node_datas[node].lhs; 1815 gz.force_comptime = true; 1816 const result = try expr(gz, scope, rl, body_node); 1817 gz.force_comptime = false; 1818 return result; 1819 } 1820 1821 fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 1822 const astgen = parent_gz.astgen; 1823 const tree = astgen.tree; 1824 const node_datas = tree.nodes.items(.data); 1825 const break_label = node_datas[node].lhs; 1826 const rhs = node_datas[node].rhs; 1827 1828 // Look for the label in the scope. 1829 var scope = parent_scope; 1830 while (true) { 1831 switch (scope.tag) { 1832 .gen_zir => { 1833 const block_gz = scope.cast(GenZir).?; 1834 1835 const block_inst = blk: { 1836 if (break_label != 0) { 1837 if (block_gz.label) |*label| { 1838 if (try astgen.tokenIdentEql(label.token, break_label)) { 1839 label.used = true; 1840 break :blk label.block_inst; 1841 } 1842 } 1843 } else if (block_gz.break_block != 0) { 1844 break :blk block_gz.break_block; 1845 } 1846 scope = block_gz.parent; 1847 continue; 1848 }; 1849 1850 const break_tag: Zir.Inst.Tag = if (block_gz.is_inline or block_gz.force_comptime) 1851 .break_inline 1852 else 1853 .@"break"; 1854 1855 if (rhs == 0) { 1856 try genDefers(parent_gz, scope, parent_scope, .normal_only); 1857 1858 _ = try parent_gz.addBreak(break_tag, block_inst, .void_value); 1859 return Zir.Inst.Ref.unreachable_value; 1860 } 1861 block_gz.break_count += 1; 1862 1863 // The loop scope has a mechanism to prevent rvalue() from emitting a 1864 // store to the result location for the loop body (since it is continues 1865 // rather than returning a result from the loop) but here is a `break` 1866 // which needs to override this behavior. 1867 const prev_rvalue_noresult = parent_gz.rvalue_noresult; 1868 parent_gz.rvalue_noresult = .none; 1869 const operand = try reachableExpr(parent_gz, parent_scope, block_gz.break_result_loc, rhs, node); 1870 const search_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 1871 parent_gz.rvalue_noresult = prev_rvalue_noresult; 1872 1873 try genDefers(parent_gz, scope, parent_scope, .normal_only); 1874 1875 switch (block_gz.break_result_loc) { 1876 .block_ptr => { 1877 const br = try parent_gz.addBreak(break_tag, block_inst, operand); 1878 try block_gz.labeled_breaks.append(astgen.gpa, .{ .br = br, .search = search_index }); 1879 }, 1880 .ptr => { 1881 // In this case we don't have any mechanism to intercept it; 1882 // we assume the result location is written, and we break with void. 1883 _ = try parent_gz.addBreak(break_tag, block_inst, .void_value); 1884 }, 1885 .discard => { 1886 _ = try parent_gz.addBreak(break_tag, block_inst, .void_value); 1887 }, 1888 else => { 1889 _ = try parent_gz.addBreak(break_tag, block_inst, operand); 1890 }, 1891 } 1892 return Zir.Inst.Ref.unreachable_value; 1893 }, 1894 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 1895 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 1896 .namespace => break, 1897 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, 1898 .top => unreachable, 1899 } 1900 } 1901 if (break_label != 0) { 1902 const label_name = try astgen.identifierTokenString(break_label); 1903 return astgen.failTok(break_label, "label not found: '{s}'", .{label_name}); 1904 } else { 1905 return astgen.failNode(node, "break expression outside loop", .{}); 1906 } 1907 } 1908 1909 fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 1910 const astgen = parent_gz.astgen; 1911 const tree = astgen.tree; 1912 const node_datas = tree.nodes.items(.data); 1913 const break_label = node_datas[node].lhs; 1914 1915 // Look for the label in the scope. 1916 var scope = parent_scope; 1917 while (true) { 1918 switch (scope.tag) { 1919 .gen_zir => { 1920 const gen_zir = scope.cast(GenZir).?; 1921 const continue_block = gen_zir.continue_block; 1922 if (continue_block == 0) { 1923 scope = gen_zir.parent; 1924 continue; 1925 } 1926 if (break_label != 0) blk: { 1927 if (gen_zir.label) |*label| { 1928 if (try astgen.tokenIdentEql(label.token, break_label)) { 1929 label.used = true; 1930 break :blk; 1931 } 1932 } 1933 // found continue but either it has a different label, or no label 1934 scope = gen_zir.parent; 1935 continue; 1936 } 1937 1938 const break_tag: Zir.Inst.Tag = if (gen_zir.is_inline or gen_zir.force_comptime) 1939 .break_inline 1940 else 1941 .@"break"; 1942 _ = try parent_gz.addBreak(break_tag, continue_block, .void_value); 1943 return Zir.Inst.Ref.unreachable_value; 1944 }, 1945 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 1946 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 1947 .defer_normal => { 1948 const defer_scope = scope.cast(Scope.Defer).?; 1949 scope = defer_scope.parent; 1950 const expr_node = node_datas[defer_scope.defer_node].rhs; 1951 try unusedResultDeferExpr(parent_gz, defer_scope, defer_scope.parent, expr_node); 1952 }, 1953 .defer_error => scope = scope.cast(Scope.Defer).?.parent, 1954 .namespace => break, 1955 .top => unreachable, 1956 } 1957 } 1958 if (break_label != 0) { 1959 const label_name = try astgen.identifierTokenString(break_label); 1960 return astgen.failTok(break_label, "label not found: '{s}'", .{label_name}); 1961 } else { 1962 return astgen.failNode(node, "continue expression outside loop", .{}); 1963 } 1964 } 1965 1966 fn blockExpr( 1967 gz: *GenZir, 1968 scope: *Scope, 1969 rl: ResultLoc, 1970 block_node: Ast.Node.Index, 1971 statements: []const Ast.Node.Index, 1972 ) InnerError!Zir.Inst.Ref { 1973 const tracy = trace(@src()); 1974 defer tracy.end(); 1975 1976 const astgen = gz.astgen; 1977 const tree = astgen.tree; 1978 const main_tokens = tree.nodes.items(.main_token); 1979 const token_tags = tree.tokens.items(.tag); 1980 1981 const lbrace = main_tokens[block_node]; 1982 if (token_tags[lbrace - 1] == .colon and 1983 token_tags[lbrace - 2] == .identifier) 1984 { 1985 return labeledBlockExpr(gz, scope, rl, block_node, statements); 1986 } 1987 1988 try blockExprStmts(gz, scope, statements); 1989 return rvalue(gz, rl, .void_value, block_node); 1990 } 1991 1992 fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: Ast.TokenIndex) !void { 1993 // Look for the label in the scope. 1994 var scope = parent_scope; 1995 while (true) { 1996 switch (scope.tag) { 1997 .gen_zir => { 1998 const gen_zir = scope.cast(GenZir).?; 1999 if (gen_zir.label) |prev_label| { 2000 if (try astgen.tokenIdentEql(label, prev_label.token)) { 2001 const label_name = try astgen.identifierTokenString(label); 2002 return astgen.failTokNotes(label, "redefinition of label '{s}'", .{ 2003 label_name, 2004 }, &[_]u32{ 2005 try astgen.errNoteTok( 2006 prev_label.token, 2007 "previous definition here", 2008 .{}, 2009 ), 2010 }); 2011 } 2012 } 2013 scope = gen_zir.parent; 2014 }, 2015 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 2016 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 2017 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, 2018 .namespace => break, 2019 .top => unreachable, 2020 } 2021 } 2022 } 2023 2024 fn labeledBlockExpr( 2025 gz: *GenZir, 2026 parent_scope: *Scope, 2027 rl: ResultLoc, 2028 block_node: Ast.Node.Index, 2029 statements: []const Ast.Node.Index, 2030 ) InnerError!Zir.Inst.Ref { 2031 const tracy = trace(@src()); 2032 defer tracy.end(); 2033 2034 const astgen = gz.astgen; 2035 const tree = astgen.tree; 2036 const main_tokens = tree.nodes.items(.main_token); 2037 const token_tags = tree.tokens.items(.tag); 2038 2039 const lbrace = main_tokens[block_node]; 2040 const label_token = lbrace - 2; 2041 assert(token_tags[label_token] == .identifier); 2042 2043 try astgen.checkLabelRedefinition(parent_scope, label_token); 2044 2045 // Reserve the Block ZIR instruction index so that we can put it into the GenZir struct 2046 // so that break statements can reference it. 2047 const block_tag: Zir.Inst.Tag = if (gz.force_comptime) .block_inline else .block; 2048 const block_inst = try gz.makeBlockInst(block_tag, block_node); 2049 try gz.instructions.append(astgen.gpa, block_inst); 2050 2051 var block_scope = gz.makeSubBlock(parent_scope); 2052 block_scope.label = GenZir.Label{ 2053 .token = label_token, 2054 .block_inst = block_inst, 2055 }; 2056 block_scope.setBreakResultLoc(rl); 2057 defer block_scope.unstack(); 2058 defer block_scope.labeled_breaks.deinit(astgen.gpa); 2059 2060 try blockExprStmts(&block_scope, &block_scope.base, statements); 2061 if (!block_scope.endsWithNoReturn()) { 2062 const break_tag: Zir.Inst.Tag = if (block_scope.force_comptime) .break_inline else .@"break"; 2063 _ = try block_scope.addBreak(break_tag, block_inst, .void_value); 2064 } 2065 2066 if (!block_scope.label.?.used) { 2067 try astgen.appendErrorTok(label_token, "unused block label", .{}); 2068 } 2069 2070 const zir_datas = gz.astgen.instructions.items(.data); 2071 const zir_tags = gz.astgen.instructions.items(.tag); 2072 const strat = rl.strategy(&block_scope); 2073 switch (strat.tag) { 2074 .break_void => { 2075 // The code took advantage of the result location as a pointer. 2076 // Turn the break instruction operands into void. 2077 for (block_scope.labeled_breaks.items) |br| { 2078 zir_datas[br.br].@"break".operand = .void_value; 2079 } 2080 try block_scope.setBlockBody(block_inst); 2081 2082 return indexToRef(block_inst); 2083 }, 2084 .break_operand => { 2085 // All break operands are values that did not use the result location pointer. 2086 // The break instructions need to have their operands coerced if the 2087 // block's result location is a `ty`. In this case we overwrite the 2088 // `store_to_block_ptr` instruction with an `as` instruction and repurpose 2089 // it as the break operand. 2090 // This corresponds to similar code in `setCondBrPayloadElideBlockStorePtr`. 2091 if (block_scope.rl_ty_inst != .none) { 2092 for (block_scope.labeled_breaks.items) |br| { 2093 // We expect the `store_to_block_ptr` to be created between 1-3 instructions 2094 // prior to the break. 2095 var search_index = br.search -| 3; 2096 while (search_index < br.search) : (search_index += 1) { 2097 if (zir_tags[search_index] == .store_to_block_ptr and 2098 zir_datas[search_index].bin.lhs == block_scope.rl_ptr) 2099 { 2100 zir_tags[search_index] = .as; 2101 zir_datas[search_index].bin = .{ 2102 .lhs = block_scope.rl_ty_inst, 2103 .rhs = zir_datas[br.br].@"break".operand, 2104 }; 2105 zir_datas[br.br].@"break".operand = indexToRef(search_index); 2106 break; 2107 } 2108 } else unreachable; 2109 } 2110 } 2111 try block_scope.setBlockBody(block_inst); 2112 const block_ref = indexToRef(block_inst); 2113 switch (rl) { 2114 .ref => return block_ref, 2115 else => return rvalue(gz, rl, block_ref, block_node), 2116 } 2117 }, 2118 } 2119 } 2120 2121 fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Node.Index) !void { 2122 const astgen = gz.astgen; 2123 const tree = astgen.tree; 2124 const node_tags = tree.nodes.items(.tag); 2125 2126 if (statements.len == 0) return; 2127 2128 try gz.addDbgBlockBegin(); 2129 2130 var block_arena = std.heap.ArenaAllocator.init(gz.astgen.gpa); 2131 defer block_arena.deinit(); 2132 const block_arena_allocator = block_arena.allocator(); 2133 2134 var noreturn_src_node: Ast.Node.Index = 0; 2135 var scope = parent_scope; 2136 for (statements) |statement| { 2137 if (noreturn_src_node != 0) { 2138 try astgen.appendErrorNodeNotes( 2139 statement, 2140 "unreachable code", 2141 .{}, 2142 &[_]u32{ 2143 try astgen.errNoteNode( 2144 noreturn_src_node, 2145 "control flow is diverted here", 2146 .{}, 2147 ), 2148 }, 2149 ); 2150 } 2151 switch (node_tags[statement]) { 2152 // zig fmt: off 2153 .global_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.globalVarDecl(statement)), 2154 .local_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.localVarDecl(statement)), 2155 .simple_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.simpleVarDecl(statement)), 2156 .aligned_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.alignedVarDecl(statement)), 2157 2158 .@"defer" => scope = try makeDeferScope(gz.astgen, scope, statement, block_arena_allocator, .defer_normal), 2159 .@"errdefer" => scope = try makeDeferScope(gz.astgen, scope, statement, block_arena_allocator, .defer_error), 2160 2161 .assign => try assign(gz, scope, statement), 2162 2163 .assign_shl => try assignShift(gz, scope, statement, .shl), 2164 .assign_shr => try assignShift(gz, scope, statement, .shr), 2165 2166 .assign_bit_and => try assignOp(gz, scope, statement, .bit_and), 2167 .assign_bit_or => try assignOp(gz, scope, statement, .bit_or), 2168 .assign_bit_xor => try assignOp(gz, scope, statement, .xor), 2169 .assign_div => try assignOp(gz, scope, statement, .div), 2170 .assign_sub => try assignOp(gz, scope, statement, .sub), 2171 .assign_sub_wrap => try assignOp(gz, scope, statement, .subwrap), 2172 .assign_mod => try assignOp(gz, scope, statement, .mod_rem), 2173 .assign_add => try assignOp(gz, scope, statement, .add), 2174 .assign_add_wrap => try assignOp(gz, scope, statement, .addwrap), 2175 .assign_mul => try assignOp(gz, scope, statement, .mul), 2176 .assign_mul_wrap => try assignOp(gz, scope, statement, .mulwrap), 2177 2178 else => noreturn_src_node = try unusedResultExpr(gz, scope, statement), 2179 // zig fmt: on 2180 } 2181 } 2182 2183 try gz.addDbgBlockEnd(); 2184 2185 try genDefers(gz, parent_scope, scope, .normal_only); 2186 try checkUsed(gz, parent_scope, scope); 2187 } 2188 2189 fn unusedResultDeferExpr(gz: *GenZir, defer_scope: *Scope.Defer, expr_scope: *Scope, expr_node: Ast.Node.Index) InnerError!void { 2190 const astgen = gz.astgen; 2191 const prev_offset = astgen.source_offset; 2192 const prev_line = astgen.source_line; 2193 const prev_column = astgen.source_column; 2194 defer { 2195 astgen.source_offset = prev_offset; 2196 astgen.source_line = prev_line; 2197 astgen.source_column = prev_column; 2198 } 2199 astgen.source_offset = defer_scope.source_offset; 2200 astgen.source_line = defer_scope.source_line; 2201 astgen.source_column = defer_scope.source_column; 2202 _ = try unusedResultExpr(gz, expr_scope, expr_node); 2203 } 2204 2205 /// Returns AST source node of the thing that is noreturn if the statement is 2206 /// definitely `noreturn`. Otherwise returns 0. 2207 fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) InnerError!Ast.Node.Index { 2208 try emitDbgNode(gz, statement); 2209 // We need to emit an error if the result is not `noreturn` or `void`, but 2210 // we want to avoid adding the ZIR instruction if possible for performance. 2211 const maybe_unused_result = try expr(gz, scope, .none, statement); 2212 var noreturn_src_node: Ast.Node.Index = 0; 2213 const elide_check = if (refToIndex(maybe_unused_result)) |inst| b: { 2214 // Note that this array becomes invalid after appending more items to it 2215 // in the above while loop. 2216 const zir_tags = gz.astgen.instructions.items(.tag); 2217 switch (zir_tags[inst]) { 2218 // For some instructions, modify the zir data 2219 // so we can avoid a separate ensure_result_used instruction. 2220 .call => { 2221 const extra_index = gz.astgen.instructions.items(.data)[inst].pl_node.payload_index; 2222 const slot = &gz.astgen.extra.items[extra_index]; 2223 var flags = @bitCast(Zir.Inst.Call.Flags, slot.*); 2224 flags.ensure_result_used = true; 2225 slot.* = @bitCast(u32, flags); 2226 break :b true; 2227 }, 2228 .builtin_call => { 2229 const extra_index = gz.astgen.instructions.items(.data)[inst].pl_node.payload_index; 2230 const slot = &gz.astgen.extra.items[extra_index]; 2231 var flags = @bitCast(Zir.Inst.BuiltinCall.Flags, slot.*); 2232 flags.ensure_result_used = true; 2233 slot.* = @bitCast(u32, flags); 2234 break :b true; 2235 }, 2236 2237 // ZIR instructions that might be a type other than `noreturn` or `void`. 2238 .add, 2239 .addwrap, 2240 .add_sat, 2241 .param, 2242 .param_comptime, 2243 .param_anytype, 2244 .param_anytype_comptime, 2245 .alloc, 2246 .alloc_mut, 2247 .alloc_comptime_mut, 2248 .alloc_inferred, 2249 .alloc_inferred_mut, 2250 .alloc_inferred_comptime, 2251 .alloc_inferred_comptime_mut, 2252 .make_ptr_const, 2253 .array_cat, 2254 .array_mul, 2255 .array_type, 2256 .array_type_sentinel, 2257 .elem_type_index, 2258 .vector_type, 2259 .indexable_ptr_len, 2260 .anyframe_type, 2261 .as, 2262 .as_node, 2263 .bit_and, 2264 .bitcast, 2265 .bit_or, 2266 .block, 2267 .block_inline, 2268 .suspend_block, 2269 .loop, 2270 .bool_br_and, 2271 .bool_br_or, 2272 .bool_not, 2273 .cmp_lt, 2274 .cmp_lte, 2275 .cmp_eq, 2276 .cmp_gte, 2277 .cmp_gt, 2278 .cmp_neq, 2279 .coerce_result_ptr, 2280 .decl_ref, 2281 .decl_val, 2282 .load, 2283 .div, 2284 .elem_ptr, 2285 .elem_val, 2286 .elem_ptr_node, 2287 .elem_ptr_imm, 2288 .elem_val_node, 2289 .field_ptr, 2290 .field_val, 2291 .field_call_bind, 2292 .field_ptr_named, 2293 .field_val_named, 2294 .func, 2295 .func_inferred, 2296 .func_fancy, 2297 .int, 2298 .int_big, 2299 .float, 2300 .float128, 2301 .int_type, 2302 .is_non_null, 2303 .is_non_null_ptr, 2304 .is_non_err, 2305 .is_non_err_ptr, 2306 .mod_rem, 2307 .mul, 2308 .mulwrap, 2309 .mul_sat, 2310 .ref, 2311 .shl, 2312 .shl_sat, 2313 .shr, 2314 .str, 2315 .sub, 2316 .subwrap, 2317 .sub_sat, 2318 .negate, 2319 .negate_wrap, 2320 .typeof, 2321 .typeof_builtin, 2322 .xor, 2323 .optional_type, 2324 .optional_payload_safe, 2325 .optional_payload_unsafe, 2326 .optional_payload_safe_ptr, 2327 .optional_payload_unsafe_ptr, 2328 .err_union_payload_safe, 2329 .err_union_payload_unsafe, 2330 .err_union_payload_safe_ptr, 2331 .err_union_payload_unsafe_ptr, 2332 .err_union_code, 2333 .err_union_code_ptr, 2334 .ptr_type, 2335 .overflow_arithmetic_ptr, 2336 .enum_literal, 2337 .merge_error_sets, 2338 .error_union_type, 2339 .bit_not, 2340 .error_value, 2341 .slice_start, 2342 .slice_end, 2343 .slice_sentinel, 2344 .import, 2345 .switch_block, 2346 .switch_cond, 2347 .switch_cond_ref, 2348 .switch_capture, 2349 .switch_capture_ref, 2350 .switch_capture_multi, 2351 .switch_capture_multi_ref, 2352 .struct_init_empty, 2353 .struct_init, 2354 .struct_init_ref, 2355 .struct_init_anon, 2356 .struct_init_anon_ref, 2357 .array_init, 2358 .array_init_anon, 2359 .array_init_ref, 2360 .array_init_anon_ref, 2361 .union_init, 2362 .field_type, 2363 .field_type_ref, 2364 .error_set_decl, 2365 .error_set_decl_anon, 2366 .error_set_decl_func, 2367 .int_to_enum, 2368 .enum_to_int, 2369 .type_info, 2370 .size_of, 2371 .bit_size_of, 2372 .log2_int_type, 2373 .typeof_log2_int_type, 2374 .ptr_to_int, 2375 .align_of, 2376 .bool_to_int, 2377 .embed_file, 2378 .error_name, 2379 .sqrt, 2380 .sin, 2381 .cos, 2382 .tan, 2383 .exp, 2384 .exp2, 2385 .log, 2386 .log2, 2387 .log10, 2388 .fabs, 2389 .floor, 2390 .ceil, 2391 .trunc, 2392 .round, 2393 .tag_name, 2394 .reify, 2395 .type_name, 2396 .frame_type, 2397 .frame_size, 2398 .float_to_int, 2399 .int_to_float, 2400 .int_to_ptr, 2401 .float_cast, 2402 .int_cast, 2403 .ptr_cast, 2404 .truncate, 2405 .align_cast, 2406 .has_decl, 2407 .has_field, 2408 .clz, 2409 .ctz, 2410 .pop_count, 2411 .byte_swap, 2412 .bit_reverse, 2413 .div_exact, 2414 .div_floor, 2415 .div_trunc, 2416 .mod, 2417 .rem, 2418 .shl_exact, 2419 .shr_exact, 2420 .bit_offset_of, 2421 .offset_of, 2422 .cmpxchg_strong, 2423 .cmpxchg_weak, 2424 .splat, 2425 .reduce, 2426 .shuffle, 2427 .atomic_load, 2428 .atomic_rmw, 2429 .mul_add, 2430 .field_parent_ptr, 2431 .maximum, 2432 .minimum, 2433 .builtin_async_call, 2434 .c_import, 2435 .@"resume", 2436 .@"await", 2437 .ret_err_value_code, 2438 .closure_get, 2439 .array_base_ptr, 2440 .field_base_ptr, 2441 .param_type, 2442 .ret_ptr, 2443 .ret_type, 2444 .@"try", 2445 .try_ptr, 2446 //.try_inline, 2447 //.try_ptr_inline, 2448 => break :b false, 2449 2450 .extended => switch (gz.astgen.instructions.items(.data)[inst].extended.opcode) { 2451 .breakpoint, 2452 .fence, 2453 .set_align_stack, 2454 .set_float_mode, 2455 => break :b true, 2456 else => break :b false, 2457 }, 2458 2459 // ZIR instructions that are always `noreturn`. 2460 .@"break", 2461 .break_inline, 2462 .condbr, 2463 .condbr_inline, 2464 .compile_error, 2465 .ret_node, 2466 .ret_load, 2467 .ret_tok, 2468 .ret_err_value, 2469 .@"unreachable", 2470 .repeat, 2471 .repeat_inline, 2472 .panic, 2473 .panic_comptime, 2474 => { 2475 noreturn_src_node = statement; 2476 break :b true; 2477 }, 2478 2479 // ZIR instructions that are always `void`. 2480 .dbg_stmt, 2481 .dbg_var_ptr, 2482 .dbg_var_val, 2483 .dbg_block_begin, 2484 .dbg_block_end, 2485 .ensure_result_used, 2486 .ensure_result_non_error, 2487 .@"export", 2488 .export_value, 2489 .set_eval_branch_quota, 2490 .ensure_err_payload_void, 2491 .atomic_store, 2492 .store, 2493 .store_node, 2494 .store_to_block_ptr, 2495 .store_to_inferred_ptr, 2496 .resolve_inferred_alloc, 2497 .validate_struct_init, 2498 .validate_struct_init_comptime, 2499 .validate_array_init, 2500 .validate_array_init_comptime, 2501 .set_cold, 2502 .set_runtime_safety, 2503 .closure_capture, 2504 .memcpy, 2505 .memset, 2506 .validate_array_init_ty, 2507 .validate_struct_init_ty, 2508 .validate_deref, 2509 => break :b true, 2510 } 2511 } else switch (maybe_unused_result) { 2512 .none => unreachable, 2513 2514 .unreachable_value => b: { 2515 noreturn_src_node = statement; 2516 break :b true; 2517 }, 2518 2519 .void_value => true, 2520 2521 else => false, 2522 }; 2523 if (!elide_check) { 2524 _ = try gz.addUnNode(.ensure_result_used, maybe_unused_result, statement); 2525 } 2526 return noreturn_src_node; 2527 } 2528 2529 fn countDefers(astgen: *AstGen, outer_scope: *Scope, inner_scope: *Scope) struct { 2530 have_any: bool, 2531 have_normal: bool, 2532 have_err: bool, 2533 need_err_code: bool, 2534 } { 2535 const tree = astgen.tree; 2536 const node_datas = tree.nodes.items(.data); 2537 2538 var have_normal = false; 2539 var have_err = false; 2540 var need_err_code = false; 2541 var scope = inner_scope; 2542 while (scope != outer_scope) { 2543 switch (scope.tag) { 2544 .gen_zir => scope = scope.cast(GenZir).?.parent, 2545 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 2546 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 2547 .defer_normal => { 2548 const defer_scope = scope.cast(Scope.Defer).?; 2549 scope = defer_scope.parent; 2550 2551 have_normal = true; 2552 }, 2553 .defer_error => { 2554 const defer_scope = scope.cast(Scope.Defer).?; 2555 scope = defer_scope.parent; 2556 2557 have_err = true; 2558 2559 const have_err_payload = node_datas[defer_scope.defer_node].lhs != 0; 2560 need_err_code = need_err_code or have_err_payload; 2561 }, 2562 .namespace => unreachable, 2563 .top => unreachable, 2564 } 2565 } 2566 return .{ 2567 .have_any = have_normal or have_err, 2568 .have_normal = have_normal, 2569 .have_err = have_err, 2570 .need_err_code = need_err_code, 2571 }; 2572 } 2573 2574 const DefersToEmit = union(enum) { 2575 both: Zir.Inst.Ref, // err code 2576 both_sans_err, 2577 normal_only, 2578 }; 2579 2580 fn genDefers( 2581 gz: *GenZir, 2582 outer_scope: *Scope, 2583 inner_scope: *Scope, 2584 which_ones: DefersToEmit, 2585 ) InnerError!void { 2586 const astgen = gz.astgen; 2587 const tree = astgen.tree; 2588 const node_datas = tree.nodes.items(.data); 2589 2590 var scope = inner_scope; 2591 while (scope != outer_scope) { 2592 switch (scope.tag) { 2593 .gen_zir => scope = scope.cast(GenZir).?.parent, 2594 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 2595 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 2596 .defer_normal => { 2597 const defer_scope = scope.cast(Scope.Defer).?; 2598 scope = defer_scope.parent; 2599 const expr_node = node_datas[defer_scope.defer_node].rhs; 2600 const prev_in_defer = gz.in_defer; 2601 gz.in_defer = true; 2602 defer gz.in_defer = prev_in_defer; 2603 try unusedResultDeferExpr(gz, defer_scope, defer_scope.parent, expr_node); 2604 }, 2605 .defer_error => { 2606 const defer_scope = scope.cast(Scope.Defer).?; 2607 scope = defer_scope.parent; 2608 switch (which_ones) { 2609 .both_sans_err => { 2610 const expr_node = node_datas[defer_scope.defer_node].rhs; 2611 const prev_in_defer = gz.in_defer; 2612 gz.in_defer = true; 2613 defer gz.in_defer = prev_in_defer; 2614 try unusedResultDeferExpr(gz, defer_scope, defer_scope.parent, expr_node); 2615 }, 2616 .both => |err_code| { 2617 const expr_node = node_datas[defer_scope.defer_node].rhs; 2618 const payload_token = node_datas[defer_scope.defer_node].lhs; 2619 const prev_in_defer = gz.in_defer; 2620 gz.in_defer = true; 2621 defer gz.in_defer = prev_in_defer; 2622 var local_val_scope: Scope.LocalVal = undefined; 2623 try gz.addDbgBlockBegin(); 2624 const sub_scope = if (payload_token == 0) defer_scope.parent else blk: { 2625 const ident_name = try astgen.identAsString(payload_token); 2626 local_val_scope = .{ 2627 .parent = defer_scope.parent, 2628 .gen_zir = gz, 2629 .name = ident_name, 2630 .inst = err_code, 2631 .token_src = payload_token, 2632 .id_cat = .@"capture", 2633 }; 2634 try gz.addDbgVar(.dbg_var_val, ident_name, err_code); 2635 break :blk &local_val_scope.base; 2636 }; 2637 try unusedResultDeferExpr(gz, defer_scope, sub_scope, expr_node); 2638 try gz.addDbgBlockEnd(); 2639 }, 2640 .normal_only => continue, 2641 } 2642 }, 2643 .namespace => unreachable, 2644 .top => unreachable, 2645 } 2646 } 2647 } 2648 2649 fn checkUsed( 2650 gz: *GenZir, 2651 outer_scope: *Scope, 2652 inner_scope: *Scope, 2653 ) InnerError!void { 2654 const astgen = gz.astgen; 2655 2656 var scope = inner_scope; 2657 while (scope != outer_scope) { 2658 switch (scope.tag) { 2659 .gen_zir => scope = scope.cast(GenZir).?.parent, 2660 .local_val => { 2661 const s = scope.cast(Scope.LocalVal).?; 2662 if (!s.used) { 2663 try astgen.appendErrorTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)}); 2664 } 2665 scope = s.parent; 2666 }, 2667 .local_ptr => { 2668 const s = scope.cast(Scope.LocalPtr).?; 2669 if (!s.used) { 2670 try astgen.appendErrorTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)}); 2671 } 2672 scope = s.parent; 2673 }, 2674 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, 2675 .namespace => unreachable, 2676 .top => unreachable, 2677 } 2678 } 2679 } 2680 2681 fn makeDeferScope( 2682 astgen: *AstGen, 2683 scope: *Scope, 2684 node: Ast.Node.Index, 2685 block_arena: Allocator, 2686 scope_tag: Scope.Tag, 2687 ) InnerError!*Scope { 2688 const tree = astgen.tree; 2689 const node_datas = tree.nodes.items(.data); 2690 const expr_node = node_datas[node].rhs; 2691 const token_starts = tree.tokens.items(.start); 2692 const node_start = token_starts[tree.firstToken(expr_node)]; 2693 const defer_scope = try block_arena.create(Scope.Defer); 2694 astgen.advanceSourceCursor(node_start); 2695 2696 defer_scope.* = .{ 2697 .base = .{ .tag = scope_tag }, 2698 .parent = scope, 2699 .defer_node = node, 2700 .source_offset = astgen.source_offset, 2701 .source_line = astgen.source_line, 2702 .source_column = astgen.source_column, 2703 }; 2704 return &defer_scope.base; 2705 } 2706 2707 fn varDecl( 2708 gz: *GenZir, 2709 scope: *Scope, 2710 node: Ast.Node.Index, 2711 block_arena: Allocator, 2712 var_decl: Ast.full.VarDecl, 2713 ) InnerError!*Scope { 2714 try emitDbgNode(gz, node); 2715 const astgen = gz.astgen; 2716 const tree = astgen.tree; 2717 const token_tags = tree.tokens.items(.tag); 2718 const main_tokens = tree.nodes.items(.main_token); 2719 2720 const name_token = var_decl.ast.mut_token + 1; 2721 const ident_name_raw = tree.tokenSlice(name_token); 2722 if (mem.eql(u8, ident_name_raw, "_")) { 2723 return astgen.failTok(name_token, "'_' used as an identifier without @\"_\" syntax", .{}); 2724 } 2725 const ident_name = try astgen.identAsString(name_token); 2726 2727 try astgen.detectLocalShadowing(scope, ident_name, name_token, ident_name_raw); 2728 2729 if (var_decl.ast.init_node == 0) { 2730 return astgen.failNode(node, "variables must be initialized", .{}); 2731 } 2732 2733 if (var_decl.ast.addrspace_node != 0) { 2734 return astgen.failTok(main_tokens[var_decl.ast.addrspace_node], "cannot set address space of local variable '{s}'", .{ident_name_raw}); 2735 } 2736 2737 if (var_decl.ast.section_node != 0) { 2738 return astgen.failTok(main_tokens[var_decl.ast.section_node], "cannot set section of local variable '{s}'", .{ident_name_raw}); 2739 } 2740 2741 const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node != 0) 2742 try expr(gz, scope, align_rl, var_decl.ast.align_node) 2743 else 2744 .none; 2745 2746 switch (token_tags[var_decl.ast.mut_token]) { 2747 .keyword_const => { 2748 if (var_decl.comptime_token) |comptime_token| { 2749 try astgen.appendErrorTok(comptime_token, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{}); 2750 } 2751 2752 // Depending on the type of AST the initialization expression is, we may need an lvalue 2753 // or an rvalue as a result location. If it is an rvalue, we can use the instruction as 2754 // the variable, no memory location needed. 2755 const type_node = var_decl.ast.type_node; 2756 if (align_inst == .none and 2757 !nodeMayNeedMemoryLocation(tree, var_decl.ast.init_node, type_node != 0)) 2758 { 2759 const result_loc: ResultLoc = if (type_node != 0) .{ 2760 .ty = try typeExpr(gz, scope, type_node), 2761 } else .none; 2762 const prev_anon_name_strategy = gz.anon_name_strategy; 2763 gz.anon_name_strategy = .dbg_var; 2764 const init_inst = try reachableExpr(gz, scope, result_loc, var_decl.ast.init_node, node); 2765 gz.anon_name_strategy = prev_anon_name_strategy; 2766 2767 try gz.addDbgVar(.dbg_var_val, ident_name, init_inst); 2768 2769 const sub_scope = try block_arena.create(Scope.LocalVal); 2770 sub_scope.* = .{ 2771 .parent = scope, 2772 .gen_zir = gz, 2773 .name = ident_name, 2774 .inst = init_inst, 2775 .token_src = name_token, 2776 .id_cat = .@"local constant", 2777 }; 2778 return &sub_scope.base; 2779 } 2780 2781 const is_comptime = gz.force_comptime or 2782 tree.nodes.items(.tag)[var_decl.ast.init_node] == .@"comptime"; 2783 2784 // Detect whether the initialization expression actually uses the 2785 // result location pointer. 2786 var init_scope = gz.makeSubBlock(scope); 2787 // we may add more instructions to gz before stacking init_scope 2788 init_scope.instructions_top = GenZir.unstacked_top; 2789 init_scope.anon_name_strategy = .dbg_var; 2790 defer init_scope.unstack(); 2791 2792 var resolve_inferred_alloc: Zir.Inst.Ref = .none; 2793 var opt_type_inst: Zir.Inst.Ref = .none; 2794 if (type_node != 0) { 2795 const type_inst = try typeExpr(gz, &init_scope.base, type_node); 2796 opt_type_inst = type_inst; 2797 if (align_inst == .none) { 2798 init_scope.instructions_top = gz.instructions.items.len; 2799 init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node); 2800 } else { 2801 init_scope.rl_ptr = try gz.addAllocExtended(.{ 2802 .node = node, 2803 .type_inst = type_inst, 2804 .align_inst = align_inst, 2805 .is_const = true, 2806 .is_comptime = is_comptime, 2807 }); 2808 init_scope.instructions_top = gz.instructions.items.len; 2809 } 2810 init_scope.rl_ty_inst = type_inst; 2811 } else { 2812 const alloc = if (align_inst == .none) alloc: { 2813 init_scope.instructions_top = gz.instructions.items.len; 2814 const tag: Zir.Inst.Tag = if (is_comptime) 2815 .alloc_inferred_comptime 2816 else 2817 .alloc_inferred; 2818 break :alloc try init_scope.addNode(tag, node); 2819 } else alloc: { 2820 const ref = try gz.addAllocExtended(.{ 2821 .node = node, 2822 .type_inst = .none, 2823 .align_inst = align_inst, 2824 .is_const = true, 2825 .is_comptime = is_comptime, 2826 }); 2827 init_scope.instructions_top = gz.instructions.items.len; 2828 break :alloc ref; 2829 }; 2830 resolve_inferred_alloc = alloc; 2831 init_scope.rl_ptr = alloc; 2832 init_scope.rl_ty_inst = .none; 2833 } 2834 const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope }; 2835 const init_inst = try reachableExpr(&init_scope, &init_scope.base, init_result_loc, var_decl.ast.init_node, node); 2836 2837 const zir_tags = astgen.instructions.items(.tag); 2838 const zir_datas = astgen.instructions.items(.data); 2839 2840 if (align_inst == .none and init_scope.rvalue_rl_count == 1) { 2841 // Result location pointer not used. We don't need an alloc for this 2842 // const local, and type inference becomes trivial. 2843 // Implicitly move the init_scope instructions into the parent scope, 2844 // then elide the alloc instruction and the store_to_block_ptr instruction. 2845 var src = init_scope.instructions_top; 2846 var dst = src; 2847 init_scope.instructions_top = GenZir.unstacked_top; 2848 while (src < gz.instructions.items.len) : (src += 1) { 2849 const src_inst = gz.instructions.items[src]; 2850 if (indexToRef(src_inst) == init_scope.rl_ptr) continue; 2851 if (zir_tags[src_inst] == .store_to_block_ptr) { 2852 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) continue; 2853 } 2854 gz.instructions.items[dst] = src_inst; 2855 dst += 1; 2856 } 2857 gz.instructions.items.len = dst; 2858 2859 // In case the result location did not do the coercion 2860 // for us so we must do it here. 2861 const coerced_init = if (opt_type_inst != .none) 2862 try gz.addBin(.as, opt_type_inst, init_inst) 2863 else 2864 init_inst; 2865 2866 try gz.addDbgVar(.dbg_var_val, ident_name, coerced_init); 2867 2868 const sub_scope = try block_arena.create(Scope.LocalVal); 2869 sub_scope.* = .{ 2870 .parent = scope, 2871 .gen_zir = gz, 2872 .name = ident_name, 2873 .inst = coerced_init, 2874 .token_src = name_token, 2875 .id_cat = .@"local constant", 2876 }; 2877 return &sub_scope.base; 2878 } 2879 // The initialization expression took advantage of the result location 2880 // of the const local. In this case we will create an alloc and a LocalPtr for it. 2881 // Implicitly move the init_scope instructions into the parent scope, then swap 2882 // store_to_block_ptr for store_to_inferred_ptr. 2883 2884 var src = init_scope.instructions_top; 2885 init_scope.instructions_top = GenZir.unstacked_top; 2886 while (src < gz.instructions.items.len) : (src += 1) { 2887 const src_inst = gz.instructions.items[src]; 2888 if (zir_tags[src_inst] == .store_to_block_ptr) { 2889 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) { 2890 if (type_node != 0) { 2891 zir_tags[src_inst] = .store; 2892 } else { 2893 zir_tags[src_inst] = .store_to_inferred_ptr; 2894 } 2895 } 2896 } 2897 } 2898 if (resolve_inferred_alloc != .none) { 2899 _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node); 2900 } 2901 const const_ptr = try gz.addUnNode(.make_ptr_const, init_scope.rl_ptr, node); 2902 2903 try gz.addDbgVar(.dbg_var_ptr, ident_name, const_ptr); 2904 2905 const sub_scope = try block_arena.create(Scope.LocalPtr); 2906 sub_scope.* = .{ 2907 .parent = scope, 2908 .gen_zir = gz, 2909 .name = ident_name, 2910 .ptr = const_ptr, 2911 .token_src = name_token, 2912 .maybe_comptime = true, 2913 .id_cat = .@"local constant", 2914 }; 2915 return &sub_scope.base; 2916 }, 2917 .keyword_var => { 2918 const old_rl_ty_inst = gz.rl_ty_inst; 2919 defer gz.rl_ty_inst = old_rl_ty_inst; 2920 2921 const is_comptime = var_decl.comptime_token != null or gz.force_comptime; 2922 var resolve_inferred_alloc: Zir.Inst.Ref = .none; 2923 const var_data: struct { 2924 result_loc: ResultLoc, 2925 alloc: Zir.Inst.Ref, 2926 } = if (var_decl.ast.type_node != 0) a: { 2927 const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node); 2928 const alloc = alloc: { 2929 if (align_inst == .none) { 2930 const tag: Zir.Inst.Tag = if (is_comptime) 2931 .alloc_comptime_mut 2932 else 2933 .alloc_mut; 2934 break :alloc try gz.addUnNode(tag, type_inst, node); 2935 } else { 2936 break :alloc try gz.addAllocExtended(.{ 2937 .node = node, 2938 .type_inst = type_inst, 2939 .align_inst = align_inst, 2940 .is_const = false, 2941 .is_comptime = is_comptime, 2942 }); 2943 } 2944 }; 2945 gz.rl_ty_inst = type_inst; 2946 break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } }; 2947 } else a: { 2948 const alloc = alloc: { 2949 if (align_inst == .none) { 2950 const tag: Zir.Inst.Tag = if (is_comptime) 2951 .alloc_inferred_comptime_mut 2952 else 2953 .alloc_inferred_mut; 2954 break :alloc try gz.addNode(tag, node); 2955 } else { 2956 break :alloc try gz.addAllocExtended(.{ 2957 .node = node, 2958 .type_inst = .none, 2959 .align_inst = align_inst, 2960 .is_const = false, 2961 .is_comptime = is_comptime, 2962 }); 2963 } 2964 }; 2965 gz.rl_ty_inst = .none; 2966 resolve_inferred_alloc = alloc; 2967 break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } }; 2968 }; 2969 const prev_anon_name_strategy = gz.anon_name_strategy; 2970 gz.anon_name_strategy = .dbg_var; 2971 _ = try reachableExprComptime(gz, scope, var_data.result_loc, var_decl.ast.init_node, node, is_comptime); 2972 gz.anon_name_strategy = prev_anon_name_strategy; 2973 if (resolve_inferred_alloc != .none) { 2974 _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node); 2975 } 2976 2977 try gz.addDbgVar(.dbg_var_ptr, ident_name, var_data.alloc); 2978 2979 const sub_scope = try block_arena.create(Scope.LocalPtr); 2980 sub_scope.* = .{ 2981 .parent = scope, 2982 .gen_zir = gz, 2983 .name = ident_name, 2984 .ptr = var_data.alloc, 2985 .token_src = name_token, 2986 .maybe_comptime = is_comptime, 2987 .id_cat = .@"local variable", 2988 }; 2989 return &sub_scope.base; 2990 }, 2991 else => unreachable, 2992 } 2993 } 2994 2995 fn emitDbgNode(gz: *GenZir, node: Ast.Node.Index) !void { 2996 // The instruction emitted here is for debugging runtime code. 2997 // If the current block will be evaluated only during semantic analysis 2998 // then no dbg_stmt ZIR instruction is needed. 2999 if (gz.force_comptime) return; 3000 3001 const astgen = gz.astgen; 3002 astgen.advanceSourceCursorToNode(node); 3003 const line = astgen.source_line - gz.decl_line; 3004 const column = astgen.source_column; 3005 3006 _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{ 3007 .dbg_stmt = .{ 3008 .line = line, 3009 .column = column, 3010 }, 3011 } }); 3012 } 3013 3014 fn assign(gz: *GenZir, scope: *Scope, infix_node: Ast.Node.Index) InnerError!void { 3015 try emitDbgNode(gz, infix_node); 3016 const astgen = gz.astgen; 3017 const tree = astgen.tree; 3018 const node_datas = tree.nodes.items(.data); 3019 const main_tokens = tree.nodes.items(.main_token); 3020 const node_tags = tree.nodes.items(.tag); 3021 3022 const lhs = node_datas[infix_node].lhs; 3023 const rhs = node_datas[infix_node].rhs; 3024 if (node_tags[lhs] == .identifier) { 3025 // This intentionally does not support `@"_"` syntax. 3026 const ident_name = tree.tokenSlice(main_tokens[lhs]); 3027 if (mem.eql(u8, ident_name, "_")) { 3028 _ = try expr(gz, scope, .discard, rhs); 3029 return; 3030 } 3031 } 3032 const lvalue = try lvalExpr(gz, scope, lhs); 3033 _ = try expr(gz, scope, .{ .ptr = lvalue }, rhs); 3034 } 3035 3036 fn assignOp( 3037 gz: *GenZir, 3038 scope: *Scope, 3039 infix_node: Ast.Node.Index, 3040 op_inst_tag: Zir.Inst.Tag, 3041 ) InnerError!void { 3042 try emitDbgNode(gz, infix_node); 3043 const astgen = gz.astgen; 3044 const tree = astgen.tree; 3045 const node_datas = tree.nodes.items(.data); 3046 3047 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs); 3048 const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node); 3049 const lhs_type = try gz.addUnNode(.typeof, lhs, infix_node); 3050 const rhs = try expr(gz, scope, .{ .coerced_ty = lhs_type }, node_datas[infix_node].rhs); 3051 3052 const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{ 3053 .lhs = lhs, 3054 .rhs = rhs, 3055 }); 3056 _ = try gz.addBin(.store, lhs_ptr, result); 3057 } 3058 3059 fn assignShift( 3060 gz: *GenZir, 3061 scope: *Scope, 3062 infix_node: Ast.Node.Index, 3063 op_inst_tag: Zir.Inst.Tag, 3064 ) InnerError!void { 3065 try emitDbgNode(gz, infix_node); 3066 const astgen = gz.astgen; 3067 const tree = astgen.tree; 3068 const node_datas = tree.nodes.items(.data); 3069 3070 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs); 3071 const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node); 3072 const rhs_type = try gz.addUnNode(.typeof_log2_int_type, lhs, infix_node); 3073 const rhs = try expr(gz, scope, .{ .ty = rhs_type }, node_datas[infix_node].rhs); 3074 3075 const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{ 3076 .lhs = lhs, 3077 .rhs = rhs, 3078 }); 3079 _ = try gz.addBin(.store, lhs_ptr, result); 3080 } 3081 3082 fn assignShiftSat(gz: *GenZir, scope: *Scope, infix_node: Ast.Node.Index) InnerError!void { 3083 try emitDbgNode(gz, infix_node); 3084 const astgen = gz.astgen; 3085 const tree = astgen.tree; 3086 const node_datas = tree.nodes.items(.data); 3087 3088 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs); 3089 const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node); 3090 // Saturating shift-left allows any integer type for both the LHS and RHS. 3091 const rhs = try expr(gz, scope, .none, node_datas[infix_node].rhs); 3092 3093 const result = try gz.addPlNode(.shl_sat, infix_node, Zir.Inst.Bin{ 3094 .lhs = lhs, 3095 .rhs = rhs, 3096 }); 3097 _ = try gz.addBin(.store, lhs_ptr, result); 3098 } 3099 3100 fn ptrType( 3101 gz: *GenZir, 3102 scope: *Scope, 3103 rl: ResultLoc, 3104 node: Ast.Node.Index, 3105 ptr_info: Ast.full.PtrType, 3106 ) InnerError!Zir.Inst.Ref { 3107 if (ptr_info.size == .C and ptr_info.allowzero_token != null) { 3108 return gz.astgen.failTok(ptr_info.allowzero_token.?, "C pointers always allow address zero", .{}); 3109 } 3110 3111 const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type); 3112 3113 var sentinel_ref: Zir.Inst.Ref = .none; 3114 var align_ref: Zir.Inst.Ref = .none; 3115 var addrspace_ref: Zir.Inst.Ref = .none; 3116 var bit_start_ref: Zir.Inst.Ref = .none; 3117 var bit_end_ref: Zir.Inst.Ref = .none; 3118 var trailing_count: u32 = 0; 3119 3120 if (ptr_info.ast.sentinel != 0) { 3121 sentinel_ref = try expr(gz, scope, .{ .ty = elem_type }, ptr_info.ast.sentinel); 3122 trailing_count += 1; 3123 } 3124 if (ptr_info.ast.align_node != 0) { 3125 align_ref = try expr(gz, scope, coerced_align_rl, ptr_info.ast.align_node); 3126 trailing_count += 1; 3127 } 3128 if (ptr_info.ast.addrspace_node != 0) { 3129 addrspace_ref = try expr(gz, scope, .{ .ty = .address_space_type }, ptr_info.ast.addrspace_node); 3130 trailing_count += 1; 3131 } 3132 if (ptr_info.ast.bit_range_start != 0) { 3133 assert(ptr_info.ast.bit_range_end != 0); 3134 bit_start_ref = try expr(gz, scope, .{ .coerced_ty = .u16_type }, ptr_info.ast.bit_range_start); 3135 bit_end_ref = try expr(gz, scope, .{ .coerced_ty = .u16_type }, ptr_info.ast.bit_range_end); 3136 trailing_count += 2; 3137 } 3138 3139 const gpa = gz.astgen.gpa; 3140 try gz.instructions.ensureUnusedCapacity(gpa, 1); 3141 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 3142 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.PtrType).Struct.fields.len + 3143 trailing_count); 3144 3145 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.PtrType{ 3146 .elem_type = elem_type, 3147 .src_node = gz.nodeIndexToRelative(node), 3148 }); 3149 if (sentinel_ref != .none) { 3150 gz.astgen.extra.appendAssumeCapacity(@enumToInt(sentinel_ref)); 3151 } 3152 if (align_ref != .none) { 3153 gz.astgen.extra.appendAssumeCapacity(@enumToInt(align_ref)); 3154 } 3155 if (addrspace_ref != .none) { 3156 gz.astgen.extra.appendAssumeCapacity(@enumToInt(addrspace_ref)); 3157 } 3158 if (bit_start_ref != .none) { 3159 gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_start_ref)); 3160 gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_end_ref)); 3161 } 3162 3163 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 3164 const result = indexToRef(new_index); 3165 gz.astgen.instructions.appendAssumeCapacity(.{ .tag = .ptr_type, .data = .{ 3166 .ptr_type = .{ 3167 .flags = .{ 3168 .is_allowzero = ptr_info.allowzero_token != null, 3169 .is_mutable = ptr_info.const_token == null, 3170 .is_volatile = ptr_info.volatile_token != null, 3171 .has_sentinel = sentinel_ref != .none, 3172 .has_align = align_ref != .none, 3173 .has_addrspace = addrspace_ref != .none, 3174 .has_bit_range = bit_start_ref != .none, 3175 }, 3176 .size = ptr_info.size, 3177 .payload_index = payload_index, 3178 }, 3179 } }); 3180 gz.instructions.appendAssumeCapacity(new_index); 3181 3182 return rvalue(gz, rl, result, node); 3183 } 3184 3185 fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) !Zir.Inst.Ref { 3186 const astgen = gz.astgen; 3187 const tree = astgen.tree; 3188 const node_datas = tree.nodes.items(.data); 3189 const node_tags = tree.nodes.items(.tag); 3190 const main_tokens = tree.nodes.items(.main_token); 3191 3192 const len_node = node_datas[node].lhs; 3193 if (node_tags[len_node] == .identifier and 3194 mem.eql(u8, tree.tokenSlice(main_tokens[len_node]), "_")) 3195 { 3196 return astgen.failNode(len_node, "unable to infer array size", .{}); 3197 } 3198 const len = try expr(gz, scope, .{ .coerced_ty = .usize_type }, len_node); 3199 const elem_type = try typeExpr(gz, scope, node_datas[node].rhs); 3200 3201 const result = try gz.addPlNode(.array_type, node, Zir.Inst.Bin{ 3202 .lhs = len, 3203 .rhs = elem_type, 3204 }); 3205 return rvalue(gz, rl, result, node); 3206 } 3207 3208 fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) !Zir.Inst.Ref { 3209 const astgen = gz.astgen; 3210 const tree = astgen.tree; 3211 const node_datas = tree.nodes.items(.data); 3212 const node_tags = tree.nodes.items(.tag); 3213 const main_tokens = tree.nodes.items(.main_token); 3214 const extra = tree.extraData(node_datas[node].rhs, Ast.Node.ArrayTypeSentinel); 3215 3216 const len_node = node_datas[node].lhs; 3217 if (node_tags[len_node] == .identifier and 3218 mem.eql(u8, tree.tokenSlice(main_tokens[len_node]), "_")) 3219 { 3220 return astgen.failNode(len_node, "unable to infer array size", .{}); 3221 } 3222 const len = try reachableExpr(gz, scope, .{ .coerced_ty = .usize_type }, len_node, node); 3223 const elem_type = try typeExpr(gz, scope, extra.elem_type); 3224 const sentinel = try reachableExpr(gz, scope, .{ .coerced_ty = elem_type }, extra.sentinel, node); 3225 3226 const result = try gz.addPlNode(.array_type_sentinel, node, Zir.Inst.ArrayTypeSentinel{ 3227 .len = len, 3228 .elem_type = elem_type, 3229 .sentinel = sentinel, 3230 }); 3231 return rvalue(gz, rl, result, node); 3232 } 3233 3234 const WipMembers = struct { 3235 payload: *ArrayListUnmanaged(u32), 3236 payload_top: usize, 3237 decls_start: u32, 3238 decls_end: u32, 3239 field_bits_start: u32, 3240 fields_start: u32, 3241 fields_end: u32, 3242 decl_index: u32 = 0, 3243 field_index: u32 = 0, 3244 3245 const Self = @This(); 3246 /// struct, union, enum, and opaque decls all use same 4 bits per decl 3247 const bits_per_decl = 4; 3248 const decls_per_u32 = 32 / bits_per_decl; 3249 /// struct, union, enum, and opaque decls all have maximum size of 11 u32 slots 3250 /// (4 for src_hash + line + name + value + doc_comment + align + link_section + address_space ) 3251 const max_decl_size = 11; 3252 3253 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 { 3254 const payload_top = @intCast(u32, payload.items.len); 3255 const decls_start = payload_top + (decl_count + decls_per_u32 - 1) / decls_per_u32; 3256 const field_bits_start = decls_start + decl_count * max_decl_size; 3257 const fields_start = field_bits_start + if (bits_per_field > 0) blk: { 3258 const fields_per_u32 = 32 / bits_per_field; 3259 break :blk (field_count + fields_per_u32 - 1) / fields_per_u32; 3260 } else 0; 3261 const payload_end = fields_start + field_count * max_field_size; 3262 try payload.resize(gpa, payload_end); 3263 return Self{ 3264 .payload = payload, 3265 .payload_top = payload_top, 3266 .decls_start = decls_start, 3267 .field_bits_start = field_bits_start, 3268 .fields_start = fields_start, 3269 .decls_end = decls_start, 3270 .fields_end = fields_start, 3271 }; 3272 } 3273 3274 pub fn nextDecl(self: *Self, is_pub: bool, is_export: bool, has_align: bool, has_section_or_addrspace: bool) void { 3275 const index = self.payload_top + self.decl_index / decls_per_u32; 3276 assert(index < self.decls_start); 3277 const bit_bag: u32 = if (self.decl_index % decls_per_u32 == 0) 0 else self.payload.items[index]; 3278 self.payload.items[index] = (bit_bag >> bits_per_decl) | 3279 (@as(u32, @boolToInt(is_pub)) << 28) | 3280 (@as(u32, @boolToInt(is_export)) << 29) | 3281 (@as(u32, @boolToInt(has_align)) << 30) | 3282 (@as(u32, @boolToInt(has_section_or_addrspace)) << 31); 3283 self.decl_index += 1; 3284 } 3285 3286 pub fn nextField(self: *Self, comptime bits_per_field: u32, bits: [bits_per_field]bool) void { 3287 const fields_per_u32 = 32 / bits_per_field; 3288 const index = self.field_bits_start + self.field_index / fields_per_u32; 3289 assert(index < self.fields_start); 3290 var bit_bag: u32 = if (self.field_index % fields_per_u32 == 0) 0 else self.payload.items[index]; 3291 bit_bag >>= bits_per_field; 3292 comptime var i = 0; 3293 inline while (i < bits_per_field) : (i += 1) { 3294 bit_bag |= @as(u32, @boolToInt(bits[i])) << (32 - bits_per_field + i); 3295 } 3296 self.payload.items[index] = bit_bag; 3297 self.field_index += 1; 3298 } 3299 3300 pub fn appendToDecl(self: *Self, data: u32) void { 3301 assert(self.decls_end < self.field_bits_start); 3302 self.payload.items[self.decls_end] = data; 3303 self.decls_end += 1; 3304 } 3305 3306 pub fn appendToDeclSlice(self: *Self, data: []const u32) void { 3307 assert(self.decls_end + data.len <= self.field_bits_start); 3308 mem.copy(u32, self.payload.items[self.decls_end..], data); 3309 self.decls_end += @intCast(u32, data.len); 3310 } 3311 3312 pub fn appendToField(self: *Self, data: u32) void { 3313 assert(self.fields_end < self.payload.items.len); 3314 self.payload.items[self.fields_end] = data; 3315 self.fields_end += 1; 3316 } 3317 3318 pub fn finishBits(self: *Self, comptime bits_per_field: u32) void { 3319 const empty_decl_slots = decls_per_u32 - (self.decl_index % decls_per_u32); 3320 if (self.decl_index > 0 and empty_decl_slots < decls_per_u32) { 3321 const index = self.payload_top + self.decl_index / decls_per_u32; 3322 self.payload.items[index] >>= @intCast(u5, empty_decl_slots * bits_per_decl); 3323 } 3324 if (bits_per_field > 0) { 3325 const fields_per_u32 = 32 / bits_per_field; 3326 const empty_field_slots = fields_per_u32 - (self.field_index % fields_per_u32); 3327 if (self.field_index > 0 and empty_field_slots < fields_per_u32) { 3328 const index = self.field_bits_start + self.field_index / fields_per_u32; 3329 self.payload.items[index] >>= @intCast(u5, empty_field_slots * bits_per_field); 3330 } 3331 } 3332 } 3333 3334 pub fn declsSlice(self: *Self) []u32 { 3335 return self.payload.items[self.payload_top..self.decls_end]; 3336 } 3337 3338 pub fn fieldsSlice(self: *Self) []u32 { 3339 return self.payload.items[self.field_bits_start..self.fields_end]; 3340 } 3341 3342 pub fn deinit(self: *Self) void { 3343 self.payload.items.len = self.payload_top; 3344 } 3345 }; 3346 3347 fn fnDecl( 3348 astgen: *AstGen, 3349 gz: *GenZir, 3350 scope: *Scope, 3351 wip_members: *WipMembers, 3352 decl_node: Ast.Node.Index, 3353 body_node: Ast.Node.Index, 3354 fn_proto: Ast.full.FnProto, 3355 ) InnerError!void { 3356 const tree = astgen.tree; 3357 const token_tags = tree.tokens.items(.tag); 3358 3359 // missing function name already happened in scanDecls() 3360 const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail; 3361 const fn_name_str_index = try astgen.identAsString(fn_name_token); 3362 3363 // We insert this at the beginning so that its instruction index marks the 3364 // start of the top level declaration. 3365 const block_inst = try gz.makeBlockInst(.block_inline, fn_proto.ast.proto_node); 3366 astgen.advanceSourceCursorToNode(decl_node); 3367 3368 var decl_gz: GenZir = .{ 3369 .force_comptime = true, 3370 .in_defer = false, 3371 .decl_node_index = fn_proto.ast.proto_node, 3372 .decl_line = astgen.source_line, 3373 .parent = scope, 3374 .astgen = astgen, 3375 .instructions = gz.instructions, 3376 .instructions_top = gz.instructions.items.len, 3377 }; 3378 defer decl_gz.unstack(); 3379 3380 var fn_gz: GenZir = .{ 3381 .force_comptime = false, 3382 .in_defer = false, 3383 .decl_node_index = fn_proto.ast.proto_node, 3384 .decl_line = decl_gz.decl_line, 3385 .parent = &decl_gz.base, 3386 .astgen = astgen, 3387 .instructions = gz.instructions, 3388 .instructions_top = GenZir.unstacked_top, 3389 }; 3390 defer fn_gz.unstack(); 3391 3392 // TODO: support noinline 3393 const is_pub = fn_proto.visib_token != null; 3394 const is_export = blk: { 3395 const maybe_export_token = fn_proto.extern_export_inline_token orelse break :blk false; 3396 break :blk token_tags[maybe_export_token] == .keyword_export; 3397 }; 3398 const is_extern = blk: { 3399 const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false; 3400 break :blk token_tags[maybe_extern_token] == .keyword_extern; 3401 }; 3402 const has_inline_keyword = blk: { 3403 const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false; 3404 break :blk token_tags[maybe_inline_token] == .keyword_inline; 3405 }; 3406 3407 const doc_comment_index = try astgen.docCommentAsString(fn_proto.firstToken()); 3408 3409 // align, linksection, and addrspace is passed in the func instruction in this case. 3410 wip_members.nextDecl(is_pub, is_export, false, false); 3411 3412 var noalias_bits: u32 = 0; 3413 var params_scope = &fn_gz.base; 3414 const is_var_args = is_var_args: { 3415 var param_type_i: usize = 0; 3416 var it = fn_proto.iterate(tree); 3417 while (it.next()) |param| : (param_type_i += 1) { 3418 const is_comptime = if (param.comptime_noalias) |token| switch (token_tags[token]) { 3419 .keyword_noalias => is_comptime: { 3420 noalias_bits |= @as(u32, 1) << (std.math.cast(u5, param_type_i) orelse 3421 return astgen.failTok(token, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{})); 3422 break :is_comptime false; 3423 }, 3424 .keyword_comptime => true, 3425 else => false, 3426 } else false; 3427 3428 const is_anytype = if (param.anytype_ellipsis3) |token| blk: { 3429 switch (token_tags[token]) { 3430 .keyword_anytype => break :blk true, 3431 .ellipsis3 => break :is_var_args true, 3432 else => unreachable, 3433 } 3434 } else false; 3435 3436 const param_name: u32 = if (param.name_token) |name_token| blk: { 3437 const name_bytes = tree.tokenSlice(name_token); 3438 if (mem.eql(u8, "_", name_bytes)) 3439 break :blk 0; 3440 3441 const param_name = try astgen.identAsString(name_token); 3442 if (!is_extern) { 3443 try astgen.detectLocalShadowing(params_scope, param_name, name_token, name_bytes); 3444 } 3445 break :blk param_name; 3446 } else if (!is_extern) { 3447 if (param.anytype_ellipsis3) |tok| { 3448 return astgen.failTok(tok, "missing parameter name", .{}); 3449 } else { 3450 return astgen.failNode(param.type_expr, "missing parameter name", .{}); 3451 } 3452 } else 0; 3453 3454 const param_inst = if (is_anytype) param: { 3455 const name_token = param.name_token orelse param.anytype_ellipsis3.?; 3456 const tag: Zir.Inst.Tag = if (is_comptime) 3457 .param_anytype_comptime 3458 else 3459 .param_anytype; 3460 break :param try decl_gz.addStrTok(tag, param_name, name_token); 3461 } else param: { 3462 const param_type_node = param.type_expr; 3463 assert(param_type_node != 0); 3464 var param_gz = decl_gz.makeSubBlock(scope); 3465 defer param_gz.unstack(); 3466 const param_type = try expr(¶m_gz, params_scope, coerced_type_rl, param_type_node); 3467 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1); 3468 _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type); 3469 3470 const main_tokens = tree.nodes.items(.main_token); 3471 const name_token = param.name_token orelse main_tokens[param_type_node]; 3472 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param; 3473 const param_inst = try decl_gz.addParam(¶m_gz, tag, name_token, param_name, param.first_doc_comment); 3474 assert(param_inst_expected == param_inst); 3475 break :param indexToRef(param_inst); 3476 }; 3477 3478 if (param_name == 0 or is_extern) continue; 3479 3480 const sub_scope = try astgen.arena.create(Scope.LocalVal); 3481 sub_scope.* = .{ 3482 .parent = params_scope, 3483 .gen_zir = &decl_gz, 3484 .name = param_name, 3485 .inst = param_inst, 3486 .token_src = param.name_token.?, 3487 .id_cat = .@"function parameter", 3488 }; 3489 params_scope = &sub_scope.base; 3490 } 3491 break :is_var_args false; 3492 }; 3493 3494 const lib_name: u32 = if (fn_proto.lib_name) |lib_name_token| blk: { 3495 const lib_name_str = try astgen.strLitAsString(lib_name_token); 3496 break :blk lib_name_str.index; 3497 } else 0; 3498 3499 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; 3500 const is_inferred_error = token_tags[maybe_bang] == .bang; 3501 3502 // After creating the function ZIR instruction, it will need to update the break 3503 // instructions inside the expression blocks for align, addrspace, cc, and ret_ty 3504 // to use the function instruction as the "block" to break from. 3505 3506 var align_gz = decl_gz.makeSubBlock(params_scope); 3507 defer align_gz.unstack(); 3508 const align_ref: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: { 3509 const inst = try expr(&decl_gz, params_scope, coerced_align_rl, fn_proto.ast.align_expr); 3510 if (align_gz.instructionsSlice().len == 0) { 3511 // In this case we will send a len=0 body which can be encoded more efficiently. 3512 break :inst inst; 3513 } 3514 _ = try align_gz.addBreak(.break_inline, 0, inst); 3515 break :inst inst; 3516 }; 3517 3518 var addrspace_gz = decl_gz.makeSubBlock(params_scope); 3519 defer addrspace_gz.unstack(); 3520 const addrspace_ref: Zir.Inst.Ref = if (fn_proto.ast.addrspace_expr == 0) .none else inst: { 3521 const inst = try expr(&decl_gz, params_scope, .{ .coerced_ty = .address_space_type }, fn_proto.ast.addrspace_expr); 3522 if (addrspace_gz.instructionsSlice().len == 0) { 3523 // In this case we will send a len=0 body which can be encoded more efficiently. 3524 break :inst inst; 3525 } 3526 _ = try addrspace_gz.addBreak(.break_inline, 0, inst); 3527 break :inst inst; 3528 }; 3529 3530 var section_gz = decl_gz.makeSubBlock(params_scope); 3531 defer section_gz.unstack(); 3532 const section_ref: Zir.Inst.Ref = if (fn_proto.ast.section_expr == 0) .none else inst: { 3533 const inst = try expr(&decl_gz, params_scope, .{ .coerced_ty = .const_slice_u8_type }, fn_proto.ast.section_expr); 3534 if (section_gz.instructionsSlice().len == 0) { 3535 // In this case we will send a len=0 body which can be encoded more efficiently. 3536 break :inst inst; 3537 } 3538 _ = try section_gz.addBreak(.break_inline, 0, inst); 3539 break :inst inst; 3540 }; 3541 3542 var cc_gz = decl_gz.makeSubBlock(params_scope); 3543 defer cc_gz.unstack(); 3544 const cc_ref: Zir.Inst.Ref = blk: { 3545 if (fn_proto.ast.callconv_expr != 0) { 3546 if (has_inline_keyword) { 3547 return astgen.failNode( 3548 fn_proto.ast.callconv_expr, 3549 "explicit callconv incompatible with inline keyword", 3550 .{}, 3551 ); 3552 } 3553 const inst = try expr( 3554 &decl_gz, 3555 params_scope, 3556 .{ .coerced_ty = .calling_convention_type }, 3557 fn_proto.ast.callconv_expr, 3558 ); 3559 if (cc_gz.instructionsSlice().len == 0) { 3560 // In this case we will send a len=0 body which can be encoded more efficiently. 3561 break :blk inst; 3562 } 3563 _ = try cc_gz.addBreak(.break_inline, 0, inst); 3564 break :blk inst; 3565 } else if (is_extern) { 3566 // note: https://github.com/ziglang/zig/issues/5269 3567 break :blk .calling_convention_c; 3568 } else if (has_inline_keyword) { 3569 break :blk .calling_convention_inline; 3570 } else { 3571 break :blk .none; 3572 } 3573 }; 3574 3575 var ret_gz = decl_gz.makeSubBlock(params_scope); 3576 defer ret_gz.unstack(); 3577 const ret_ref: Zir.Inst.Ref = inst: { 3578 const inst = try expr(&ret_gz, params_scope, coerced_type_rl, fn_proto.ast.return_type); 3579 if (ret_gz.instructionsSlice().len == 0) { 3580 // In this case we will send a len=0 body which can be encoded more efficiently. 3581 break :inst inst; 3582 } 3583 _ = try ret_gz.addBreak(.break_inline, 0, inst); 3584 break :inst inst; 3585 }; 3586 3587 const func_inst: Zir.Inst.Ref = if (body_node == 0) func: { 3588 if (!is_extern) { 3589 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function has no body", .{}); 3590 } 3591 if (is_inferred_error) { 3592 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{}); 3593 } 3594 break :func try decl_gz.addFunc(.{ 3595 .src_node = decl_node, 3596 .cc_ref = cc_ref, 3597 .cc_gz = &cc_gz, 3598 .align_ref = align_ref, 3599 .align_gz = &align_gz, 3600 .ret_ref = ret_ref, 3601 .ret_gz = &ret_gz, 3602 .section_ref = section_ref, 3603 .section_gz = §ion_gz, 3604 .addrspace_ref = addrspace_ref, 3605 .addrspace_gz = &addrspace_gz, 3606 .param_block = block_inst, 3607 .body_gz = null, 3608 .lib_name = lib_name, 3609 .is_var_args = is_var_args, 3610 .is_inferred_error = false, 3611 .is_test = false, 3612 .is_extern = true, 3613 .noalias_bits = noalias_bits, 3614 }); 3615 } else func: { 3616 if (is_var_args) { 3617 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function is variadic", .{}); 3618 } 3619 3620 // as a scope, fn_gz encloses ret_gz, but for instruction list, fn_gz stacks on ret_gz 3621 fn_gz.instructions_top = ret_gz.instructions.items.len; 3622 3623 const prev_fn_block = astgen.fn_block; 3624 astgen.fn_block = &fn_gz; 3625 defer astgen.fn_block = prev_fn_block; 3626 3627 astgen.advanceSourceCursorToNode(body_node); 3628 const lbrace_line = astgen.source_line - decl_gz.decl_line; 3629 const lbrace_column = astgen.source_column; 3630 3631 _ = try expr(&fn_gz, params_scope, .none, body_node); 3632 try checkUsed(gz, &fn_gz.base, params_scope); 3633 3634 if (!fn_gz.endsWithNoReturn()) { 3635 // Since we are adding the return instruction here, we must handle the coercion. 3636 // We do this by using the `ret_tok` instruction. 3637 _ = try fn_gz.addUnTok(.ret_tok, .void_value, tree.lastToken(body_node)); 3638 } 3639 3640 break :func try decl_gz.addFunc(.{ 3641 .src_node = decl_node, 3642 .cc_ref = cc_ref, 3643 .cc_gz = &cc_gz, 3644 .align_ref = align_ref, 3645 .align_gz = &align_gz, 3646 .ret_ref = ret_ref, 3647 .ret_gz = &ret_gz, 3648 .section_ref = section_ref, 3649 .section_gz = §ion_gz, 3650 .addrspace_ref = addrspace_ref, 3651 .addrspace_gz = &addrspace_gz, 3652 .lbrace_line = lbrace_line, 3653 .lbrace_column = lbrace_column, 3654 .param_block = block_inst, 3655 .body_gz = &fn_gz, 3656 .lib_name = lib_name, 3657 .is_var_args = is_var_args, 3658 .is_inferred_error = is_inferred_error, 3659 .is_test = false, 3660 .is_extern = false, 3661 .noalias_bits = noalias_bits, 3662 }); 3663 }; 3664 3665 // We add this at the end so that its instruction index marks the end range 3666 // of the top level declaration. addFunc already unstacked fn_gz and ret_gz. 3667 _ = try decl_gz.addBreak(.break_inline, block_inst, func_inst); 3668 try decl_gz.setBlockBody(block_inst); 3669 3670 { 3671 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node)); 3672 const casted = @bitCast([4]u32, contents_hash); 3673 wip_members.appendToDeclSlice(&casted); 3674 } 3675 { 3676 const line_delta = decl_gz.decl_line - gz.decl_line; 3677 wip_members.appendToDecl(line_delta); 3678 } 3679 wip_members.appendToDecl(fn_name_str_index); 3680 wip_members.appendToDecl(block_inst); 3681 wip_members.appendToDecl(doc_comment_index); 3682 } 3683 3684 fn globalVarDecl( 3685 astgen: *AstGen, 3686 gz: *GenZir, 3687 scope: *Scope, 3688 wip_members: *WipMembers, 3689 node: Ast.Node.Index, 3690 var_decl: Ast.full.VarDecl, 3691 ) InnerError!void { 3692 const tree = astgen.tree; 3693 const token_tags = tree.tokens.items(.tag); 3694 3695 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var; 3696 // We do this at the beginning so that the instruction index marks the range start 3697 // of the top level declaration. 3698 const block_inst = try gz.makeBlockInst(.block_inline, node); 3699 3700 const name_token = var_decl.ast.mut_token + 1; 3701 const name_str_index = try astgen.identAsString(name_token); 3702 astgen.advanceSourceCursorToNode(node); 3703 3704 var block_scope: GenZir = .{ 3705 .parent = scope, 3706 .decl_node_index = node, 3707 .decl_line = astgen.source_line, 3708 .astgen = astgen, 3709 .force_comptime = true, 3710 .in_defer = false, 3711 .anon_name_strategy = .parent, 3712 .instructions = gz.instructions, 3713 .instructions_top = gz.instructions.items.len, 3714 }; 3715 defer block_scope.unstack(); 3716 3717 const is_pub = var_decl.visib_token != null; 3718 const is_export = blk: { 3719 const maybe_export_token = var_decl.extern_export_token orelse break :blk false; 3720 break :blk token_tags[maybe_export_token] == .keyword_export; 3721 }; 3722 const is_extern = blk: { 3723 const maybe_extern_token = var_decl.extern_export_token orelse break :blk false; 3724 break :blk token_tags[maybe_extern_token] == .keyword_extern; 3725 }; 3726 const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node == 0) .none else inst: { 3727 break :inst try expr(&block_scope, &block_scope.base, align_rl, var_decl.ast.align_node); 3728 }; 3729 const addrspace_inst: Zir.Inst.Ref = if (var_decl.ast.addrspace_node == 0) .none else inst: { 3730 break :inst try expr(&block_scope, &block_scope.base, .{ .ty = .address_space_type }, var_decl.ast.addrspace_node); 3731 }; 3732 const section_inst: Zir.Inst.Ref = if (var_decl.ast.section_node == 0) .none else inst: { 3733 break :inst try comptimeExpr(&block_scope, &block_scope.base, .{ .ty = .const_slice_u8_type }, var_decl.ast.section_node); 3734 }; 3735 const has_section_or_addrspace = section_inst != .none or addrspace_inst != .none; 3736 wip_members.nextDecl(is_pub, is_export, align_inst != .none, has_section_or_addrspace); 3737 3738 const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: { 3739 if (!is_mutable) { 3740 return astgen.failTok(tok, "threadlocal variable cannot be constant", .{}); 3741 } 3742 break :blk true; 3743 } else false; 3744 3745 const lib_name: u32 = if (var_decl.lib_name) |lib_name_token| blk: { 3746 const lib_name_str = try astgen.strLitAsString(lib_name_token); 3747 break :blk lib_name_str.index; 3748 } else 0; 3749 3750 const doc_comment_index = try astgen.docCommentAsString(var_decl.firstToken()); 3751 3752 assert(var_decl.comptime_token == null); // handled by parser 3753 3754 const var_inst: Zir.Inst.Ref = if (var_decl.ast.init_node != 0) vi: { 3755 if (is_extern) { 3756 return astgen.failNode( 3757 var_decl.ast.init_node, 3758 "extern variables have no initializers", 3759 .{}, 3760 ); 3761 } 3762 3763 const type_inst: Zir.Inst.Ref = if (var_decl.ast.type_node != 0) 3764 try expr( 3765 &block_scope, 3766 &block_scope.base, 3767 .{ .ty = .type_type }, 3768 var_decl.ast.type_node, 3769 ) 3770 else 3771 .none; 3772 3773 const init_inst = try expr( 3774 &block_scope, 3775 &block_scope.base, 3776 if (type_inst != .none) .{ .ty = type_inst } else .none, 3777 var_decl.ast.init_node, 3778 ); 3779 3780 if (is_mutable) { 3781 const var_inst = try block_scope.addVar(.{ 3782 .var_type = type_inst, 3783 .lib_name = 0, 3784 .align_inst = .none, // passed via the decls data 3785 .init = init_inst, 3786 .is_extern = false, 3787 .is_threadlocal = is_threadlocal, 3788 }); 3789 break :vi var_inst; 3790 } else { 3791 break :vi init_inst; 3792 } 3793 } else if (!is_extern) { 3794 return astgen.failNode(node, "variables must be initialized", .{}); 3795 } else if (var_decl.ast.type_node != 0) vi: { 3796 // Extern variable which has an explicit type. 3797 const type_inst = try typeExpr(&block_scope, &block_scope.base, var_decl.ast.type_node); 3798 3799 const var_inst = try block_scope.addVar(.{ 3800 .var_type = type_inst, 3801 .lib_name = lib_name, 3802 .align_inst = .none, // passed via the decls data 3803 .init = .none, 3804 .is_extern = true, 3805 .is_threadlocal = is_threadlocal, 3806 }); 3807 break :vi var_inst; 3808 } else { 3809 return astgen.failNode(node, "unable to infer variable type", .{}); 3810 }; 3811 // We do this at the end so that the instruction index marks the end 3812 // range of a top level declaration. 3813 _ = try block_scope.addBreak(.break_inline, block_inst, var_inst); 3814 try block_scope.setBlockBody(block_inst); 3815 3816 { 3817 const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); 3818 const casted = @bitCast([4]u32, contents_hash); 3819 wip_members.appendToDeclSlice(&casted); 3820 } 3821 { 3822 const line_delta = block_scope.decl_line - gz.decl_line; 3823 wip_members.appendToDecl(line_delta); 3824 } 3825 wip_members.appendToDecl(name_str_index); 3826 wip_members.appendToDecl(block_inst); 3827 wip_members.appendToDecl(doc_comment_index); // doc_comment wip 3828 if (align_inst != .none) { 3829 wip_members.appendToDecl(@enumToInt(align_inst)); 3830 } 3831 if (has_section_or_addrspace) { 3832 wip_members.appendToDecl(@enumToInt(section_inst)); 3833 wip_members.appendToDecl(@enumToInt(addrspace_inst)); 3834 } 3835 } 3836 3837 fn comptimeDecl( 3838 astgen: *AstGen, 3839 gz: *GenZir, 3840 scope: *Scope, 3841 wip_members: *WipMembers, 3842 node: Ast.Node.Index, 3843 ) InnerError!void { 3844 const tree = astgen.tree; 3845 const node_datas = tree.nodes.items(.data); 3846 const body_node = node_datas[node].lhs; 3847 3848 // Up top so the ZIR instruction index marks the start range of this 3849 // top-level declaration. 3850 const block_inst = try gz.makeBlockInst(.block_inline, node); 3851 wip_members.nextDecl(false, false, false, false); 3852 astgen.advanceSourceCursorToNode(node); 3853 3854 var decl_block: GenZir = .{ 3855 .force_comptime = true, 3856 .in_defer = false, 3857 .decl_node_index = node, 3858 .decl_line = astgen.source_line, 3859 .parent = scope, 3860 .astgen = astgen, 3861 .instructions = gz.instructions, 3862 .instructions_top = gz.instructions.items.len, 3863 }; 3864 defer decl_block.unstack(); 3865 3866 const block_result = try expr(&decl_block, &decl_block.base, .none, body_node); 3867 if (decl_block.isEmpty() or !decl_block.refIsNoReturn(block_result)) { 3868 _ = try decl_block.addBreak(.break_inline, block_inst, .void_value); 3869 } 3870 try decl_block.setBlockBody(block_inst); 3871 3872 { 3873 const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); 3874 const casted = @bitCast([4]u32, contents_hash); 3875 wip_members.appendToDeclSlice(&casted); 3876 } 3877 { 3878 const line_delta = decl_block.decl_line - gz.decl_line; 3879 wip_members.appendToDecl(line_delta); 3880 } 3881 wip_members.appendToDecl(0); 3882 wip_members.appendToDecl(block_inst); 3883 wip_members.appendToDecl(0); // no doc comments on comptime decls 3884 } 3885 3886 fn usingnamespaceDecl( 3887 astgen: *AstGen, 3888 gz: *GenZir, 3889 scope: *Scope, 3890 wip_members: *WipMembers, 3891 node: Ast.Node.Index, 3892 ) InnerError!void { 3893 const tree = astgen.tree; 3894 const node_datas = tree.nodes.items(.data); 3895 3896 const type_expr = node_datas[node].lhs; 3897 const is_pub = blk: { 3898 const main_tokens = tree.nodes.items(.main_token); 3899 const token_tags = tree.tokens.items(.tag); 3900 const main_token = main_tokens[node]; 3901 break :blk (main_token > 0 and token_tags[main_token - 1] == .keyword_pub); 3902 }; 3903 // Up top so the ZIR instruction index marks the start range of this 3904 // top-level declaration. 3905 const block_inst = try gz.makeBlockInst(.block_inline, node); 3906 wip_members.nextDecl(is_pub, true, false, false); 3907 astgen.advanceSourceCursorToNode(node); 3908 3909 var decl_block: GenZir = .{ 3910 .force_comptime = true, 3911 .in_defer = false, 3912 .decl_node_index = node, 3913 .decl_line = astgen.source_line, 3914 .parent = scope, 3915 .astgen = astgen, 3916 .instructions = gz.instructions, 3917 .instructions_top = gz.instructions.items.len, 3918 }; 3919 defer decl_block.unstack(); 3920 3921 const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr); 3922 _ = try decl_block.addBreak(.break_inline, block_inst, namespace_inst); 3923 try decl_block.setBlockBody(block_inst); 3924 3925 { 3926 const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); 3927 const casted = @bitCast([4]u32, contents_hash); 3928 wip_members.appendToDeclSlice(&casted); 3929 } 3930 { 3931 const line_delta = decl_block.decl_line - gz.decl_line; 3932 wip_members.appendToDecl(line_delta); 3933 } 3934 wip_members.appendToDecl(0); 3935 wip_members.appendToDecl(block_inst); 3936 wip_members.appendToDecl(0); // no doc comments on usingnamespace decls 3937 } 3938 3939 fn testDecl( 3940 astgen: *AstGen, 3941 gz: *GenZir, 3942 scope: *Scope, 3943 wip_members: *WipMembers, 3944 node: Ast.Node.Index, 3945 ) InnerError!void { 3946 const tree = astgen.tree; 3947 const node_datas = tree.nodes.items(.data); 3948 const body_node = node_datas[node].rhs; 3949 3950 // Up top so the ZIR instruction index marks the start range of this 3951 // top-level declaration. 3952 const block_inst = try gz.makeBlockInst(.block_inline, node); 3953 3954 wip_members.nextDecl(false, false, false, false); 3955 astgen.advanceSourceCursorToNode(node); 3956 3957 var decl_block: GenZir = .{ 3958 .force_comptime = true, 3959 .in_defer = false, 3960 .decl_node_index = node, 3961 .decl_line = astgen.source_line, 3962 .parent = scope, 3963 .astgen = astgen, 3964 .instructions = gz.instructions, 3965 .instructions_top = gz.instructions.items.len, 3966 }; 3967 defer decl_block.unstack(); 3968 3969 const main_tokens = tree.nodes.items(.main_token); 3970 const token_tags = tree.tokens.items(.tag); 3971 const test_token = main_tokens[node]; 3972 const test_name_token = test_token + 1; 3973 const test_name_token_tag = token_tags[test_name_token]; 3974 const is_decltest = test_name_token_tag == .identifier; 3975 const test_name: u32 = blk: { 3976 if (test_name_token_tag == .string_literal) { 3977 break :blk try astgen.testNameString(test_name_token); 3978 } else if (test_name_token_tag == .identifier) { 3979 const ident_name_raw = tree.tokenSlice(test_name_token); 3980 3981 if (mem.eql(u8, ident_name_raw, "_")) return astgen.failTok(test_name_token, "'_' used as an identifier without @\"_\" syntax", .{}); 3982 3983 // if not @"" syntax, just use raw token slice 3984 if (ident_name_raw[0] != '@') { 3985 if (primitives.get(ident_name_raw)) |_| return astgen.failTok(test_name_token, "cannot test a primitive", .{}); 3986 3987 if (ident_name_raw.len >= 2) integer: { 3988 const first_c = ident_name_raw[0]; 3989 if (first_c == 'i' or first_c == 'u') { 3990 _ = switch (first_c == 'i') { 3991 true => .signed, 3992 false => .unsigned, 3993 }; 3994 _ = parseBitCount(ident_name_raw[1..]) catch |err| switch (err) { 3995 error.Overflow => return astgen.failTok( 3996 test_name_token, 3997 "primitive integer type '{s}' exceeds maximum bit width of 65535", 3998 .{ident_name_raw}, 3999 ), 4000 error.InvalidCharacter => break :integer, 4001 }; 4002 return astgen.failTok(test_name_token, "cannot test a primitive", .{}); 4003 } 4004 } 4005 } 4006 4007 // Local variables, including function parameters. 4008 const name_str_index = try astgen.identAsString(test_name_token); 4009 var s = scope; 4010 var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already 4011 var num_namespaces_out: u32 = 0; 4012 var capturing_namespace: ?*Scope.Namespace = null; 4013 while (true) switch (s.tag) { 4014 .local_val, .local_ptr => unreachable, // a test cannot be in a local scope 4015 .gen_zir => s = s.cast(GenZir).?.parent, 4016 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, 4017 .namespace => { 4018 const ns = s.cast(Scope.Namespace).?; 4019 if (ns.decls.get(name_str_index)) |i| { 4020 if (found_already) |f| { 4021 return astgen.failTokNotes(test_name_token, "ambiguous reference", .{}, &.{ 4022 try astgen.errNoteNode(f, "declared here", .{}), 4023 try astgen.errNoteNode(i, "also declared here", .{}), 4024 }); 4025 } 4026 // We found a match but must continue looking for ambiguous references to decls. 4027 found_already = i; 4028 } 4029 num_namespaces_out += 1; 4030 capturing_namespace = ns; 4031 s = ns.parent; 4032 }, 4033 .top => break, 4034 }; 4035 if (found_already == null) { 4036 const ident_name = try astgen.identifierTokenString(test_name_token); 4037 return astgen.failTok(test_name_token, "use of undeclared identifier '{s}'", .{ident_name}); 4038 } 4039 4040 break :blk name_str_index; 4041 } 4042 // String table index 1 has a special meaning here of test decl with no name. 4043 break :blk 1; 4044 }; 4045 4046 var fn_block: GenZir = .{ 4047 .force_comptime = false, 4048 .in_defer = false, 4049 .decl_node_index = node, 4050 .decl_line = decl_block.decl_line, 4051 .parent = &decl_block.base, 4052 .astgen = astgen, 4053 .instructions = decl_block.instructions, 4054 .instructions_top = decl_block.instructions.items.len, 4055 }; 4056 defer fn_block.unstack(); 4057 4058 const prev_fn_block = astgen.fn_block; 4059 astgen.fn_block = &fn_block; 4060 defer astgen.fn_block = prev_fn_block; 4061 4062 astgen.advanceSourceCursorToNode(body_node); 4063 const lbrace_line = astgen.source_line - decl_block.decl_line; 4064 const lbrace_column = astgen.source_column; 4065 4066 const block_result = try expr(&fn_block, &fn_block.base, .none, body_node); 4067 if (fn_block.isEmpty() or !fn_block.refIsNoReturn(block_result)) { 4068 // Since we are adding the return instruction here, we must handle the coercion. 4069 // We do this by using the `ret_tok` instruction. 4070 _ = try fn_block.addUnTok(.ret_tok, .void_value, tree.lastToken(body_node)); 4071 } 4072 4073 const func_inst = try decl_block.addFunc(.{ 4074 .src_node = node, 4075 4076 .cc_ref = .none, 4077 .cc_gz = null, 4078 .align_ref = .none, 4079 .align_gz = null, 4080 .ret_ref = .void_type, 4081 .ret_gz = null, 4082 .section_ref = .none, 4083 .section_gz = null, 4084 .addrspace_ref = .none, 4085 .addrspace_gz = null, 4086 4087 .lbrace_line = lbrace_line, 4088 .lbrace_column = lbrace_column, 4089 .param_block = block_inst, 4090 .body_gz = &fn_block, 4091 .lib_name = 0, 4092 .is_var_args = false, 4093 .is_inferred_error = true, 4094 .is_test = true, 4095 .is_extern = false, 4096 .noalias_bits = 0, 4097 }); 4098 4099 _ = try decl_block.addBreak(.break_inline, block_inst, func_inst); 4100 try decl_block.setBlockBody(block_inst); 4101 4102 { 4103 const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); 4104 const casted = @bitCast([4]u32, contents_hash); 4105 wip_members.appendToDeclSlice(&casted); 4106 } 4107 { 4108 const line_delta = decl_block.decl_line - gz.decl_line; 4109 wip_members.appendToDecl(line_delta); 4110 } 4111 if (is_decltest) 4112 wip_members.appendToDecl(2) // 2 here means that it is a decltest, look at doc comment for name 4113 else 4114 wip_members.appendToDecl(test_name); 4115 wip_members.appendToDecl(block_inst); 4116 if (is_decltest) 4117 wip_members.appendToDecl(test_name) // the doc comment on a decltest represents it's name 4118 else 4119 wip_members.appendToDecl(0); // no doc comments on test decls 4120 } 4121 4122 fn structDeclInner( 4123 gz: *GenZir, 4124 scope: *Scope, 4125 node: Ast.Node.Index, 4126 container_decl: Ast.full.ContainerDecl, 4127 layout: std.builtin.Type.ContainerLayout, 4128 ) InnerError!Zir.Inst.Ref { 4129 const decl_inst = try gz.reserveInstructionIndex(); 4130 4131 if (container_decl.ast.members.len == 0) { 4132 try gz.setStruct(decl_inst, .{ 4133 .src_node = node, 4134 .layout = layout, 4135 .fields_len = 0, 4136 .decls_len = 0, 4137 .known_non_opv = false, 4138 .known_comptime_only = false, 4139 }); 4140 return indexToRef(decl_inst); 4141 } 4142 4143 const astgen = gz.astgen; 4144 const gpa = astgen.gpa; 4145 const tree = astgen.tree; 4146 4147 var namespace: Scope.Namespace = .{ 4148 .parent = scope, 4149 .node = node, 4150 .inst = decl_inst, 4151 .declaring_gz = gz, 4152 }; 4153 defer namespace.deinit(gpa); 4154 4155 // The struct_decl instruction introduces a scope in which the decls of the struct 4156 // are in scope, so that field types, alignments, and default value expressions 4157 // can refer to decls within the struct itself. 4158 astgen.advanceSourceCursorToNode(node); 4159 var block_scope: GenZir = .{ 4160 .parent = &namespace.base, 4161 .decl_node_index = node, 4162 .decl_line = astgen.source_line, 4163 .astgen = astgen, 4164 .force_comptime = true, 4165 .in_defer = false, 4166 .instructions = gz.instructions, 4167 .instructions_top = gz.instructions.items.len, 4168 }; 4169 defer block_scope.unstack(); 4170 4171 const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members); 4172 const field_count = @intCast(u32, container_decl.ast.members.len - decl_count); 4173 4174 const bits_per_field = 4; 4175 const max_field_size = 5; 4176 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size); 4177 defer wip_members.deinit(); 4178 4179 // We will use the scratch buffer, starting here, for the bodies: 4180 // bodies: { // for every fields_len 4181 // field_type_body_inst: Inst, // for each field_type_body_len 4182 // align_body_inst: Inst, // for each align_body_len 4183 // init_body_inst: Inst, // for each init_body_len 4184 // } 4185 // Note that the scratch buffer is simultaneously being used by WipMembers, however 4186 // it will not access any elements beyond this point in the ArrayList. It also 4187 // accesses via the ArrayList items field so it can handle the scratch buffer being 4188 // reallocated. 4189 // No defer needed here because it is handled by `wip_members.deinit()` above. 4190 const bodies_start = astgen.scratch.items.len; 4191 4192 var known_non_opv = false; 4193 var known_comptime_only = false; 4194 for (container_decl.ast.members) |member_node| { 4195 const member = switch (try containerMember(gz, &namespace.base, &wip_members, member_node)) { 4196 .decl => continue, 4197 .field => |field| field, 4198 }; 4199 4200 const field_name = try astgen.identAsString(member.ast.name_token); 4201 wip_members.appendToField(field_name); 4202 4203 const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); 4204 wip_members.appendToField(doc_comment_index); 4205 4206 if (member.ast.type_expr == 0) { 4207 return astgen.failTok(member.ast.name_token, "struct field missing type", .{}); 4208 } 4209 4210 const field_type = try typeExpr(&block_scope, &namespace.base, member.ast.type_expr); 4211 const have_type_body = !block_scope.isEmpty(); 4212 const have_align = member.ast.align_expr != 0; 4213 const have_value = member.ast.value_expr != 0; 4214 const is_comptime = member.comptime_token != null; 4215 4216 if (!is_comptime) { 4217 known_non_opv = known_non_opv or 4218 nodeImpliesMoreThanOnePossibleValue(tree, member.ast.type_expr); 4219 known_comptime_only = known_comptime_only or 4220 nodeImpliesComptimeOnly(tree, member.ast.type_expr); 4221 } 4222 wip_members.nextField(bits_per_field, .{ have_align, have_value, is_comptime, have_type_body }); 4223 4224 if (have_type_body) { 4225 if (!block_scope.endsWithNoReturn()) { 4226 _ = try block_scope.addBreak(.break_inline, decl_inst, field_type); 4227 } 4228 const body = block_scope.instructionsSlice(); 4229 const old_scratch_len = astgen.scratch.items.len; 4230 try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body)); 4231 appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body); 4232 wip_members.appendToField(@intCast(u32, astgen.scratch.items.len - old_scratch_len)); 4233 block_scope.instructions.items.len = block_scope.instructions_top; 4234 } else { 4235 wip_members.appendToField(@enumToInt(field_type)); 4236 } 4237 4238 if (have_align) { 4239 if (layout == .Packed) { 4240 try astgen.appendErrorNode(member.ast.align_expr, "unable to override alignment of packed struct fields", .{}); 4241 } 4242 const align_ref = try expr(&block_scope, &namespace.base, coerced_align_rl, member.ast.align_expr); 4243 if (!block_scope.endsWithNoReturn()) { 4244 _ = try block_scope.addBreak(.break_inline, decl_inst, align_ref); 4245 } 4246 const body = block_scope.instructionsSlice(); 4247 const old_scratch_len = astgen.scratch.items.len; 4248 try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body)); 4249 appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body); 4250 wip_members.appendToField(@intCast(u32, astgen.scratch.items.len - old_scratch_len)); 4251 block_scope.instructions.items.len = block_scope.instructions_top; 4252 } 4253 4254 if (have_value) { 4255 const rl: ResultLoc = if (field_type == .none) .none else .{ .coerced_ty = field_type }; 4256 4257 const default_inst = try expr(&block_scope, &namespace.base, rl, member.ast.value_expr); 4258 if (!block_scope.endsWithNoReturn()) { 4259 _ = try block_scope.addBreak(.break_inline, decl_inst, default_inst); 4260 } 4261 const body = block_scope.instructionsSlice(); 4262 const old_scratch_len = astgen.scratch.items.len; 4263 try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body)); 4264 appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body); 4265 wip_members.appendToField(@intCast(u32, astgen.scratch.items.len - old_scratch_len)); 4266 block_scope.instructions.items.len = block_scope.instructions_top; 4267 } else if (member.comptime_token) |comptime_token| { 4268 return astgen.failTok(comptime_token, "comptime field without default initialization value", .{}); 4269 } 4270 } 4271 4272 try gz.setStruct(decl_inst, .{ 4273 .src_node = node, 4274 .layout = layout, 4275 .fields_len = field_count, 4276 .decls_len = decl_count, 4277 .known_non_opv = known_non_opv, 4278 .known_comptime_only = known_comptime_only, 4279 }); 4280 4281 wip_members.finishBits(bits_per_field); 4282 const decls_slice = wip_members.declsSlice(); 4283 const fields_slice = wip_members.fieldsSlice(); 4284 const bodies_slice = astgen.scratch.items[bodies_start..]; 4285 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + fields_slice.len + bodies_slice.len); 4286 astgen.extra.appendSliceAssumeCapacity(decls_slice); 4287 astgen.extra.appendSliceAssumeCapacity(fields_slice); 4288 astgen.extra.appendSliceAssumeCapacity(bodies_slice); 4289 4290 block_scope.unstack(); 4291 try gz.addNamespaceCaptures(&namespace); 4292 return indexToRef(decl_inst); 4293 } 4294 4295 fn unionDeclInner( 4296 gz: *GenZir, 4297 scope: *Scope, 4298 node: Ast.Node.Index, 4299 members: []const Ast.Node.Index, 4300 layout: std.builtin.Type.ContainerLayout, 4301 arg_node: Ast.Node.Index, 4302 auto_enum_tok: ?Ast.TokenIndex, 4303 ) InnerError!Zir.Inst.Ref { 4304 const decl_inst = try gz.reserveInstructionIndex(); 4305 4306 const astgen = gz.astgen; 4307 const gpa = astgen.gpa; 4308 4309 var namespace: Scope.Namespace = .{ 4310 .parent = scope, 4311 .node = node, 4312 .inst = decl_inst, 4313 .declaring_gz = gz, 4314 }; 4315 defer namespace.deinit(gpa); 4316 4317 // The union_decl instruction introduces a scope in which the decls of the union 4318 // are in scope, so that field types, alignments, and default value expressions 4319 // can refer to decls within the union itself. 4320 astgen.advanceSourceCursorToNode(node); 4321 var block_scope: GenZir = .{ 4322 .parent = &namespace.base, 4323 .decl_node_index = node, 4324 .decl_line = astgen.source_line, 4325 .astgen = astgen, 4326 .force_comptime = true, 4327 .in_defer = false, 4328 .instructions = gz.instructions, 4329 .instructions_top = gz.instructions.items.len, 4330 }; 4331 defer block_scope.unstack(); 4332 4333 const decl_count = try astgen.scanDecls(&namespace, members); 4334 const field_count = @intCast(u32, members.len - decl_count); 4335 4336 if (layout != .Auto and (auto_enum_tok != null or arg_node != 0)) { 4337 const layout_str = if (layout == .Extern) "extern" else "packed"; 4338 if (arg_node != 0) { 4339 return astgen.failNode(arg_node, "{s} union does not support enum tag type", .{layout_str}); 4340 } else { 4341 return astgen.failTok(auto_enum_tok.?, "{s} union does not support enum tag type", .{layout_str}); 4342 } 4343 } 4344 4345 const arg_inst: Zir.Inst.Ref = if (arg_node != 0) 4346 try typeExpr(&block_scope, &namespace.base, arg_node) 4347 else 4348 .none; 4349 4350 const bits_per_field = 4; 4351 const max_field_size = 5; 4352 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size); 4353 defer wip_members.deinit(); 4354 4355 for (members) |member_node| { 4356 const member = switch (try containerMember(gz, &namespace.base, &wip_members, member_node)) { 4357 .decl => continue, 4358 .field => |field| field, 4359 }; 4360 if (member.comptime_token) |comptime_token| { 4361 return astgen.failTok(comptime_token, "union fields cannot be marked comptime", .{}); 4362 } 4363 4364 const field_name = try astgen.identAsString(member.ast.name_token); 4365 wip_members.appendToField(field_name); 4366 4367 const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); 4368 wip_members.appendToField(doc_comment_index); 4369 4370 const have_type = member.ast.type_expr != 0; 4371 const have_align = member.ast.align_expr != 0; 4372 const have_value = member.ast.value_expr != 0; 4373 const unused = false; 4374 wip_members.nextField(bits_per_field, .{ have_type, have_align, have_value, unused }); 4375 4376 if (have_type) { 4377 const field_type = try typeExpr(&block_scope, &namespace.base, member.ast.type_expr); 4378 wip_members.appendToField(@enumToInt(field_type)); 4379 } else if (arg_inst == .none and auto_enum_tok == null) { 4380 return astgen.failNode(member_node, "union field missing type", .{}); 4381 } 4382 if (have_align) { 4383 const align_inst = try expr(&block_scope, &block_scope.base, .{ .ty = .u32_type }, member.ast.align_expr); 4384 wip_members.appendToField(@enumToInt(align_inst)); 4385 } 4386 if (have_value) { 4387 if (arg_inst == .none) { 4388 return astgen.failNodeNotes( 4389 node, 4390 "explicitly valued tagged union missing integer tag type", 4391 .{}, 4392 &[_]u32{ 4393 try astgen.errNoteNode( 4394 member.ast.value_expr, 4395 "tag value specified here", 4396 .{}, 4397 ), 4398 }, 4399 ); 4400 } 4401 if (auto_enum_tok == null) { 4402 return astgen.failNodeNotes( 4403 node, 4404 "explicitly valued tagged union requires inferred enum tag type", 4405 .{}, 4406 &[_]u32{ 4407 try astgen.errNoteNode( 4408 member.ast.value_expr, 4409 "tag value specified here", 4410 .{}, 4411 ), 4412 }, 4413 ); 4414 } 4415 const tag_value = try expr(&block_scope, &block_scope.base, .{ .ty = arg_inst }, member.ast.value_expr); 4416 wip_members.appendToField(@enumToInt(tag_value)); 4417 } 4418 } 4419 if (field_count == 0) { 4420 return astgen.failNode(node, "union declarations must have at least one tag", .{}); 4421 } 4422 4423 if (!block_scope.isEmpty()) { 4424 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); 4425 } 4426 4427 const body = block_scope.instructionsSlice(); 4428 const body_len = astgen.countBodyLenAfterFixups(body); 4429 4430 try gz.setUnion(decl_inst, .{ 4431 .src_node = node, 4432 .layout = layout, 4433 .tag_type = arg_inst, 4434 .body_len = body_len, 4435 .fields_len = field_count, 4436 .decls_len = decl_count, 4437 .auto_enum_tag = auto_enum_tok != null, 4438 }); 4439 4440 wip_members.finishBits(bits_per_field); 4441 const decls_slice = wip_members.declsSlice(); 4442 const fields_slice = wip_members.fieldsSlice(); 4443 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + body_len + fields_slice.len); 4444 astgen.extra.appendSliceAssumeCapacity(decls_slice); 4445 astgen.appendBodyWithFixups(body); 4446 astgen.extra.appendSliceAssumeCapacity(fields_slice); 4447 4448 block_scope.unstack(); 4449 try gz.addNamespaceCaptures(&namespace); 4450 return indexToRef(decl_inst); 4451 } 4452 4453 fn containerDecl( 4454 gz: *GenZir, 4455 scope: *Scope, 4456 rl: ResultLoc, 4457 node: Ast.Node.Index, 4458 container_decl: Ast.full.ContainerDecl, 4459 ) InnerError!Zir.Inst.Ref { 4460 const astgen = gz.astgen; 4461 const gpa = astgen.gpa; 4462 const tree = astgen.tree; 4463 const token_tags = tree.tokens.items(.tag); 4464 const node_tags = tree.nodes.items(.tag); 4465 4466 const prev_fn_block = astgen.fn_block; 4467 astgen.fn_block = null; 4468 defer astgen.fn_block = prev_fn_block; 4469 4470 // We must not create any types until Sema. Here the goal is only to generate 4471 // ZIR for all the field types, alignments, and default value expressions. 4472 4473 switch (token_tags[container_decl.ast.main_token]) { 4474 .keyword_struct => { 4475 const layout = if (container_decl.layout_token) |t| switch (token_tags[t]) { 4476 .keyword_packed => std.builtin.Type.ContainerLayout.Packed, 4477 .keyword_extern => std.builtin.Type.ContainerLayout.Extern, 4478 else => unreachable, 4479 } else std.builtin.Type.ContainerLayout.Auto; 4480 4481 assert(container_decl.ast.arg == 0); 4482 4483 const result = try structDeclInner(gz, scope, node, container_decl, layout); 4484 return rvalue(gz, rl, result, node); 4485 }, 4486 .keyword_union => { 4487 const layout = if (container_decl.layout_token) |t| switch (token_tags[t]) { 4488 .keyword_packed => std.builtin.Type.ContainerLayout.Packed, 4489 .keyword_extern => std.builtin.Type.ContainerLayout.Extern, 4490 else => unreachable, 4491 } else std.builtin.Type.ContainerLayout.Auto; 4492 4493 const result = try unionDeclInner(gz, scope, node, container_decl.ast.members, layout, container_decl.ast.arg, container_decl.ast.enum_token); 4494 return rvalue(gz, rl, result, node); 4495 }, 4496 .keyword_enum => { 4497 if (container_decl.layout_token) |t| { 4498 return astgen.failTok(t, "enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type", .{}); 4499 } 4500 // Count total fields as well as how many have explicitly provided tag values. 4501 const counts = blk: { 4502 var values: usize = 0; 4503 var total_fields: usize = 0; 4504 var decls: usize = 0; 4505 var nonexhaustive_node: Ast.Node.Index = 0; 4506 var nonfinal_nonexhaustive = false; 4507 for (container_decl.ast.members) |member_node| { 4508 const member = switch (node_tags[member_node]) { 4509 .container_field_init => tree.containerFieldInit(member_node), 4510 .container_field_align => tree.containerFieldAlign(member_node), 4511 .container_field => tree.containerField(member_node), 4512 else => { 4513 decls += 1; 4514 continue; 4515 }, 4516 }; 4517 if (member.comptime_token) |comptime_token| { 4518 return astgen.failTok(comptime_token, "enum fields cannot be marked comptime", .{}); 4519 } 4520 if (member.ast.type_expr != 0) { 4521 return astgen.failNodeNotes( 4522 member.ast.type_expr, 4523 "enum fields do not have types", 4524 .{}, 4525 &[_]u32{ 4526 try astgen.errNoteNode( 4527 node, 4528 "consider 'union(enum)' here to make it a tagged union", 4529 .{}, 4530 ), 4531 }, 4532 ); 4533 } 4534 // Alignment expressions in enums are caught by the parser. 4535 assert(member.ast.align_expr == 0); 4536 4537 const name_token = member.ast.name_token; 4538 if (mem.eql(u8, tree.tokenSlice(name_token), "_")) { 4539 if (nonexhaustive_node != 0) { 4540 return astgen.failNodeNotes( 4541 member_node, 4542 "redundant non-exhaustive enum mark", 4543 .{}, 4544 &[_]u32{ 4545 try astgen.errNoteNode( 4546 nonexhaustive_node, 4547 "other mark here", 4548 .{}, 4549 ), 4550 }, 4551 ); 4552 } 4553 nonexhaustive_node = member_node; 4554 if (member.ast.value_expr != 0) { 4555 return astgen.failNode(member.ast.value_expr, "'_' is used to mark an enum as non-exhaustive and cannot be assigned a value", .{}); 4556 } 4557 continue; 4558 } else if (nonexhaustive_node != 0) { 4559 nonfinal_nonexhaustive = true; 4560 } 4561 total_fields += 1; 4562 if (member.ast.value_expr != 0) { 4563 if (container_decl.ast.arg == 0) { 4564 return astgen.failNode(member.ast.value_expr, "value assigned to enum tag with inferred tag type", .{}); 4565 } 4566 values += 1; 4567 } 4568 } 4569 if (nonfinal_nonexhaustive) { 4570 return astgen.failNode(nonexhaustive_node, "'_' field of non-exhaustive enum must be last", .{}); 4571 } 4572 break :blk .{ 4573 .total_fields = total_fields, 4574 .values = values, 4575 .decls = decls, 4576 .nonexhaustive_node = nonexhaustive_node, 4577 }; 4578 }; 4579 if (counts.total_fields == 0 and counts.nonexhaustive_node == 0) { 4580 // One can construct an enum with no tags, and it functions the same as `noreturn`. But 4581 // this is only useful for generic code; when explicitly using `enum {}` syntax, there 4582 // must be at least one tag. 4583 try astgen.appendErrorNode(node, "enum declarations must have at least one tag", .{}); 4584 } 4585 if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) { 4586 try astgen.appendErrorNodeNotes( 4587 node, 4588 "non-exhaustive enum missing integer tag type", 4589 .{}, 4590 &[_]u32{ 4591 try astgen.errNoteNode( 4592 counts.nonexhaustive_node, 4593 "marked non-exhaustive here", 4594 .{}, 4595 ), 4596 }, 4597 ); 4598 } 4599 // In this case we must generate ZIR code for the tag values, similar to 4600 // how structs are handled above. 4601 const nonexhaustive = counts.nonexhaustive_node != 0; 4602 4603 const decl_inst = try gz.reserveInstructionIndex(); 4604 4605 var namespace: Scope.Namespace = .{ 4606 .parent = scope, 4607 .node = node, 4608 .inst = decl_inst, 4609 .declaring_gz = gz, 4610 }; 4611 defer namespace.deinit(gpa); 4612 4613 // The enum_decl instruction introduces a scope in which the decls of the enum 4614 // are in scope, so that tag values can refer to decls within the enum itself. 4615 astgen.advanceSourceCursorToNode(node); 4616 var block_scope: GenZir = .{ 4617 .parent = &namespace.base, 4618 .decl_node_index = node, 4619 .decl_line = astgen.source_line, 4620 .astgen = astgen, 4621 .force_comptime = true, 4622 .in_defer = false, 4623 .instructions = gz.instructions, 4624 .instructions_top = gz.instructions.items.len, 4625 }; 4626 defer block_scope.unstack(); 4627 4628 _ = try astgen.scanDecls(&namespace, container_decl.ast.members); 4629 4630 const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0) 4631 try comptimeExpr(&block_scope, &namespace.base, .{ .ty = .type_type }, container_decl.ast.arg) 4632 else 4633 .none; 4634 4635 const bits_per_field = 1; 4636 const max_field_size = 3; 4637 var wip_members = try WipMembers.init(gpa, &astgen.scratch, @intCast(u32, counts.decls), @intCast(u32, counts.total_fields), bits_per_field, max_field_size); 4638 defer wip_members.deinit(); 4639 4640 for (container_decl.ast.members) |member_node| { 4641 if (member_node == counts.nonexhaustive_node) 4642 continue; 4643 const member = switch (try containerMember(gz, &namespace.base, &wip_members, member_node)) { 4644 .decl => continue, 4645 .field => |field| field, 4646 }; 4647 assert(member.comptime_token == null); 4648 assert(member.ast.type_expr == 0); 4649 assert(member.ast.align_expr == 0); 4650 4651 const field_name = try astgen.identAsString(member.ast.name_token); 4652 wip_members.appendToField(field_name); 4653 4654 const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); 4655 wip_members.appendToField(doc_comment_index); 4656 4657 const have_value = member.ast.value_expr != 0; 4658 wip_members.nextField(bits_per_field, .{have_value}); 4659 4660 if (have_value) { 4661 if (arg_inst == .none) { 4662 return astgen.failNodeNotes( 4663 node, 4664 "explicitly valued enum missing integer tag type", 4665 .{}, 4666 &[_]u32{ 4667 try astgen.errNoteNode( 4668 member.ast.value_expr, 4669 "tag value specified here", 4670 .{}, 4671 ), 4672 }, 4673 ); 4674 } 4675 const tag_value_inst = try expr(&block_scope, &namespace.base, .{ .ty = arg_inst }, member.ast.value_expr); 4676 wip_members.appendToField(@enumToInt(tag_value_inst)); 4677 } 4678 } 4679 4680 if (!block_scope.isEmpty()) { 4681 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); 4682 } 4683 4684 const body = block_scope.instructionsSlice(); 4685 const body_len = astgen.countBodyLenAfterFixups(body); 4686 4687 try gz.setEnum(decl_inst, .{ 4688 .src_node = node, 4689 .nonexhaustive = nonexhaustive, 4690 .tag_type = arg_inst, 4691 .body_len = body_len, 4692 .fields_len = @intCast(u32, counts.total_fields), 4693 .decls_len = @intCast(u32, counts.decls), 4694 }); 4695 4696 wip_members.finishBits(bits_per_field); 4697 const decls_slice = wip_members.declsSlice(); 4698 const fields_slice = wip_members.fieldsSlice(); 4699 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + body_len + fields_slice.len); 4700 astgen.extra.appendSliceAssumeCapacity(decls_slice); 4701 astgen.appendBodyWithFixups(body); 4702 astgen.extra.appendSliceAssumeCapacity(fields_slice); 4703 4704 block_scope.unstack(); 4705 try gz.addNamespaceCaptures(&namespace); 4706 return rvalue(gz, rl, indexToRef(decl_inst), node); 4707 }, 4708 .keyword_opaque => { 4709 assert(container_decl.ast.arg == 0); 4710 4711 const decl_inst = try gz.reserveInstructionIndex(); 4712 4713 var namespace: Scope.Namespace = .{ 4714 .parent = scope, 4715 .node = node, 4716 .inst = decl_inst, 4717 .declaring_gz = gz, 4718 }; 4719 defer namespace.deinit(gpa); 4720 4721 const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members); 4722 4723 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, 0, 0, 0); 4724 defer wip_members.deinit(); 4725 4726 for (container_decl.ast.members) |member_node| { 4727 const res = try containerMember(gz, &namespace.base, &wip_members, member_node); 4728 if (res == .field) { 4729 return astgen.failNode(member_node, "opaque types cannot have fields", .{}); 4730 } 4731 } 4732 4733 try gz.setOpaque(decl_inst, .{ 4734 .src_node = node, 4735 .decls_len = decl_count, 4736 }); 4737 4738 wip_members.finishBits(0); 4739 const decls_slice = wip_members.declsSlice(); 4740 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len); 4741 astgen.extra.appendSliceAssumeCapacity(decls_slice); 4742 4743 try gz.addNamespaceCaptures(&namespace); 4744 return rvalue(gz, rl, indexToRef(decl_inst), node); 4745 }, 4746 else => unreachable, 4747 } 4748 } 4749 4750 const ContainerMemberResult = union(enum) { decl, field: Ast.full.ContainerField }; 4751 4752 fn containerMember( 4753 gz: *GenZir, 4754 scope: *Scope, 4755 wip_members: *WipMembers, 4756 member_node: Ast.Node.Index, 4757 ) InnerError!ContainerMemberResult { 4758 const astgen = gz.astgen; 4759 const tree = astgen.tree; 4760 const node_tags = tree.nodes.items(.tag); 4761 const node_datas = tree.nodes.items(.data); 4762 switch (node_tags[member_node]) { 4763 .container_field_init => return ContainerMemberResult{ .field = tree.containerFieldInit(member_node) }, 4764 .container_field_align => return ContainerMemberResult{ .field = tree.containerFieldAlign(member_node) }, 4765 .container_field => return ContainerMemberResult{ .field = tree.containerField(member_node) }, 4766 4767 .fn_decl => { 4768 const fn_proto = node_datas[member_node].lhs; 4769 const body = node_datas[member_node].rhs; 4770 switch (node_tags[fn_proto]) { 4771 .fn_proto_simple => { 4772 var params: [1]Ast.Node.Index = undefined; 4773 astgen.fnDecl(gz, scope, wip_members, member_node, body, tree.fnProtoSimple(¶ms, fn_proto)) catch |err| switch (err) { 4774 error.OutOfMemory => return error.OutOfMemory, 4775 error.AnalysisFail => {}, 4776 }; 4777 }, 4778 .fn_proto_multi => { 4779 astgen.fnDecl(gz, scope, wip_members, member_node, body, tree.fnProtoMulti(fn_proto)) catch |err| switch (err) { 4780 error.OutOfMemory => return error.OutOfMemory, 4781 error.AnalysisFail => {}, 4782 }; 4783 }, 4784 .fn_proto_one => { 4785 var params: [1]Ast.Node.Index = undefined; 4786 astgen.fnDecl(gz, scope, wip_members, member_node, body, tree.fnProtoOne(¶ms, fn_proto)) catch |err| switch (err) { 4787 error.OutOfMemory => return error.OutOfMemory, 4788 error.AnalysisFail => {}, 4789 }; 4790 }, 4791 .fn_proto => { 4792 astgen.fnDecl(gz, scope, wip_members, member_node, body, tree.fnProto(fn_proto)) catch |err| switch (err) { 4793 error.OutOfMemory => return error.OutOfMemory, 4794 error.AnalysisFail => {}, 4795 }; 4796 }, 4797 else => unreachable, 4798 } 4799 }, 4800 .fn_proto_simple => { 4801 var params: [1]Ast.Node.Index = undefined; 4802 astgen.fnDecl(gz, scope, wip_members, member_node, 0, tree.fnProtoSimple(¶ms, member_node)) catch |err| switch (err) { 4803 error.OutOfMemory => return error.OutOfMemory, 4804 error.AnalysisFail => {}, 4805 }; 4806 }, 4807 .fn_proto_multi => { 4808 astgen.fnDecl(gz, scope, wip_members, member_node, 0, tree.fnProtoMulti(member_node)) catch |err| switch (err) { 4809 error.OutOfMemory => return error.OutOfMemory, 4810 error.AnalysisFail => {}, 4811 }; 4812 }, 4813 .fn_proto_one => { 4814 var params: [1]Ast.Node.Index = undefined; 4815 astgen.fnDecl(gz, scope, wip_members, member_node, 0, tree.fnProtoOne(¶ms, member_node)) catch |err| switch (err) { 4816 error.OutOfMemory => return error.OutOfMemory, 4817 error.AnalysisFail => {}, 4818 }; 4819 }, 4820 .fn_proto => { 4821 astgen.fnDecl(gz, scope, wip_members, member_node, 0, tree.fnProto(member_node)) catch |err| switch (err) { 4822 error.OutOfMemory => return error.OutOfMemory, 4823 error.AnalysisFail => {}, 4824 }; 4825 }, 4826 4827 .global_var_decl => { 4828 astgen.globalVarDecl(gz, scope, wip_members, member_node, tree.globalVarDecl(member_node)) catch |err| switch (err) { 4829 error.OutOfMemory => return error.OutOfMemory, 4830 error.AnalysisFail => {}, 4831 }; 4832 }, 4833 .local_var_decl => { 4834 astgen.globalVarDecl(gz, scope, wip_members, member_node, tree.localVarDecl(member_node)) catch |err| switch (err) { 4835 error.OutOfMemory => return error.OutOfMemory, 4836 error.AnalysisFail => {}, 4837 }; 4838 }, 4839 .simple_var_decl => { 4840 astgen.globalVarDecl(gz, scope, wip_members, member_node, tree.simpleVarDecl(member_node)) catch |err| switch (err) { 4841 error.OutOfMemory => return error.OutOfMemory, 4842 error.AnalysisFail => {}, 4843 }; 4844 }, 4845 .aligned_var_decl => { 4846 astgen.globalVarDecl(gz, scope, wip_members, member_node, tree.alignedVarDecl(member_node)) catch |err| switch (err) { 4847 error.OutOfMemory => return error.OutOfMemory, 4848 error.AnalysisFail => {}, 4849 }; 4850 }, 4851 4852 .@"comptime" => { 4853 astgen.comptimeDecl(gz, scope, wip_members, member_node) catch |err| switch (err) { 4854 error.OutOfMemory => return error.OutOfMemory, 4855 error.AnalysisFail => {}, 4856 }; 4857 }, 4858 .@"usingnamespace" => { 4859 astgen.usingnamespaceDecl(gz, scope, wip_members, member_node) catch |err| switch (err) { 4860 error.OutOfMemory => return error.OutOfMemory, 4861 error.AnalysisFail => {}, 4862 }; 4863 }, 4864 .test_decl => { 4865 astgen.testDecl(gz, scope, wip_members, member_node) catch |err| switch (err) { 4866 error.OutOfMemory => return error.OutOfMemory, 4867 error.AnalysisFail => {}, 4868 }; 4869 }, 4870 else => unreachable, 4871 } 4872 return .decl; 4873 } 4874 4875 fn errorSetDecl(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 4876 const astgen = gz.astgen; 4877 const gpa = astgen.gpa; 4878 const tree = astgen.tree; 4879 const main_tokens = tree.nodes.items(.main_token); 4880 const token_tags = tree.tokens.items(.tag); 4881 4882 const payload_index = try reserveExtra(astgen, @typeInfo(Zir.Inst.ErrorSetDecl).Struct.fields.len); 4883 var fields_len: usize = 0; 4884 { 4885 var idents: std.AutoHashMapUnmanaged(u32, Ast.TokenIndex) = .{}; 4886 defer idents.deinit(gpa); 4887 4888 const error_token = main_tokens[node]; 4889 var tok_i = error_token + 2; 4890 while (true) : (tok_i += 1) { 4891 switch (token_tags[tok_i]) { 4892 .doc_comment, .comma => {}, 4893 .identifier => { 4894 const str_index = try astgen.identAsString(tok_i); 4895 const gop = try idents.getOrPut(gpa, str_index); 4896 if (gop.found_existing) { 4897 const name = try gpa.dupe(u8, mem.span(astgen.nullTerminatedString(str_index))); 4898 defer gpa.free(name); 4899 return astgen.failTokNotes( 4900 tok_i, 4901 "duplicate error set field '{s}'", 4902 .{name}, 4903 &[_]u32{ 4904 try astgen.errNoteTok( 4905 gop.value_ptr.*, 4906 "previous declaration here", 4907 .{}, 4908 ), 4909 }, 4910 ); 4911 } 4912 gop.value_ptr.* = tok_i; 4913 4914 try astgen.extra.ensureUnusedCapacity(gpa, 2); 4915 astgen.extra.appendAssumeCapacity(str_index); 4916 const doc_comment_index = try astgen.docCommentAsString(tok_i); 4917 astgen.extra.appendAssumeCapacity(doc_comment_index); 4918 fields_len += 1; 4919 }, 4920 .r_brace => break, 4921 else => unreachable, 4922 } 4923 } 4924 } 4925 4926 setExtra(astgen, payload_index, Zir.Inst.ErrorSetDecl{ 4927 .fields_len = @intCast(u32, fields_len), 4928 }); 4929 const result = try gz.addPlNodePayloadIndex(.error_set_decl, node, payload_index); 4930 return rvalue(gz, rl, result, node); 4931 } 4932 4933 fn tryExpr( 4934 parent_gz: *GenZir, 4935 scope: *Scope, 4936 rl: ResultLoc, 4937 node: Ast.Node.Index, 4938 operand_node: Ast.Node.Index, 4939 ) InnerError!Zir.Inst.Ref { 4940 const astgen = parent_gz.astgen; 4941 4942 const fn_block = astgen.fn_block orelse { 4943 return astgen.failNode(node, "'try' outside function scope", .{}); 4944 }; 4945 4946 if (parent_gz.in_defer) return astgen.failNode(node, "'try' not allowed inside defer expression", .{}); 4947 4948 const operand_rl: ResultLoc = switch (rl) { 4949 .ref => .ref, 4950 else => .none, 4951 }; 4952 // This could be a pointer or value depending on the `rl` parameter. 4953 const operand = try expr(parent_gz, scope, operand_rl, operand_node); 4954 const is_inline = parent_gz.force_comptime; 4955 const is_inline_bit = @as(u2, @boolToInt(is_inline)); 4956 const is_ptr_bit = @as(u2, @boolToInt(operand_rl == .ref)) << 1; 4957 const block_tag: Zir.Inst.Tag = switch (is_inline_bit | is_ptr_bit) { 4958 0b00 => .@"try", 4959 0b01 => .@"try", 4960 //0b01 => .try_inline, 4961 0b10 => .try_ptr, 4962 0b11 => .try_ptr, 4963 //0b11 => .try_ptr_inline, 4964 }; 4965 const try_inst = try parent_gz.makeBlockInst(block_tag, node); 4966 try parent_gz.instructions.append(astgen.gpa, try_inst); 4967 4968 var else_scope = parent_gz.makeSubBlock(scope); 4969 defer else_scope.unstack(); 4970 4971 const err_tag = switch (rl) { 4972 .ref => Zir.Inst.Tag.err_union_code_ptr, 4973 else => Zir.Inst.Tag.err_union_code, 4974 }; 4975 const err_code = try else_scope.addUnNode(err_tag, operand, node); 4976 try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code }); 4977 _ = try else_scope.addUnNode(.ret_node, err_code, node); 4978 4979 try else_scope.setTryBody(try_inst, operand); 4980 const result = indexToRef(try_inst); 4981 switch (rl) { 4982 .ref => return result, 4983 else => return rvalue(parent_gz, rl, result, node), 4984 } 4985 } 4986 4987 fn orelseCatchExpr( 4988 parent_gz: *GenZir, 4989 scope: *Scope, 4990 rl: ResultLoc, 4991 node: Ast.Node.Index, 4992 lhs: Ast.Node.Index, 4993 cond_op: Zir.Inst.Tag, 4994 unwrap_op: Zir.Inst.Tag, 4995 unwrap_code_op: Zir.Inst.Tag, 4996 rhs: Ast.Node.Index, 4997 payload_token: ?Ast.TokenIndex, 4998 ) InnerError!Zir.Inst.Ref { 4999 const astgen = parent_gz.astgen; 5000 const tree = astgen.tree; 5001 5002 var block_scope = parent_gz.makeSubBlock(scope); 5003 block_scope.setBreakResultLoc(rl); 5004 defer block_scope.unstack(); 5005 5006 const operand_rl: ResultLoc = switch (block_scope.break_result_loc) { 5007 .ref => .ref, 5008 else => .none, 5009 }; 5010 block_scope.break_count += 1; 5011 // This could be a pointer or value depending on the `operand_rl` parameter. 5012 // We cannot use `block_scope.break_result_loc` because that has the bare 5013 // type, whereas this expression has the optional type. Later we make 5014 // up for this fact by calling rvalue on the else branch. 5015 const operand = try reachableExpr(&block_scope, &block_scope.base, operand_rl, lhs, rhs); 5016 const cond = try block_scope.addUnNode(cond_op, operand, node); 5017 const condbr = try block_scope.addCondBr(.condbr, node); 5018 5019 const block = try parent_gz.makeBlockInst(.block, node); 5020 try block_scope.setBlockBody(block); 5021 // block_scope unstacked now, can add new instructions to parent_gz 5022 try parent_gz.instructions.append(astgen.gpa, block); 5023 5024 var then_scope = block_scope.makeSubBlock(scope); 5025 defer then_scope.unstack(); 5026 5027 // This could be a pointer or value depending on `unwrap_op`. 5028 const unwrapped_payload = try then_scope.addUnNode(unwrap_op, operand, node); 5029 const then_result = switch (rl) { 5030 .ref => unwrapped_payload, 5031 else => try rvalue(&then_scope, block_scope.break_result_loc, unwrapped_payload, node), 5032 }; 5033 5034 var else_scope = block_scope.makeSubBlock(scope); 5035 defer else_scope.unstack(); 5036 5037 var err_val_scope: Scope.LocalVal = undefined; 5038 const else_sub_scope = blk: { 5039 const payload = payload_token orelse break :blk &else_scope.base; 5040 const err_str = tree.tokenSlice(payload); 5041 if (mem.eql(u8, err_str, "_")) { 5042 return astgen.failTok(payload, "discard of error capture; omit it instead", .{}); 5043 } 5044 const err_name = try astgen.identAsString(payload); 5045 5046 try astgen.detectLocalShadowing(scope, err_name, payload, err_str); 5047 5048 err_val_scope = .{ 5049 .parent = &else_scope.base, 5050 .gen_zir = &else_scope, 5051 .name = err_name, 5052 .inst = try else_scope.addUnNode(unwrap_code_op, operand, node), 5053 .token_src = payload, 5054 .id_cat = .@"capture", 5055 }; 5056 break :blk &err_val_scope.base; 5057 }; 5058 5059 const else_result = try expr(&else_scope, else_sub_scope, block_scope.break_result_loc, rhs); 5060 if (!else_scope.endsWithNoReturn()) { 5061 block_scope.break_count += 1; 5062 } 5063 try checkUsed(parent_gz, &else_scope.base, else_sub_scope); 5064 5065 // We hold off on the break instructions as well as copying the then/else 5066 // instructions into place until we know whether to keep store_to_block_ptr 5067 // instructions or not. 5068 5069 const break_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .break_inline else .@"break"; 5070 return finishThenElseBlock( 5071 parent_gz, 5072 rl, 5073 node, 5074 &block_scope, 5075 &then_scope, 5076 &else_scope, 5077 condbr, 5078 cond, 5079 then_result, 5080 else_result, 5081 block, 5082 block, 5083 break_tag, 5084 ); 5085 } 5086 5087 /// Supports `else_scope` stacked on `then_scope` stacked on `block_scope`. Unstacks `else_scope` then `then_scope`. 5088 fn finishThenElseBlock( 5089 parent_gz: *GenZir, 5090 rl: ResultLoc, 5091 node: Ast.Node.Index, 5092 block_scope: *GenZir, 5093 then_scope: *GenZir, 5094 else_scope: *GenZir, 5095 condbr: Zir.Inst.Index, 5096 cond: Zir.Inst.Ref, 5097 then_result: Zir.Inst.Ref, 5098 else_result: Zir.Inst.Ref, 5099 main_block: Zir.Inst.Index, 5100 then_break_block: Zir.Inst.Index, 5101 break_tag: Zir.Inst.Tag, 5102 ) InnerError!Zir.Inst.Ref { 5103 // We now have enough information to decide whether the result instruction should 5104 // be communicated via result location pointer or break instructions. 5105 const strat = rl.strategy(block_scope); 5106 // else_scope may be stacked on then_scope, so check for no-return on then_scope manually 5107 const tags = parent_gz.astgen.instructions.items(.tag); 5108 const then_slice = then_scope.instructionsSliceUpto(else_scope); 5109 const then_no_return = then_slice.len > 0 and tags[then_slice[then_slice.len - 1]].isNoReturn(); 5110 const else_no_return = else_scope.endsWithNoReturn(); 5111 5112 switch (strat.tag) { 5113 .break_void => { 5114 const then_break = if (!then_no_return) try then_scope.makeBreak(break_tag, then_break_block, .void_value) else 0; 5115 const else_break = if (!else_no_return) try else_scope.makeBreak(break_tag, main_block, .void_value) else 0; 5116 assert(!strat.elide_store_to_block_ptr_instructions); 5117 try setCondBrPayload(condbr, cond, then_scope, then_break, else_scope, else_break); 5118 return indexToRef(main_block); 5119 }, 5120 .break_operand => { 5121 const then_break = if (!then_no_return) try then_scope.makeBreak(break_tag, then_break_block, then_result) else 0; 5122 const else_break = if (else_result == .none) 5123 try else_scope.makeBreak(break_tag, main_block, .void_value) 5124 else if (!else_no_return) 5125 try else_scope.makeBreak(break_tag, main_block, else_result) 5126 else 5127 0; 5128 5129 if (strat.elide_store_to_block_ptr_instructions) { 5130 try setCondBrPayloadElideBlockStorePtr(condbr, cond, then_scope, then_break, else_scope, else_break, block_scope.rl_ptr); 5131 } else { 5132 try setCondBrPayload(condbr, cond, then_scope, then_break, else_scope, else_break); 5133 } 5134 const block_ref = indexToRef(main_block); 5135 switch (rl) { 5136 .ref => return block_ref, 5137 else => return rvalue(parent_gz, rl, block_ref, node), 5138 } 5139 }, 5140 } 5141 } 5142 5143 /// Return whether the identifier names of two tokens are equal. Resolves @"" 5144 /// tokens without allocating. 5145 /// OK in theory it could do it without allocating. This implementation 5146 /// allocates when the @"" form is used. 5147 fn tokenIdentEql(astgen: *AstGen, token1: Ast.TokenIndex, token2: Ast.TokenIndex) !bool { 5148 const ident_name_1 = try astgen.identifierTokenString(token1); 5149 const ident_name_2 = try astgen.identifierTokenString(token2); 5150 return mem.eql(u8, ident_name_1, ident_name_2); 5151 } 5152 5153 fn fieldAccess( 5154 gz: *GenZir, 5155 scope: *Scope, 5156 rl: ResultLoc, 5157 node: Ast.Node.Index, 5158 ) InnerError!Zir.Inst.Ref { 5159 switch (rl) { 5160 .ref => return addFieldAccess(.field_ptr, gz, scope, .ref, node), 5161 else => { 5162 const access = try addFieldAccess(.field_val, gz, scope, .none, node); 5163 return rvalue(gz, rl, access, node); 5164 }, 5165 } 5166 } 5167 5168 fn addFieldAccess( 5169 tag: Zir.Inst.Tag, 5170 gz: *GenZir, 5171 scope: *Scope, 5172 lhs_rl: ResultLoc, 5173 node: Ast.Node.Index, 5174 ) InnerError!Zir.Inst.Ref { 5175 const astgen = gz.astgen; 5176 const tree = astgen.tree; 5177 const main_tokens = tree.nodes.items(.main_token); 5178 const node_datas = tree.nodes.items(.data); 5179 5180 const object_node = node_datas[node].lhs; 5181 const dot_token = main_tokens[node]; 5182 const field_ident = dot_token + 1; 5183 const str_index = try astgen.identAsString(field_ident); 5184 5185 return gz.addPlNode(tag, node, Zir.Inst.Field{ 5186 .lhs = try expr(gz, scope, lhs_rl, object_node), 5187 .field_name_start = str_index, 5188 }); 5189 } 5190 5191 fn arrayAccess( 5192 gz: *GenZir, 5193 scope: *Scope, 5194 rl: ResultLoc, 5195 node: Ast.Node.Index, 5196 ) InnerError!Zir.Inst.Ref { 5197 const astgen = gz.astgen; 5198 const tree = astgen.tree; 5199 const node_datas = tree.nodes.items(.data); 5200 switch (rl) { 5201 .ref => return gz.addPlNode(.elem_ptr_node, node, Zir.Inst.Bin{ 5202 .lhs = try expr(gz, scope, .ref, node_datas[node].lhs), 5203 .rhs = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs), 5204 }), 5205 else => return rvalue(gz, rl, try gz.addPlNode(.elem_val_node, node, Zir.Inst.Bin{ 5206 .lhs = try expr(gz, scope, .none, node_datas[node].lhs), 5207 .rhs = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs), 5208 }), node), 5209 } 5210 } 5211 5212 fn simpleBinOp( 5213 gz: *GenZir, 5214 scope: *Scope, 5215 rl: ResultLoc, 5216 node: Ast.Node.Index, 5217 op_inst_tag: Zir.Inst.Tag, 5218 ) InnerError!Zir.Inst.Ref { 5219 const astgen = gz.astgen; 5220 const tree = astgen.tree; 5221 const node_datas = tree.nodes.items(.data); 5222 5223 const result = try gz.addPlNode(op_inst_tag, node, Zir.Inst.Bin{ 5224 .lhs = try reachableExpr(gz, scope, .none, node_datas[node].lhs, node), 5225 .rhs = try reachableExpr(gz, scope, .none, node_datas[node].rhs, node), 5226 }); 5227 return rvalue(gz, rl, result, node); 5228 } 5229 5230 fn simpleStrTok( 5231 gz: *GenZir, 5232 rl: ResultLoc, 5233 ident_token: Ast.TokenIndex, 5234 node: Ast.Node.Index, 5235 op_inst_tag: Zir.Inst.Tag, 5236 ) InnerError!Zir.Inst.Ref { 5237 const astgen = gz.astgen; 5238 const str_index = try astgen.identAsString(ident_token); 5239 const result = try gz.addStrTok(op_inst_tag, str_index, ident_token); 5240 return rvalue(gz, rl, result, node); 5241 } 5242 5243 fn boolBinOp( 5244 gz: *GenZir, 5245 scope: *Scope, 5246 rl: ResultLoc, 5247 node: Ast.Node.Index, 5248 zir_tag: Zir.Inst.Tag, 5249 ) InnerError!Zir.Inst.Ref { 5250 const astgen = gz.astgen; 5251 const tree = astgen.tree; 5252 const node_datas = tree.nodes.items(.data); 5253 5254 const lhs = try expr(gz, scope, bool_rl, node_datas[node].lhs); 5255 const bool_br = try gz.addBoolBr(zir_tag, lhs); 5256 5257 var rhs_scope = gz.makeSubBlock(scope); 5258 defer rhs_scope.unstack(); 5259 const rhs = try expr(&rhs_scope, &rhs_scope.base, bool_rl, node_datas[node].rhs); 5260 if (!gz.refIsNoReturn(rhs)) { 5261 _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs); 5262 } 5263 try rhs_scope.setBoolBrBody(bool_br); 5264 5265 const block_ref = indexToRef(bool_br); 5266 return rvalue(gz, rl, block_ref, node); 5267 } 5268 5269 fn ifExpr( 5270 parent_gz: *GenZir, 5271 scope: *Scope, 5272 rl: ResultLoc, 5273 node: Ast.Node.Index, 5274 if_full: Ast.full.If, 5275 ) InnerError!Zir.Inst.Ref { 5276 const astgen = parent_gz.astgen; 5277 const tree = astgen.tree; 5278 const token_tags = tree.tokens.items(.tag); 5279 5280 var block_scope = parent_gz.makeSubBlock(scope); 5281 block_scope.setBreakResultLoc(rl); 5282 defer block_scope.unstack(); 5283 5284 const payload_is_ref = if (if_full.payload_token) |payload_token| 5285 token_tags[payload_token] == .asterisk 5286 else 5287 false; 5288 5289 try emitDbgNode(parent_gz, if_full.ast.cond_expr); 5290 const cond: struct { 5291 inst: Zir.Inst.Ref, 5292 bool_bit: Zir.Inst.Ref, 5293 } = c: { 5294 if (if_full.error_token) |_| { 5295 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; 5296 const err_union = try expr(&block_scope, &block_scope.base, cond_rl, if_full.ast.cond_expr); 5297 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err; 5298 break :c .{ 5299 .inst = err_union, 5300 .bool_bit = try block_scope.addUnNode(tag, err_union, node), 5301 }; 5302 } else if (if_full.payload_token) |_| { 5303 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; 5304 const optional = try expr(&block_scope, &block_scope.base, cond_rl, if_full.ast.cond_expr); 5305 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_null_ptr else .is_non_null; 5306 break :c .{ 5307 .inst = optional, 5308 .bool_bit = try block_scope.addUnNode(tag, optional, node), 5309 }; 5310 } else { 5311 const cond = try expr(&block_scope, &block_scope.base, bool_rl, if_full.ast.cond_expr); 5312 break :c .{ 5313 .inst = cond, 5314 .bool_bit = cond, 5315 }; 5316 } 5317 }; 5318 5319 const condbr = try block_scope.addCondBr(.condbr, node); 5320 5321 const block = try parent_gz.makeBlockInst(.block, node); 5322 try block_scope.setBlockBody(block); 5323 // block_scope unstacked now, can add new instructions to parent_gz 5324 try parent_gz.instructions.append(astgen.gpa, block); 5325 5326 var then_scope = parent_gz.makeSubBlock(scope); 5327 defer then_scope.unstack(); 5328 5329 var payload_val_scope: Scope.LocalVal = undefined; 5330 5331 try then_scope.addDbgBlockBegin(); 5332 const then_sub_scope = s: { 5333 if (if_full.error_token != null) { 5334 if (if_full.payload_token) |payload_token| { 5335 const tag: Zir.Inst.Tag = if (payload_is_ref) 5336 .err_union_payload_unsafe_ptr 5337 else 5338 .err_union_payload_unsafe; 5339 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); 5340 const token_name_index = payload_token + @boolToInt(payload_is_ref); 5341 const ident_name = try astgen.identAsString(token_name_index); 5342 const token_name_str = tree.tokenSlice(token_name_index); 5343 if (mem.eql(u8, "_", token_name_str)) 5344 break :s &then_scope.base; 5345 try astgen.detectLocalShadowing(&then_scope.base, ident_name, token_name_index, token_name_str); 5346 payload_val_scope = .{ 5347 .parent = &then_scope.base, 5348 .gen_zir = &then_scope, 5349 .name = ident_name, 5350 .inst = payload_inst, 5351 .token_src = payload_token, 5352 .id_cat = .@"capture", 5353 }; 5354 try then_scope.addDbgVar(.dbg_var_val, ident_name, payload_inst); 5355 break :s &payload_val_scope.base; 5356 } else { 5357 break :s &then_scope.base; 5358 } 5359 } else if (if_full.payload_token) |payload_token| { 5360 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; 5361 const tag: Zir.Inst.Tag = if (payload_is_ref) 5362 .optional_payload_unsafe_ptr 5363 else 5364 .optional_payload_unsafe; 5365 const ident_bytes = tree.tokenSlice(ident_token); 5366 if (mem.eql(u8, "_", ident_bytes)) 5367 break :s &then_scope.base; 5368 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); 5369 const ident_name = try astgen.identAsString(ident_token); 5370 try astgen.detectLocalShadowing(&then_scope.base, ident_name, ident_token, ident_bytes); 5371 payload_val_scope = .{ 5372 .parent = &then_scope.base, 5373 .gen_zir = &then_scope, 5374 .name = ident_name, 5375 .inst = payload_inst, 5376 .token_src = ident_token, 5377 .id_cat = .@"capture", 5378 }; 5379 try then_scope.addDbgVar(.dbg_var_val, ident_name, payload_inst); 5380 break :s &payload_val_scope.base; 5381 } else { 5382 break :s &then_scope.base; 5383 } 5384 }; 5385 5386 const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_loc, if_full.ast.then_expr); 5387 if (!then_scope.endsWithNoReturn()) { 5388 block_scope.break_count += 1; 5389 } 5390 try checkUsed(parent_gz, &then_scope.base, then_sub_scope); 5391 try then_scope.addDbgBlockEnd(); 5392 // We hold off on the break instructions as well as copying the then/else 5393 // instructions into place until we know whether to keep store_to_block_ptr 5394 // instructions or not. 5395 5396 var else_scope = parent_gz.makeSubBlock(scope); 5397 defer else_scope.unstack(); 5398 5399 const else_node = if_full.ast.else_expr; 5400 const else_info: struct { 5401 src: Ast.Node.Index, 5402 result: Zir.Inst.Ref, 5403 } = if (else_node != 0) blk: { 5404 try else_scope.addDbgBlockBegin(); 5405 const sub_scope = s: { 5406 if (if_full.error_token) |error_token| { 5407 const tag: Zir.Inst.Tag = if (payload_is_ref) 5408 .err_union_code_ptr 5409 else 5410 .err_union_code; 5411 const payload_inst = try else_scope.addUnNode(tag, cond.inst, node); 5412 const ident_name = try astgen.identAsString(error_token); 5413 const error_token_str = tree.tokenSlice(error_token); 5414 if (mem.eql(u8, "_", error_token_str)) 5415 break :s &else_scope.base; 5416 try astgen.detectLocalShadowing(&else_scope.base, ident_name, error_token, error_token_str); 5417 payload_val_scope = .{ 5418 .parent = &else_scope.base, 5419 .gen_zir = &else_scope, 5420 .name = ident_name, 5421 .inst = payload_inst, 5422 .token_src = error_token, 5423 .id_cat = .@"capture", 5424 }; 5425 try else_scope.addDbgVar(.dbg_var_val, ident_name, payload_inst); 5426 break :s &payload_val_scope.base; 5427 } else { 5428 break :s &else_scope.base; 5429 } 5430 }; 5431 const e = try expr(&else_scope, sub_scope, block_scope.break_result_loc, else_node); 5432 if (!else_scope.endsWithNoReturn()) { 5433 block_scope.break_count += 1; 5434 } 5435 try checkUsed(parent_gz, &else_scope.base, sub_scope); 5436 try else_scope.addDbgBlockEnd(); 5437 break :blk .{ 5438 .src = else_node, 5439 .result = e, 5440 }; 5441 } else .{ 5442 .src = if_full.ast.then_expr, 5443 .result = .none, 5444 }; 5445 5446 const break_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .break_inline else .@"break"; 5447 return finishThenElseBlock( 5448 parent_gz, 5449 rl, 5450 node, 5451 &block_scope, 5452 &then_scope, 5453 &else_scope, 5454 condbr, 5455 cond.bool_bit, 5456 then_result, 5457 else_info.result, 5458 block, 5459 block, 5460 break_tag, 5461 ); 5462 } 5463 5464 /// Supports `else_scope` stacked on `then_scope`. Unstacks `else_scope` then `then_scope`. 5465 fn setCondBrPayload( 5466 condbr: Zir.Inst.Index, 5467 cond: Zir.Inst.Ref, 5468 then_scope: *GenZir, 5469 then_break: Zir.Inst.Index, 5470 else_scope: *GenZir, 5471 else_break: Zir.Inst.Index, 5472 ) !void { 5473 defer then_scope.unstack(); 5474 defer else_scope.unstack(); 5475 const astgen = then_scope.astgen; 5476 const then_body = then_scope.instructionsSliceUpto(else_scope); 5477 const else_body = else_scope.instructionsSlice(); 5478 const then_body_len = astgen.countBodyLenAfterFixups(then_body) + @boolToInt(then_break != 0); 5479 const else_body_len = astgen.countBodyLenAfterFixups(else_body) + @boolToInt(else_break != 0); 5480 try astgen.extra.ensureUnusedCapacity( 5481 astgen.gpa, 5482 @typeInfo(Zir.Inst.CondBr).Struct.fields.len + then_body_len + else_body_len, 5483 ); 5484 5485 const zir_datas = astgen.instructions.items(.data); 5486 zir_datas[condbr].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{ 5487 .condition = cond, 5488 .then_body_len = then_body_len, 5489 .else_body_len = else_body_len, 5490 }); 5491 astgen.appendBodyWithFixups(then_body); 5492 if (then_break != 0) astgen.extra.appendAssumeCapacity(then_break); 5493 astgen.appendBodyWithFixups(else_body); 5494 if (else_break != 0) astgen.extra.appendAssumeCapacity(else_break); 5495 } 5496 5497 /// Supports `else_scope` stacked on `then_scope`. Unstacks `else_scope` then `then_scope`. 5498 fn setCondBrPayloadElideBlockStorePtr( 5499 condbr: Zir.Inst.Index, 5500 cond: Zir.Inst.Ref, 5501 then_scope: *GenZir, 5502 then_break: Zir.Inst.Index, 5503 else_scope: *GenZir, 5504 else_break: Zir.Inst.Index, 5505 block_ptr: Zir.Inst.Ref, 5506 ) !void { 5507 defer then_scope.unstack(); 5508 defer else_scope.unstack(); 5509 const astgen = then_scope.astgen; 5510 const then_body = then_scope.instructionsSliceUpto(else_scope); 5511 const else_body = else_scope.instructionsSlice(); 5512 const has_then_break = then_break != 0; 5513 const has_else_break = else_break != 0; 5514 const then_body_len = astgen.countBodyLenAfterFixups(then_body) + @boolToInt(has_then_break); 5515 const else_body_len = astgen.countBodyLenAfterFixups(else_body) + @boolToInt(has_else_break); 5516 try astgen.extra.ensureUnusedCapacity( 5517 astgen.gpa, 5518 @typeInfo(Zir.Inst.CondBr).Struct.fields.len + then_body_len + else_body_len, 5519 ); 5520 5521 const zir_tags = astgen.instructions.items(.tag); 5522 const zir_datas = astgen.instructions.items(.data); 5523 5524 const condbr_pl = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{ 5525 .condition = cond, 5526 .then_body_len = then_body_len, 5527 .else_body_len = else_body_len, 5528 }); 5529 zir_datas[condbr].pl_node.payload_index = condbr_pl; 5530 const then_body_len_index = condbr_pl + 1; 5531 const else_body_len_index = condbr_pl + 2; 5532 5533 // The break instructions need to have their operands coerced if the 5534 // switch's result location is a `ty`. In this case we overwrite the 5535 // `store_to_block_ptr` instruction with an `as` instruction and repurpose 5536 // it as the break operand. 5537 // This corresponds to similar code in `labeledBlockExpr`. 5538 for (then_body) |src_inst| { 5539 if (zir_tags[src_inst] == .store_to_block_ptr and 5540 zir_datas[src_inst].bin.lhs == block_ptr) 5541 { 5542 if (then_scope.rl_ty_inst != .none and has_then_break) { 5543 zir_tags[src_inst] = .as; 5544 zir_datas[src_inst].bin = .{ 5545 .lhs = then_scope.rl_ty_inst, 5546 .rhs = zir_datas[then_break].@"break".operand, 5547 }; 5548 zir_datas[then_break].@"break".operand = indexToRef(src_inst); 5549 } else { 5550 astgen.extra.items[then_body_len_index] -= 1; 5551 continue; 5552 } 5553 } 5554 appendPossiblyRefdBodyInst(astgen, &astgen.extra, src_inst); 5555 } 5556 if (has_then_break) astgen.extra.appendAssumeCapacity(then_break); 5557 5558 for (else_body) |src_inst| { 5559 if (zir_tags[src_inst] == .store_to_block_ptr and 5560 zir_datas[src_inst].bin.lhs == block_ptr) 5561 { 5562 if (else_scope.rl_ty_inst != .none and has_else_break) { 5563 zir_tags[src_inst] = .as; 5564 zir_datas[src_inst].bin = .{ 5565 .lhs = else_scope.rl_ty_inst, 5566 .rhs = zir_datas[else_break].@"break".operand, 5567 }; 5568 zir_datas[else_break].@"break".operand = indexToRef(src_inst); 5569 } else { 5570 astgen.extra.items[else_body_len_index] -= 1; 5571 continue; 5572 } 5573 } 5574 appendPossiblyRefdBodyInst(astgen, &astgen.extra, src_inst); 5575 } 5576 if (has_else_break) astgen.extra.appendAssumeCapacity(else_break); 5577 } 5578 5579 fn whileExpr( 5580 parent_gz: *GenZir, 5581 scope: *Scope, 5582 rl: ResultLoc, 5583 node: Ast.Node.Index, 5584 while_full: Ast.full.While, 5585 ) InnerError!Zir.Inst.Ref { 5586 const astgen = parent_gz.astgen; 5587 const tree = astgen.tree; 5588 const token_tags = tree.tokens.items(.tag); 5589 5590 if (while_full.label_token) |label_token| { 5591 try astgen.checkLabelRedefinition(scope, label_token); 5592 } 5593 5594 const is_inline = parent_gz.force_comptime or while_full.inline_token != null; 5595 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop; 5596 const loop_block = try parent_gz.makeBlockInst(loop_tag, node); 5597 try parent_gz.instructions.append(astgen.gpa, loop_block); 5598 5599 var loop_scope = parent_gz.makeSubBlock(scope); 5600 loop_scope.is_inline = is_inline; 5601 loop_scope.setBreakResultLoc(rl); 5602 defer loop_scope.unstack(); 5603 defer loop_scope.labeled_breaks.deinit(astgen.gpa); 5604 5605 var continue_scope = parent_gz.makeSubBlock(&loop_scope.base); 5606 defer continue_scope.unstack(); 5607 5608 const payload_is_ref = if (while_full.payload_token) |payload_token| 5609 token_tags[payload_token] == .asterisk 5610 else 5611 false; 5612 5613 try emitDbgNode(parent_gz, while_full.ast.cond_expr); 5614 const cond: struct { 5615 inst: Zir.Inst.Ref, 5616 bool_bit: Zir.Inst.Ref, 5617 } = c: { 5618 if (while_full.error_token) |_| { 5619 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; 5620 const err_union = try expr(&continue_scope, &continue_scope.base, cond_rl, while_full.ast.cond_expr); 5621 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err; 5622 break :c .{ 5623 .inst = err_union, 5624 .bool_bit = try continue_scope.addUnNode(tag, err_union, node), 5625 }; 5626 } else if (while_full.payload_token) |_| { 5627 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; 5628 const optional = try expr(&continue_scope, &continue_scope.base, cond_rl, while_full.ast.cond_expr); 5629 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_null_ptr else .is_non_null; 5630 break :c .{ 5631 .inst = optional, 5632 .bool_bit = try continue_scope.addUnNode(tag, optional, node), 5633 }; 5634 } else { 5635 const cond = try expr(&continue_scope, &continue_scope.base, bool_rl, while_full.ast.cond_expr); 5636 break :c .{ 5637 .inst = cond, 5638 .bool_bit = cond, 5639 }; 5640 } 5641 }; 5642 5643 const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr; 5644 const condbr = try continue_scope.addCondBr(condbr_tag, node); 5645 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block; 5646 const cond_block = try loop_scope.makeBlockInst(block_tag, node); 5647 try continue_scope.setBlockBody(cond_block); 5648 // continue_scope unstacked now, can add new instructions to loop_scope 5649 try loop_scope.instructions.append(astgen.gpa, cond_block); 5650 5651 // make scope now but don't stack on parent_gz until loop_scope 5652 // gets unstacked after cont_expr is emitted and added below 5653 var then_scope = parent_gz.makeSubBlock(&continue_scope.base); 5654 then_scope.markAsLoopBody(loop_scope); 5655 then_scope.instructions_top = GenZir.unstacked_top; 5656 defer then_scope.unstack(); 5657 5658 var dbg_var_name: ?u32 = null; 5659 var dbg_var_inst: Zir.Inst.Ref = undefined; 5660 var payload_inst: Zir.Inst.Index = 0; 5661 var payload_val_scope: Scope.LocalVal = undefined; 5662 const then_sub_scope = s: { 5663 if (while_full.error_token != null) { 5664 if (while_full.payload_token) |payload_token| { 5665 const tag: Zir.Inst.Tag = if (payload_is_ref) 5666 .err_union_payload_unsafe_ptr 5667 else 5668 .err_union_payload_unsafe; 5669 // will add this instruction to then_scope.instructions below 5670 payload_inst = try then_scope.makeUnNode(tag, cond.inst, node); 5671 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; 5672 const ident_bytes = tree.tokenSlice(ident_token); 5673 if (mem.eql(u8, "_", ident_bytes)) 5674 break :s &then_scope.base; 5675 const payload_name_loc = payload_token + @boolToInt(payload_is_ref); 5676 const ident_name = try astgen.identAsString(payload_name_loc); 5677 try astgen.detectLocalShadowing(&then_scope.base, ident_name, payload_name_loc, ident_bytes); 5678 payload_val_scope = .{ 5679 .parent = &then_scope.base, 5680 .gen_zir = &then_scope, 5681 .name = ident_name, 5682 .inst = indexToRef(payload_inst), 5683 .token_src = payload_token, 5684 .id_cat = .@"capture", 5685 }; 5686 dbg_var_name = ident_name; 5687 dbg_var_inst = indexToRef(payload_inst); 5688 break :s &payload_val_scope.base; 5689 } else { 5690 break :s &then_scope.base; 5691 } 5692 } else if (while_full.payload_token) |payload_token| { 5693 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; 5694 const tag: Zir.Inst.Tag = if (payload_is_ref) 5695 .optional_payload_unsafe_ptr 5696 else 5697 .optional_payload_unsafe; 5698 // will add this instruction to then_scope.instructions below 5699 payload_inst = try then_scope.makeUnNode(tag, cond.inst, node); 5700 const ident_name = try astgen.identAsString(ident_token); 5701 const ident_bytes = tree.tokenSlice(ident_token); 5702 if (mem.eql(u8, "_", ident_bytes)) 5703 break :s &then_scope.base; 5704 try astgen.detectLocalShadowing(&then_scope.base, ident_name, ident_token, ident_bytes); 5705 payload_val_scope = .{ 5706 .parent = &then_scope.base, 5707 .gen_zir = &then_scope, 5708 .name = ident_name, 5709 .inst = indexToRef(payload_inst), 5710 .token_src = ident_token, 5711 .id_cat = .@"capture", 5712 }; 5713 dbg_var_name = ident_name; 5714 dbg_var_inst = indexToRef(payload_inst); 5715 break :s &payload_val_scope.base; 5716 } else { 5717 break :s &then_scope.base; 5718 } 5719 }; 5720 5721 // This code could be improved to avoid emitting the continue expr when there 5722 // are no jumps to it. This happens when the last statement of a while body is noreturn 5723 // and there are no `continue` statements. 5724 // Tracking issue: https://github.com/ziglang/zig/issues/9185 5725 try then_scope.addDbgBlockBegin(); 5726 if (dbg_var_name) |some| { 5727 try then_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst); 5728 } 5729 if (while_full.ast.cont_expr != 0) { 5730 _ = try unusedResultExpr(&loop_scope, then_sub_scope, while_full.ast.cont_expr); 5731 } 5732 try then_scope.addDbgBlockEnd(); 5733 const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; 5734 _ = try loop_scope.addNode(repeat_tag, node); 5735 5736 try loop_scope.setBlockBody(loop_block); 5737 loop_scope.break_block = loop_block; 5738 loop_scope.continue_block = cond_block; 5739 if (while_full.label_token) |label_token| { 5740 loop_scope.label = @as(?GenZir.Label, GenZir.Label{ 5741 .token = label_token, 5742 .block_inst = loop_block, 5743 }); 5744 } 5745 5746 // done adding instructions to loop_scope, can now stack then_scope 5747 then_scope.instructions_top = then_scope.instructions.items.len; 5748 5749 if (payload_inst != 0) try then_scope.instructions.append(astgen.gpa, payload_inst); 5750 try then_scope.addDbgBlockBegin(); 5751 if (dbg_var_name) |some| { 5752 try then_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst); 5753 } 5754 const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr); 5755 try checkUsed(parent_gz, &then_scope.base, then_sub_scope); 5756 try then_scope.addDbgBlockEnd(); 5757 5758 var else_scope = parent_gz.makeSubBlock(&continue_scope.base); 5759 defer else_scope.unstack(); 5760 5761 const else_node = while_full.ast.else_expr; 5762 const else_info: struct { 5763 src: Ast.Node.Index, 5764 result: Zir.Inst.Ref, 5765 } = if (else_node != 0) blk: { 5766 try else_scope.addDbgBlockBegin(); 5767 const sub_scope = s: { 5768 if (while_full.error_token) |error_token| { 5769 const tag: Zir.Inst.Tag = if (payload_is_ref) 5770 .err_union_code_ptr 5771 else 5772 .err_union_code; 5773 const else_payload_inst = try else_scope.addUnNode(tag, cond.inst, node); 5774 const ident_name = try astgen.identAsString(error_token); 5775 const ident_bytes = tree.tokenSlice(error_token); 5776 if (mem.eql(u8, ident_bytes, "_")) 5777 break :s &else_scope.base; 5778 try astgen.detectLocalShadowing(&else_scope.base, ident_name, error_token, ident_bytes); 5779 payload_val_scope = .{ 5780 .parent = &else_scope.base, 5781 .gen_zir = &else_scope, 5782 .name = ident_name, 5783 .inst = else_payload_inst, 5784 .token_src = error_token, 5785 .id_cat = .@"capture", 5786 }; 5787 try else_scope.addDbgVar(.dbg_var_val, ident_name, else_payload_inst); 5788 break :s &payload_val_scope.base; 5789 } else { 5790 break :s &else_scope.base; 5791 } 5792 }; 5793 // Remove the continue block and break block so that `continue` and `break` 5794 // control flow apply to outer loops; not this one. 5795 loop_scope.continue_block = 0; 5796 loop_scope.break_block = 0; 5797 const e = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node); 5798 if (!else_scope.endsWithNoReturn()) { 5799 loop_scope.break_count += 1; 5800 } 5801 try checkUsed(parent_gz, &else_scope.base, sub_scope); 5802 try else_scope.addDbgBlockEnd(); 5803 break :blk .{ 5804 .src = else_node, 5805 .result = e, 5806 }; 5807 } else .{ 5808 .src = while_full.ast.then_expr, 5809 .result = .none, 5810 }; 5811 5812 if (loop_scope.label) |some| { 5813 if (!some.used) { 5814 try astgen.appendErrorTok(some.token, "unused while loop label", .{}); 5815 } 5816 } 5817 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; 5818 return finishThenElseBlock( 5819 parent_gz, 5820 rl, 5821 node, 5822 &loop_scope, 5823 &then_scope, 5824 &else_scope, 5825 condbr, 5826 cond.bool_bit, 5827 then_result, 5828 else_info.result, 5829 loop_block, 5830 cond_block, 5831 break_tag, 5832 ); 5833 } 5834 5835 fn forExpr( 5836 parent_gz: *GenZir, 5837 scope: *Scope, 5838 rl: ResultLoc, 5839 node: Ast.Node.Index, 5840 for_full: Ast.full.While, 5841 ) InnerError!Zir.Inst.Ref { 5842 const astgen = parent_gz.astgen; 5843 5844 if (for_full.label_token) |label_token| { 5845 try astgen.checkLabelRedefinition(scope, label_token); 5846 } 5847 5848 // Set up variables and constants. 5849 const is_inline = parent_gz.force_comptime or for_full.inline_token != null; 5850 const tree = astgen.tree; 5851 const token_tags = tree.tokens.items(.tag); 5852 5853 const payload_is_ref = if (for_full.payload_token) |payload_token| 5854 token_tags[payload_token] == .asterisk 5855 else 5856 false; 5857 5858 try emitDbgNode(parent_gz, for_full.ast.cond_expr); 5859 5860 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; 5861 const array_ptr = try expr(parent_gz, scope, cond_rl, for_full.ast.cond_expr); 5862 const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr); 5863 5864 const index_ptr = blk: { 5865 const alloc_tag: Zir.Inst.Tag = if (is_inline) .alloc_comptime_mut else .alloc; 5866 const index_ptr = try parent_gz.addUnNode(alloc_tag, .usize_type, node); 5867 // initialize to zero 5868 _ = try parent_gz.addBin(.store, index_ptr, .zero_usize); 5869 break :blk index_ptr; 5870 }; 5871 5872 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop; 5873 const loop_block = try parent_gz.makeBlockInst(loop_tag, node); 5874 try parent_gz.instructions.append(astgen.gpa, loop_block); 5875 5876 var loop_scope = parent_gz.makeSubBlock(scope); 5877 loop_scope.is_inline = is_inline; 5878 loop_scope.setBreakResultLoc(rl); 5879 defer loop_scope.unstack(); 5880 defer loop_scope.labeled_breaks.deinit(astgen.gpa); 5881 5882 var cond_scope = parent_gz.makeSubBlock(&loop_scope.base); 5883 defer cond_scope.unstack(); 5884 5885 // check condition i < array_expr.len 5886 const index = try cond_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr); 5887 const cond = try cond_scope.addPlNode(.cmp_lt, for_full.ast.cond_expr, Zir.Inst.Bin{ 5888 .lhs = index, 5889 .rhs = len, 5890 }); 5891 5892 const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr; 5893 const condbr = try cond_scope.addCondBr(condbr_tag, node); 5894 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block; 5895 const cond_block = try loop_scope.makeBlockInst(block_tag, node); 5896 try cond_scope.setBlockBody(cond_block); 5897 // cond_block unstacked now, can add new instructions to loop_scope 5898 try loop_scope.instructions.append(astgen.gpa, cond_block); 5899 5900 // Increment the index variable. 5901 const index_2 = try loop_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr); 5902 const index_plus_one = try loop_scope.addPlNode(.add, node, Zir.Inst.Bin{ 5903 .lhs = index_2, 5904 .rhs = .one_usize, 5905 }); 5906 _ = try loop_scope.addBin(.store, index_ptr, index_plus_one); 5907 const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; 5908 _ = try loop_scope.addNode(repeat_tag, node); 5909 5910 try loop_scope.setBlockBody(loop_block); 5911 loop_scope.break_block = loop_block; 5912 loop_scope.continue_block = cond_block; 5913 if (for_full.label_token) |label_token| { 5914 loop_scope.label = @as(?GenZir.Label, GenZir.Label{ 5915 .token = label_token, 5916 .block_inst = loop_block, 5917 }); 5918 } 5919 5920 var then_scope = parent_gz.makeSubBlock(&cond_scope.base); 5921 then_scope.markAsLoopBody(loop_scope); 5922 defer then_scope.unstack(); 5923 5924 try then_scope.addDbgBlockBegin(); 5925 var payload_val_scope: Scope.LocalVal = undefined; 5926 var index_scope: Scope.LocalPtr = undefined; 5927 const then_sub_scope = blk: { 5928 const payload_token = for_full.payload_token.?; 5929 const ident = if (token_tags[payload_token] == .asterisk) 5930 payload_token + 1 5931 else 5932 payload_token; 5933 const is_ptr = ident != payload_token; 5934 const value_name = tree.tokenSlice(ident); 5935 var payload_sub_scope: *Scope = undefined; 5936 if (!mem.eql(u8, value_name, "_")) { 5937 const name_str_index = try astgen.identAsString(ident); 5938 const tag: Zir.Inst.Tag = if (is_ptr) .elem_ptr else .elem_val; 5939 const payload_inst = try then_scope.addPlNode(tag, for_full.ast.cond_expr, Zir.Inst.Bin{ 5940 .lhs = array_ptr, 5941 .rhs = index, 5942 }); 5943 try astgen.detectLocalShadowing(&then_scope.base, name_str_index, ident, value_name); 5944 payload_val_scope = .{ 5945 .parent = &then_scope.base, 5946 .gen_zir = &then_scope, 5947 .name = name_str_index, 5948 .inst = payload_inst, 5949 .token_src = ident, 5950 .id_cat = .@"capture", 5951 }; 5952 try then_scope.addDbgVar(.dbg_var_val, name_str_index, payload_inst); 5953 payload_sub_scope = &payload_val_scope.base; 5954 } else if (is_ptr) { 5955 return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{}); 5956 } else { 5957 payload_sub_scope = &then_scope.base; 5958 } 5959 5960 const index_token = if (token_tags[ident + 1] == .comma) 5961 ident + 2 5962 else 5963 break :blk payload_sub_scope; 5964 const token_bytes = tree.tokenSlice(index_token); 5965 if (mem.eql(u8, token_bytes, "_")) { 5966 return astgen.failTok(index_token, "discard of index capture; omit it instead", .{}); 5967 } 5968 const index_name = try astgen.identAsString(index_token); 5969 try astgen.detectLocalShadowing(payload_sub_scope, index_name, index_token, token_bytes); 5970 index_scope = .{ 5971 .parent = payload_sub_scope, 5972 .gen_zir = &then_scope, 5973 .name = index_name, 5974 .ptr = index_ptr, 5975 .token_src = index_token, 5976 .maybe_comptime = is_inline, 5977 .id_cat = .@"loop index capture", 5978 }; 5979 try then_scope.addDbgVar(.dbg_var_val, index_name, index_ptr); 5980 break :blk &index_scope.base; 5981 }; 5982 5983 const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr); 5984 try checkUsed(parent_gz, &then_scope.base, then_sub_scope); 5985 try then_scope.addDbgBlockEnd(); 5986 5987 var else_scope = parent_gz.makeSubBlock(&cond_scope.base); 5988 defer else_scope.unstack(); 5989 5990 const else_node = for_full.ast.else_expr; 5991 const else_info: struct { 5992 src: Ast.Node.Index, 5993 result: Zir.Inst.Ref, 5994 } = if (else_node != 0) blk: { 5995 const sub_scope = &else_scope.base; 5996 // Remove the continue block and break block so that `continue` and `break` 5997 // control flow apply to outer loops; not this one. 5998 loop_scope.continue_block = 0; 5999 loop_scope.break_block = 0; 6000 const else_result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node); 6001 if (!else_scope.endsWithNoReturn()) { 6002 loop_scope.break_count += 1; 6003 } 6004 break :blk .{ 6005 .src = else_node, 6006 .result = else_result, 6007 }; 6008 } else .{ 6009 .src = for_full.ast.then_expr, 6010 .result = .none, 6011 }; 6012 6013 if (loop_scope.label) |some| { 6014 if (!some.used) { 6015 try astgen.appendErrorTok(some.token, "unused for loop label", .{}); 6016 } 6017 } 6018 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; 6019 return finishThenElseBlock( 6020 parent_gz, 6021 rl, 6022 node, 6023 &loop_scope, 6024 &then_scope, 6025 &else_scope, 6026 condbr, 6027 cond, 6028 then_result, 6029 else_info.result, 6030 loop_block, 6031 cond_block, 6032 break_tag, 6033 ); 6034 } 6035 6036 fn switchExpr( 6037 parent_gz: *GenZir, 6038 scope: *Scope, 6039 rl: ResultLoc, 6040 switch_node: Ast.Node.Index, 6041 ) InnerError!Zir.Inst.Ref { 6042 const astgen = parent_gz.astgen; 6043 const gpa = astgen.gpa; 6044 const tree = astgen.tree; 6045 const node_datas = tree.nodes.items(.data); 6046 const node_tags = tree.nodes.items(.tag); 6047 const main_tokens = tree.nodes.items(.main_token); 6048 const token_tags = tree.tokens.items(.tag); 6049 const operand_node = node_datas[switch_node].lhs; 6050 const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange); 6051 const case_nodes = tree.extra_data[extra.start..extra.end]; 6052 6053 // We perform two passes over the AST. This first pass is to collect information 6054 // for the following variables, make note of the special prong AST node index, 6055 // and bail out with a compile error if there are multiple special prongs present. 6056 var any_payload_is_ref = false; 6057 var scalar_cases_len: u32 = 0; 6058 var multi_cases_len: u32 = 0; 6059 var special_prong: Zir.SpecialProng = .none; 6060 var special_node: Ast.Node.Index = 0; 6061 var else_src: ?Ast.TokenIndex = null; 6062 var underscore_src: ?Ast.TokenIndex = null; 6063 for (case_nodes) |case_node| { 6064 const case = switch (node_tags[case_node]) { 6065 .switch_case_one => tree.switchCaseOne(case_node), 6066 .switch_case => tree.switchCase(case_node), 6067 else => unreachable, 6068 }; 6069 if (case.payload_token) |payload_token| { 6070 if (token_tags[payload_token] == .asterisk) { 6071 any_payload_is_ref = true; 6072 } 6073 } 6074 // Check for else/`_` prong. 6075 if (case.ast.values.len == 0) { 6076 const case_src = case.ast.arrow_token - 1; 6077 if (else_src) |src| { 6078 return astgen.failTokNotes( 6079 case_src, 6080 "multiple else prongs in switch expression", 6081 .{}, 6082 &[_]u32{ 6083 try astgen.errNoteTok( 6084 src, 6085 "previous else prong here", 6086 .{}, 6087 ), 6088 }, 6089 ); 6090 } else if (underscore_src) |some_underscore| { 6091 return astgen.failNodeNotes( 6092 switch_node, 6093 "else and '_' prong in switch expression", 6094 .{}, 6095 &[_]u32{ 6096 try astgen.errNoteTok( 6097 case_src, 6098 "else prong here", 6099 .{}, 6100 ), 6101 try astgen.errNoteTok( 6102 some_underscore, 6103 "'_' prong here", 6104 .{}, 6105 ), 6106 }, 6107 ); 6108 } 6109 special_node = case_node; 6110 special_prong = .@"else"; 6111 else_src = case_src; 6112 continue; 6113 } else if (case.ast.values.len == 1 and 6114 node_tags[case.ast.values[0]] == .identifier and 6115 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_")) 6116 { 6117 const case_src = case.ast.arrow_token - 1; 6118 if (underscore_src) |src| { 6119 return astgen.failTokNotes( 6120 case_src, 6121 "multiple '_' prongs in switch expression", 6122 .{}, 6123 &[_]u32{ 6124 try astgen.errNoteTok( 6125 src, 6126 "previous '_' prong here", 6127 .{}, 6128 ), 6129 }, 6130 ); 6131 } else if (else_src) |some_else| { 6132 return astgen.failNodeNotes( 6133 switch_node, 6134 "else and '_' prong in switch expression", 6135 .{}, 6136 &[_]u32{ 6137 try astgen.errNoteTok( 6138 some_else, 6139 "else prong here", 6140 .{}, 6141 ), 6142 try astgen.errNoteTok( 6143 case_src, 6144 "'_' prong here", 6145 .{}, 6146 ), 6147 }, 6148 ); 6149 } 6150 special_node = case_node; 6151 special_prong = .under; 6152 underscore_src = case_src; 6153 continue; 6154 } 6155 6156 if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] != .switch_range) { 6157 scalar_cases_len += 1; 6158 } else { 6159 multi_cases_len += 1; 6160 } 6161 } 6162 6163 const operand_rl: ResultLoc = if (any_payload_is_ref) .ref else .none; 6164 const raw_operand = try expr(parent_gz, scope, operand_rl, operand_node); 6165 const cond_tag: Zir.Inst.Tag = if (any_payload_is_ref) .switch_cond_ref else .switch_cond; 6166 const cond = try parent_gz.addUnNode(cond_tag, raw_operand, operand_node); 6167 // We need the type of the operand to use as the result location for all the prong items. 6168 const cond_ty_inst = try parent_gz.addUnNode(.typeof, cond, operand_node); 6169 const item_rl: ResultLoc = .{ .ty = cond_ty_inst }; 6170 6171 // This contains the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti, 6172 // except the first cases_nodes.len slots are a table that indexes payloads later in the array, with 6173 // the special case index coming first, then scalar_case_len indexes, then multi_cases_len indexes 6174 const payloads = &astgen.scratch; 6175 const scratch_top = astgen.scratch.items.len; 6176 const case_table_start = scratch_top; 6177 const scalar_case_table = case_table_start + @boolToInt(special_prong != .none); 6178 const multi_case_table = scalar_case_table + scalar_cases_len; 6179 const case_table_end = multi_case_table + multi_cases_len; 6180 try astgen.scratch.resize(gpa, case_table_end); 6181 defer astgen.scratch.items.len = scratch_top; 6182 6183 var block_scope = parent_gz.makeSubBlock(scope); 6184 // block_scope not used for collecting instructions 6185 block_scope.instructions_top = GenZir.unstacked_top; 6186 block_scope.setBreakResultLoc(rl); 6187 6188 // This gets added to the parent block later, after the item expressions. 6189 const switch_block = try parent_gz.makeBlockInst(.switch_block, switch_node); 6190 6191 // We re-use this same scope for all cases, including the special prong, if any. 6192 var case_scope = parent_gz.makeSubBlock(&block_scope.base); 6193 case_scope.instructions_top = GenZir.unstacked_top; 6194 6195 // In this pass we generate all the item and prong expressions. 6196 var multi_case_index: u32 = 0; 6197 var scalar_case_index: u32 = 0; 6198 for (case_nodes) |case_node| { 6199 const case = switch (node_tags[case_node]) { 6200 .switch_case_one => tree.switchCaseOne(case_node), 6201 .switch_case => tree.switchCase(case_node), 6202 else => unreachable, 6203 }; 6204 6205 const is_multi_case = case.ast.values.len > 1 or 6206 (case.ast.values.len == 1 and node_tags[case.ast.values[0]] == .switch_range); 6207 6208 var dbg_var_name: ?u32 = null; 6209 var dbg_var_inst: Zir.Inst.Ref = undefined; 6210 var capture_inst: Zir.Inst.Index = 0; 6211 var capture_val_scope: Scope.LocalVal = undefined; 6212 const sub_scope = blk: { 6213 const payload_token = case.payload_token orelse break :blk &case_scope.base; 6214 const ident = if (token_tags[payload_token] == .asterisk) 6215 payload_token + 1 6216 else 6217 payload_token; 6218 const is_ptr = ident != payload_token; 6219 if (mem.eql(u8, tree.tokenSlice(ident), "_")) { 6220 if (is_ptr) { 6221 return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{}); 6222 } 6223 break :blk &case_scope.base; 6224 } 6225 if (case_node == special_node) { 6226 const capture_tag: Zir.Inst.Tag = if (is_ptr) 6227 .switch_capture_ref 6228 else 6229 .switch_capture; 6230 capture_inst = @intCast(Zir.Inst.Index, astgen.instructions.len); 6231 try astgen.instructions.append(gpa, .{ 6232 .tag = capture_tag, 6233 .data = .{ 6234 .switch_capture = .{ 6235 .switch_inst = switch_block, 6236 // Max int communicates that this is the else/underscore prong. 6237 .prong_index = std.math.maxInt(u32), 6238 }, 6239 }, 6240 }); 6241 } else { 6242 const is_multi_case_bits: u2 = @boolToInt(is_multi_case); 6243 const is_ptr_bits: u2 = @boolToInt(is_ptr); 6244 const capture_tag: Zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) { 6245 0b00 => .switch_capture, 6246 0b01 => .switch_capture_ref, 6247 0b10 => .switch_capture_multi, 6248 0b11 => .switch_capture_multi_ref, 6249 }; 6250 const capture_index = if (is_multi_case) multi_case_index else scalar_case_index; 6251 capture_inst = @intCast(Zir.Inst.Index, astgen.instructions.len); 6252 try astgen.instructions.append(gpa, .{ 6253 .tag = capture_tag, 6254 .data = .{ .switch_capture = .{ 6255 .switch_inst = switch_block, 6256 .prong_index = capture_index, 6257 } }, 6258 }); 6259 } 6260 const capture_name = try astgen.identAsString(ident); 6261 capture_val_scope = .{ 6262 .parent = &case_scope.base, 6263 .gen_zir = &case_scope, 6264 .name = capture_name, 6265 .inst = indexToRef(capture_inst), 6266 .token_src = payload_token, 6267 .id_cat = .@"capture", 6268 }; 6269 dbg_var_name = capture_name; 6270 dbg_var_inst = indexToRef(capture_inst); 6271 break :blk &capture_val_scope.base; 6272 }; 6273 6274 const header_index = @intCast(u32, payloads.items.len); 6275 const body_len_index = if (is_multi_case) blk: { 6276 payloads.items[multi_case_table + multi_case_index] = header_index; 6277 multi_case_index += 1; 6278 try payloads.resize(gpa, header_index + 3); // items_len, ranges_len, body_len 6279 6280 // items 6281 var items_len: u32 = 0; 6282 for (case.ast.values) |item_node| { 6283 if (node_tags[item_node] == .switch_range) continue; 6284 items_len += 1; 6285 6286 const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node); 6287 try payloads.append(gpa, @enumToInt(item_inst)); 6288 } 6289 6290 // ranges 6291 var ranges_len: u32 = 0; 6292 for (case.ast.values) |range| { 6293 if (node_tags[range] != .switch_range) continue; 6294 ranges_len += 1; 6295 6296 const first = try comptimeExpr(parent_gz, scope, item_rl, node_datas[range].lhs); 6297 const last = try comptimeExpr(parent_gz, scope, item_rl, node_datas[range].rhs); 6298 try payloads.appendSlice(gpa, &[_]u32{ 6299 @enumToInt(first), @enumToInt(last), 6300 }); 6301 } 6302 6303 payloads.items[header_index] = items_len; 6304 payloads.items[header_index + 1] = ranges_len; 6305 break :blk header_index + 2; 6306 } else if (case_node == special_node) blk: { 6307 payloads.items[case_table_start] = header_index; 6308 try payloads.resize(gpa, header_index + 1); // body_len 6309 break :blk header_index; 6310 } else blk: { 6311 payloads.items[scalar_case_table + scalar_case_index] = header_index; 6312 scalar_case_index += 1; 6313 try payloads.resize(gpa, header_index + 2); // item, body_len 6314 const item_node = case.ast.values[0]; 6315 const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node); 6316 payloads.items[header_index] = @enumToInt(item_inst); 6317 break :blk header_index + 1; 6318 }; 6319 6320 { 6321 // temporarily stack case_scope on parent_gz 6322 case_scope.instructions_top = parent_gz.instructions.items.len; 6323 defer case_scope.unstack(); 6324 6325 if (capture_inst != 0) try case_scope.instructions.append(gpa, capture_inst); 6326 try case_scope.addDbgBlockBegin(); 6327 if (dbg_var_name) |some| { 6328 try case_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst); 6329 } 6330 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); 6331 try checkUsed(parent_gz, &case_scope.base, sub_scope); 6332 try case_scope.addDbgBlockEnd(); 6333 if (!parent_gz.refIsNoReturn(case_result)) { 6334 block_scope.break_count += 1; 6335 _ = try case_scope.addBreak(.@"break", switch_block, case_result); 6336 } 6337 6338 const case_slice = case_scope.instructionsSlice(); 6339 const body_len = astgen.countBodyLenAfterFixups(case_slice); 6340 try payloads.ensureUnusedCapacity(gpa, body_len); 6341 payloads.items[body_len_index] = body_len; 6342 appendBodyWithFixupsArrayList(astgen, payloads, case_slice); 6343 } 6344 } 6345 // Now that the item expressions are generated we can add this. 6346 try parent_gz.instructions.append(gpa, switch_block); 6347 6348 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.SwitchBlock).Struct.fields.len + 6349 @boolToInt(multi_cases_len != 0) + 6350 payloads.items.len - case_table_end); 6351 6352 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.SwitchBlock{ 6353 .operand = cond, 6354 .bits = Zir.Inst.SwitchBlock.Bits{ 6355 .is_ref = any_payload_is_ref, 6356 .has_multi_cases = multi_cases_len != 0, 6357 .has_else = special_prong == .@"else", 6358 .has_under = special_prong == .under, 6359 .scalar_cases_len = @intCast(Zir.Inst.SwitchBlock.Bits.ScalarCasesLen, scalar_cases_len), 6360 }, 6361 }); 6362 6363 if (multi_cases_len != 0) { 6364 astgen.extra.appendAssumeCapacity(multi_cases_len); 6365 } 6366 6367 const zir_datas = astgen.instructions.items(.data); 6368 const zir_tags = astgen.instructions.items(.tag); 6369 6370 zir_datas[switch_block].pl_node.payload_index = payload_index; 6371 6372 const strat = rl.strategy(&block_scope); 6373 for (payloads.items[case_table_start..case_table_end]) |start_index, i| { 6374 var body_len_index = start_index; 6375 var end_index = start_index; 6376 const table_index = case_table_start + i; 6377 if (table_index < scalar_case_table) { 6378 end_index += 1; 6379 } else if (table_index < multi_case_table) { 6380 body_len_index += 1; 6381 end_index += 2; 6382 } else { 6383 body_len_index += 2; 6384 const items_len = payloads.items[start_index]; 6385 const ranges_len = payloads.items[start_index + 1]; 6386 end_index += 3 + items_len + 2 * ranges_len; 6387 } 6388 6389 const body_len = payloads.items[body_len_index]; 6390 end_index += body_len; 6391 6392 switch (strat.tag) { 6393 .break_operand => blk: { 6394 // Switch expressions return `true` for `nodeMayNeedMemoryLocation` thus 6395 // `elide_store_to_block_ptr_instructions` will either be true, 6396 // or all prongs are noreturn. 6397 if (!strat.elide_store_to_block_ptr_instructions) 6398 break :blk; 6399 6400 // There will necessarily be a store_to_block_ptr for 6401 // all prongs, except for prongs that ended with a noreturn instruction. 6402 // Elide all the `store_to_block_ptr` instructions. 6403 6404 // The break instructions need to have their operands coerced if the 6405 // switch's result location is a `ty`. In this case we overwrite the 6406 // `store_to_block_ptr` instruction with an `as` instruction and repurpose 6407 // it as the break operand. 6408 if (body_len < 2) 6409 break :blk; 6410 const store_inst = payloads.items[end_index - 2]; 6411 if (zir_tags[store_inst] != .store_to_block_ptr or 6412 zir_datas[store_inst].bin.lhs != block_scope.rl_ptr) 6413 break :blk; 6414 const break_inst = payloads.items[end_index - 1]; 6415 if (block_scope.rl_ty_inst != .none) { 6416 zir_tags[store_inst] = .as; 6417 zir_datas[store_inst].bin = .{ 6418 .lhs = block_scope.rl_ty_inst, 6419 .rhs = zir_datas[break_inst].@"break".operand, 6420 }; 6421 zir_datas[break_inst].@"break".operand = indexToRef(store_inst); 6422 } else { 6423 payloads.items[body_len_index] -= 1; 6424 astgen.extra.appendSliceAssumeCapacity(payloads.items[start_index .. end_index - 2]); 6425 astgen.extra.appendAssumeCapacity(break_inst); 6426 continue; 6427 } 6428 }, 6429 .break_void => { 6430 assert(!strat.elide_store_to_block_ptr_instructions); 6431 const last_inst = payloads.items[end_index - 1]; 6432 if (zir_tags[last_inst] == .@"break" and 6433 zir_datas[last_inst].@"break".block_inst == switch_block) 6434 { 6435 zir_datas[last_inst].@"break".operand = .void_value; 6436 } 6437 }, 6438 } 6439 6440 astgen.extra.appendSliceAssumeCapacity(payloads.items[start_index..end_index]); 6441 } 6442 6443 const block_ref = indexToRef(switch_block); 6444 if (strat.tag == .break_operand and strat.elide_store_to_block_ptr_instructions and rl != .ref) 6445 return rvalue(parent_gz, rl, block_ref, switch_node); 6446 return block_ref; 6447 } 6448 6449 fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 6450 const astgen = gz.astgen; 6451 const tree = astgen.tree; 6452 const node_datas = tree.nodes.items(.data); 6453 const node_tags = tree.nodes.items(.tag); 6454 6455 if (astgen.fn_block == null) { 6456 return astgen.failNode(node, "'return' outside function scope", .{}); 6457 } 6458 6459 if (gz.in_defer) return astgen.failNode(node, "cannot return from defer expression", .{}); 6460 6461 const defer_outer = &astgen.fn_block.?.base; 6462 6463 const operand_node = node_datas[node].lhs; 6464 if (operand_node == 0) { 6465 // Returning a void value; skip error defers. 6466 try genDefers(gz, defer_outer, scope, .normal_only); 6467 _ = try gz.addUnNode(.ret_node, .void_value, node); 6468 return Zir.Inst.Ref.unreachable_value; 6469 } 6470 6471 if (node_tags[operand_node] == .error_value) { 6472 // Hot path for `return error.Foo`. This bypasses result location logic as well as logic 6473 // for detecting whether to add something to the function's inferred error set. 6474 const ident_token = node_datas[operand_node].rhs; 6475 const err_name_str_index = try astgen.identAsString(ident_token); 6476 const defer_counts = countDefers(astgen, defer_outer, scope); 6477 if (!defer_counts.need_err_code) { 6478 try genDefers(gz, defer_outer, scope, .both_sans_err); 6479 _ = try gz.addStrTok(.ret_err_value, err_name_str_index, ident_token); 6480 return Zir.Inst.Ref.unreachable_value; 6481 } 6482 const err_code = try gz.addStrTok(.ret_err_value_code, err_name_str_index, ident_token); 6483 try genDefers(gz, defer_outer, scope, .{ .both = err_code }); 6484 _ = try gz.addUnNode(.ret_node, err_code, node); 6485 return Zir.Inst.Ref.unreachable_value; 6486 } 6487 6488 const rl: ResultLoc = if (nodeMayNeedMemoryLocation(tree, operand_node, true)) .{ 6489 .ptr = try gz.addNode(.ret_ptr, node), 6490 } else .{ 6491 .ty = try gz.addNode(.ret_type, node), 6492 }; 6493 const prev_anon_name_strategy = gz.anon_name_strategy; 6494 gz.anon_name_strategy = .func; 6495 const operand = try reachableExpr(gz, scope, rl, operand_node, node); 6496 gz.anon_name_strategy = prev_anon_name_strategy; 6497 6498 switch (nodeMayEvalToError(tree, operand_node)) { 6499 .never => { 6500 // Returning a value that cannot be an error; skip error defers. 6501 try genDefers(gz, defer_outer, scope, .normal_only); 6502 try gz.addRet(rl, operand, node); 6503 return Zir.Inst.Ref.unreachable_value; 6504 }, 6505 .always => { 6506 // Value is always an error. Emit both error defers and regular defers. 6507 const result = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand; 6508 const err_code = try gz.addUnNode(.err_union_code, result, node); 6509 try genDefers(gz, defer_outer, scope, .{ .both = err_code }); 6510 try gz.addRet(rl, operand, node); 6511 return Zir.Inst.Ref.unreachable_value; 6512 }, 6513 .maybe => { 6514 const defer_counts = countDefers(astgen, defer_outer, scope); 6515 if (!defer_counts.have_err) { 6516 // Only regular defers; no branch needed. 6517 try genDefers(gz, defer_outer, scope, .normal_only); 6518 try gz.addRet(rl, operand, node); 6519 return Zir.Inst.Ref.unreachable_value; 6520 } 6521 6522 // Emit conditional branch for generating errdefers. 6523 const result = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand; 6524 const is_non_err = try gz.addUnNode(.is_non_err, result, node); 6525 const condbr = try gz.addCondBr(.condbr, node); 6526 6527 var then_scope = gz.makeSubBlock(scope); 6528 defer then_scope.unstack(); 6529 6530 try genDefers(&then_scope, defer_outer, scope, .normal_only); 6531 try then_scope.addRet(rl, operand, node); 6532 6533 var else_scope = gz.makeSubBlock(scope); 6534 defer else_scope.unstack(); 6535 6536 const which_ones: DefersToEmit = if (!defer_counts.need_err_code) .both_sans_err else .{ 6537 .both = try else_scope.addUnNode(.err_union_code, result, node), 6538 }; 6539 try genDefers(&else_scope, defer_outer, scope, which_ones); 6540 try else_scope.addRet(rl, operand, node); 6541 6542 try setCondBrPayload(condbr, is_non_err, &then_scope, 0, &else_scope, 0); 6543 6544 return Zir.Inst.Ref.unreachable_value; 6545 }, 6546 } 6547 } 6548 6549 /// Parses the string `buf` as a base 10 integer of type `u16`. 6550 /// 6551 /// Unlike std.fmt.parseInt, does not allow the '_' character in `buf`. 6552 fn parseBitCount(buf: []const u8) std.fmt.ParseIntError!u16 { 6553 if (buf.len == 0) return error.InvalidCharacter; 6554 6555 var x: u16 = 0; 6556 6557 for (buf) |c| { 6558 const digit = switch (c) { 6559 '0'...'9' => c - '0', 6560 else => return error.InvalidCharacter, 6561 }; 6562 6563 if (x != 0) x = try std.math.mul(u16, x, 10); 6564 x = try std.math.add(u16, x, @as(u16, digit)); 6565 } 6566 6567 return x; 6568 } 6569 6570 fn identifier( 6571 gz: *GenZir, 6572 scope: *Scope, 6573 rl: ResultLoc, 6574 ident: Ast.Node.Index, 6575 ) InnerError!Zir.Inst.Ref { 6576 const tracy = trace(@src()); 6577 defer tracy.end(); 6578 6579 const astgen = gz.astgen; 6580 const tree = astgen.tree; 6581 const main_tokens = tree.nodes.items(.main_token); 6582 6583 const ident_token = main_tokens[ident]; 6584 const ident_name_raw = tree.tokenSlice(ident_token); 6585 if (mem.eql(u8, ident_name_raw, "_")) { 6586 return astgen.failNode(ident, "'_' used as an identifier without @\"_\" syntax", .{}); 6587 } 6588 6589 // if not @"" syntax, just use raw token slice 6590 if (ident_name_raw[0] != '@') { 6591 if (primitives.get(ident_name_raw)) |zir_const_ref| { 6592 return rvalue(gz, rl, zir_const_ref, ident); 6593 } 6594 6595 if (ident_name_raw.len >= 2) integer: { 6596 const first_c = ident_name_raw[0]; 6597 if (first_c == 'i' or first_c == 'u') { 6598 const signedness: std.builtin.Signedness = switch (first_c == 'i') { 6599 true => .signed, 6600 false => .unsigned, 6601 }; 6602 const bit_count = parseBitCount(ident_name_raw[1..]) catch |err| switch (err) { 6603 error.Overflow => return astgen.failNode( 6604 ident, 6605 "primitive integer type '{s}' exceeds maximum bit width of 65535", 6606 .{ident_name_raw}, 6607 ), 6608 error.InvalidCharacter => break :integer, 6609 }; 6610 const result = try gz.add(.{ 6611 .tag = .int_type, 6612 .data = .{ .int_type = .{ 6613 .src_node = gz.nodeIndexToRelative(ident), 6614 .signedness = signedness, 6615 .bit_count = bit_count, 6616 } }, 6617 }); 6618 return rvalue(gz, rl, result, ident); 6619 } 6620 } 6621 } 6622 6623 // Local variables, including function parameters. 6624 return localVarRef(gz, scope, rl, ident, ident_token); 6625 } 6626 6627 fn localVarRef( 6628 gz: *GenZir, 6629 scope: *Scope, 6630 rl: ResultLoc, 6631 ident: Ast.Node.Index, 6632 ident_token: Ast.Node.Index, 6633 ) InnerError!Zir.Inst.Ref { 6634 const astgen = gz.astgen; 6635 const gpa = astgen.gpa; 6636 6637 const name_str_index = try astgen.identAsString(ident_token); 6638 var s = scope; 6639 var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already 6640 var num_namespaces_out: u32 = 0; 6641 var capturing_namespace: ?*Scope.Namespace = null; 6642 while (true) switch (s.tag) { 6643 .local_val => { 6644 const local_val = s.cast(Scope.LocalVal).?; 6645 6646 if (local_val.name == name_str_index) { 6647 // Locals cannot shadow anything, so we do not need to look for ambiguous 6648 // references in this case. 6649 local_val.used = true; 6650 6651 const value_inst = try tunnelThroughClosure( 6652 gz, 6653 ident, 6654 num_namespaces_out, 6655 capturing_namespace, 6656 local_val.inst, 6657 local_val.token_src, 6658 gpa, 6659 ); 6660 6661 return rvalue(gz, rl, value_inst, ident); 6662 } 6663 s = local_val.parent; 6664 }, 6665 .local_ptr => { 6666 const local_ptr = s.cast(Scope.LocalPtr).?; 6667 if (local_ptr.name == name_str_index) { 6668 local_ptr.used = true; 6669 6670 // Can't close over a runtime variable 6671 if (num_namespaces_out != 0 and !local_ptr.maybe_comptime) { 6672 const ident_name = try astgen.identifierTokenString(ident_token); 6673 return astgen.failNodeNotes(ident, "mutable '{s}' not accessible from here", .{ident_name}, &.{ 6674 try astgen.errNoteTok(local_ptr.token_src, "declared mutable here", .{}), 6675 try astgen.errNoteNode(capturing_namespace.?.node, "crosses namespace boundary here", .{}), 6676 }); 6677 } 6678 6679 const ptr_inst = try tunnelThroughClosure( 6680 gz, 6681 ident, 6682 num_namespaces_out, 6683 capturing_namespace, 6684 local_ptr.ptr, 6685 local_ptr.token_src, 6686 gpa, 6687 ); 6688 6689 switch (rl) { 6690 .ref => return ptr_inst, 6691 else => { 6692 const loaded = try gz.addUnNode(.load, ptr_inst, ident); 6693 return rvalue(gz, rl, loaded, ident); 6694 }, 6695 } 6696 } 6697 s = local_ptr.parent; 6698 }, 6699 .gen_zir => s = s.cast(GenZir).?.parent, 6700 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, 6701 .namespace => { 6702 const ns = s.cast(Scope.Namespace).?; 6703 if (ns.decls.get(name_str_index)) |i| { 6704 if (found_already) |f| { 6705 return astgen.failNodeNotes(ident, "ambiguous reference", .{}, &.{ 6706 try astgen.errNoteNode(f, "declared here", .{}), 6707 try astgen.errNoteNode(i, "also declared here", .{}), 6708 }); 6709 } 6710 // We found a match but must continue looking for ambiguous references to decls. 6711 found_already = i; 6712 } 6713 num_namespaces_out += 1; 6714 capturing_namespace = ns; 6715 s = ns.parent; 6716 }, 6717 .top => break, 6718 }; 6719 if (found_already == null) { 6720 const ident_name = try astgen.identifierTokenString(ident_token); 6721 return astgen.failNode(ident, "use of undeclared identifier '{s}'", .{ident_name}); 6722 } 6723 6724 // Decl references happen by name rather than ZIR index so that when unrelated 6725 // decls are modified, ZIR code containing references to them can be unmodified. 6726 switch (rl) { 6727 .ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token), 6728 else => { 6729 const result = try gz.addStrTok(.decl_val, name_str_index, ident_token); 6730 return rvalue(gz, rl, result, ident); 6731 }, 6732 } 6733 } 6734 6735 /// Adds a capture to a namespace, if needed. 6736 /// Returns the index of the closure_capture instruction. 6737 fn tunnelThroughClosure( 6738 gz: *GenZir, 6739 inner_ref_node: Ast.Node.Index, 6740 num_tunnels: u32, 6741 ns: ?*Scope.Namespace, 6742 value: Zir.Inst.Ref, 6743 token: Ast.TokenIndex, 6744 gpa: Allocator, 6745 ) !Zir.Inst.Ref { 6746 // For trivial values, we don't need a tunnel. 6747 // Just return the ref. 6748 if (num_tunnels == 0 or refToIndex(value) == null) { 6749 return value; 6750 } 6751 6752 // Otherwise we need a tunnel. Check if this namespace 6753 // already has one for this value. 6754 const gop = try ns.?.captures.getOrPut(gpa, refToIndex(value).?); 6755 if (!gop.found_existing) { 6756 // Make a new capture for this value but don't add it to the declaring_gz yet 6757 try gz.astgen.instructions.append(gz.astgen.gpa, .{ 6758 .tag = .closure_capture, 6759 .data = .{ .un_tok = .{ 6760 .operand = value, 6761 .src_tok = ns.?.declaring_gz.?.tokenIndexToRelative(token), 6762 } }, 6763 }); 6764 gop.value_ptr.* = @intCast(Zir.Inst.Index, gz.astgen.instructions.len - 1); 6765 } 6766 6767 // Add an instruction to get the value from the closure into 6768 // our current context 6769 return try gz.addInstNode(.closure_get, gop.value_ptr.*, inner_ref_node); 6770 } 6771 6772 fn stringLiteral( 6773 gz: *GenZir, 6774 rl: ResultLoc, 6775 node: Ast.Node.Index, 6776 ) InnerError!Zir.Inst.Ref { 6777 const astgen = gz.astgen; 6778 const tree = astgen.tree; 6779 const main_tokens = tree.nodes.items(.main_token); 6780 const str_lit_token = main_tokens[node]; 6781 const str = try astgen.strLitAsString(str_lit_token); 6782 const result = try gz.add(.{ 6783 .tag = .str, 6784 .data = .{ .str = .{ 6785 .start = str.index, 6786 .len = str.len, 6787 } }, 6788 }); 6789 return rvalue(gz, rl, result, node); 6790 } 6791 6792 fn multilineStringLiteral( 6793 gz: *GenZir, 6794 rl: ResultLoc, 6795 node: Ast.Node.Index, 6796 ) InnerError!Zir.Inst.Ref { 6797 const astgen = gz.astgen; 6798 const str = try astgen.strLitNodeAsString(node); 6799 const result = try gz.add(.{ 6800 .tag = .str, 6801 .data = .{ .str = .{ 6802 .start = str.index, 6803 .len = str.len, 6804 } }, 6805 }); 6806 return rvalue(gz, rl, result, node); 6807 } 6808 6809 fn charLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 6810 const astgen = gz.astgen; 6811 const tree = astgen.tree; 6812 const main_tokens = tree.nodes.items(.main_token); 6813 const main_token = main_tokens[node]; 6814 const slice = tree.tokenSlice(main_token); 6815 6816 switch (std.zig.parseCharLiteral(slice)) { 6817 .success => |codepoint| { 6818 const result = try gz.addInt(codepoint); 6819 return rvalue(gz, rl, result, node); 6820 }, 6821 .failure => |err| return astgen.failWithStrLitError(err, main_token, slice, 0), 6822 } 6823 } 6824 6825 fn integerLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 6826 const astgen = gz.astgen; 6827 const tree = astgen.tree; 6828 const main_tokens = tree.nodes.items(.main_token); 6829 const int_token = main_tokens[node]; 6830 const prefixed_bytes = tree.tokenSlice(int_token); 6831 if (std.fmt.parseInt(u64, prefixed_bytes, 0)) |small_int| { 6832 const result: Zir.Inst.Ref = switch (small_int) { 6833 0 => .zero, 6834 1 => .one, 6835 else => try gz.addInt(small_int), 6836 }; 6837 return rvalue(gz, rl, result, node); 6838 } else |err| switch (err) { 6839 error.InvalidCharacter => unreachable, // Caught by the parser. 6840 error.Overflow => {}, 6841 } 6842 6843 var base: u8 = 10; 6844 var non_prefixed: []const u8 = prefixed_bytes; 6845 if (mem.startsWith(u8, prefixed_bytes, "0x")) { 6846 base = 16; 6847 non_prefixed = prefixed_bytes[2..]; 6848 } else if (mem.startsWith(u8, prefixed_bytes, "0o")) { 6849 base = 8; 6850 non_prefixed = prefixed_bytes[2..]; 6851 } else if (mem.startsWith(u8, prefixed_bytes, "0b")) { 6852 base = 2; 6853 non_prefixed = prefixed_bytes[2..]; 6854 } 6855 6856 const gpa = astgen.gpa; 6857 var big_int = try std.math.big.int.Managed.init(gpa); 6858 defer big_int.deinit(); 6859 big_int.setString(base, non_prefixed) catch |err| switch (err) { 6860 error.InvalidCharacter => unreachable, // caught by parser 6861 error.InvalidBase => unreachable, // we only pass 16, 8, 2, see above 6862 error.OutOfMemory => return error.OutOfMemory, 6863 }; 6864 6865 const limbs = big_int.limbs[0..big_int.len()]; 6866 assert(big_int.isPositive()); 6867 const result = try gz.addIntBig(limbs); 6868 return rvalue(gz, rl, result, node); 6869 } 6870 6871 const Sign = enum { negative, positive }; 6872 6873 fn floatLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index, sign: Sign) InnerError!Zir.Inst.Ref { 6874 const astgen = gz.astgen; 6875 const tree = astgen.tree; 6876 const main_tokens = tree.nodes.items(.main_token); 6877 6878 const main_token = main_tokens[node]; 6879 const bytes = tree.tokenSlice(main_token); 6880 const unsigned_float_number = std.fmt.parseFloat(f128, bytes) catch |err| switch (err) { 6881 error.InvalidCharacter => unreachable, // validated by tokenizer 6882 }; 6883 const float_number = switch (sign) { 6884 .negative => -unsigned_float_number, 6885 .positive => unsigned_float_number, 6886 }; 6887 // If the value fits into a f64 without losing any precision, store it that way. 6888 @setFloatMode(.Strict); 6889 const smaller_float = @floatCast(f64, float_number); 6890 const bigger_again: f128 = smaller_float; 6891 if (bigger_again == float_number) { 6892 const result = try gz.addFloat(smaller_float); 6893 return rvalue(gz, rl, result, node); 6894 } 6895 // We need to use 128 bits. Break the float into 4 u32 values so we can 6896 // put it into the `extra` array. 6897 const int_bits = @bitCast(u128, float_number); 6898 const result = try gz.addPlNode(.float128, node, Zir.Inst.Float128{ 6899 .piece0 = @truncate(u32, int_bits), 6900 .piece1 = @truncate(u32, int_bits >> 32), 6901 .piece2 = @truncate(u32, int_bits >> 64), 6902 .piece3 = @truncate(u32, int_bits >> 96), 6903 }); 6904 return rvalue(gz, rl, result, node); 6905 } 6906 6907 fn asmExpr( 6908 gz: *GenZir, 6909 scope: *Scope, 6910 rl: ResultLoc, 6911 node: Ast.Node.Index, 6912 full: Ast.full.Asm, 6913 ) InnerError!Zir.Inst.Ref { 6914 const astgen = gz.astgen; 6915 const tree = astgen.tree; 6916 const main_tokens = tree.nodes.items(.main_token); 6917 const node_datas = tree.nodes.items(.data); 6918 const node_tags = tree.nodes.items(.tag); 6919 const token_tags = tree.tokens.items(.tag); 6920 6921 const asm_source = switch (node_tags[full.ast.template]) { 6922 .string_literal => try astgen.strLitAsString(main_tokens[full.ast.template]), 6923 .multiline_string_literal => try astgen.strLitNodeAsString(full.ast.template), 6924 else => blk: { 6925 // stage1 allows this, and until we do another design iteration on inline assembly 6926 // in stage2 to improve support for the various needed use cases, we allow inline 6927 // assembly templates to be an expression. Once stage2 addresses the real world needs 6928 // of people using inline assembly (primarily OS developers) then we can re-institute 6929 // the rule into AstGen that assembly code must use string literal syntax. 6930 //return astgen.failNode(full.ast.template, "assembly code must use string literal syntax", .{}), 6931 // We still need to trigger all the expr() calls here to avoid errors for unused things. 6932 // So we pass 0 as the asm source and stage2 Sema will notice this and 6933 // report the error. 6934 _ = try comptimeExpr(gz, scope, .none, full.ast.template); 6935 break :blk IndexSlice{ .index = 0, .len = 0 }; 6936 }, 6937 }; 6938 6939 // See https://github.com/ziglang/zig/issues/215 and related issues discussing 6940 // possible inline assembly improvements. Until then here is status quo AstGen 6941 // for assembly syntax. It's used by std lib crypto aesni.zig. 6942 const is_container_asm = astgen.fn_block == null; 6943 if (is_container_asm) { 6944 if (full.volatile_token) |t| 6945 return astgen.failTok(t, "volatile is meaningless on global assembly", .{}); 6946 if (full.outputs.len != 0 or full.inputs.len != 0 or full.first_clobber != null) 6947 return astgen.failNode(node, "global assembly cannot have inputs, outputs, or clobbers", .{}); 6948 } else { 6949 if (full.outputs.len == 0 and full.volatile_token == null) { 6950 return astgen.failNode(node, "assembly expression with no output must be marked volatile", .{}); 6951 } 6952 } 6953 if (full.outputs.len > 32) { 6954 return astgen.failNode(full.outputs[32], "too many asm outputs", .{}); 6955 } 6956 var outputs_buffer: [32]Zir.Inst.Asm.Output = undefined; 6957 const outputs = outputs_buffer[0..full.outputs.len]; 6958 6959 var output_type_bits: u32 = 0; 6960 6961 for (full.outputs) |output_node, i| { 6962 const symbolic_name = main_tokens[output_node]; 6963 const name = try astgen.identAsString(symbolic_name); 6964 const constraint_token = symbolic_name + 2; 6965 const constraint = (try astgen.strLitAsString(constraint_token)).index; 6966 const has_arrow = token_tags[symbolic_name + 4] == .arrow; 6967 if (has_arrow) { 6968 if (output_type_bits != 0) { 6969 return astgen.failNode(output_node, "inline assembly allows up to one output value", .{}); 6970 } 6971 output_type_bits |= @as(u32, 1) << @intCast(u5, i); 6972 const out_type_node = node_datas[output_node].lhs; 6973 const out_type_inst = try typeExpr(gz, scope, out_type_node); 6974 outputs[i] = .{ 6975 .name = name, 6976 .constraint = constraint, 6977 .operand = out_type_inst, 6978 }; 6979 } else { 6980 const ident_token = symbolic_name + 4; 6981 // TODO have a look at #215 and related issues and decide how to 6982 // handle outputs. Do we want this to be identifiers? 6983 // Or maybe we want to force this to be expressions with a pointer type. 6984 outputs[i] = .{ 6985 .name = name, 6986 .constraint = constraint, 6987 .operand = try localVarRef(gz, scope, .ref, node, ident_token), 6988 }; 6989 } 6990 } 6991 6992 if (full.inputs.len > 32) { 6993 return astgen.failNode(full.inputs[32], "too many asm inputs", .{}); 6994 } 6995 var inputs_buffer: [32]Zir.Inst.Asm.Input = undefined; 6996 const inputs = inputs_buffer[0..full.inputs.len]; 6997 6998 for (full.inputs) |input_node, i| { 6999 const symbolic_name = main_tokens[input_node]; 7000 const name = try astgen.identAsString(symbolic_name); 7001 const constraint_token = symbolic_name + 2; 7002 const constraint = (try astgen.strLitAsString(constraint_token)).index; 7003 const operand = try expr(gz, scope, .none, node_datas[input_node].lhs); 7004 inputs[i] = .{ 7005 .name = name, 7006 .constraint = constraint, 7007 .operand = operand, 7008 }; 7009 } 7010 7011 var clobbers_buffer: [32]u32 = undefined; 7012 var clobber_i: usize = 0; 7013 if (full.first_clobber) |first_clobber| clobbers: { 7014 // asm ("foo" ::: "a", "b") 7015 // asm ("foo" ::: "a", "b",) 7016 var tok_i = first_clobber; 7017 while (true) : (tok_i += 1) { 7018 if (clobber_i >= clobbers_buffer.len) { 7019 return astgen.failTok(tok_i, "too many asm clobbers", .{}); 7020 } 7021 clobbers_buffer[clobber_i] = (try astgen.strLitAsString(tok_i)).index; 7022 clobber_i += 1; 7023 tok_i += 1; 7024 switch (token_tags[tok_i]) { 7025 .r_paren => break :clobbers, 7026 .comma => { 7027 if (token_tags[tok_i + 1] == .r_paren) { 7028 break :clobbers; 7029 } else { 7030 continue; 7031 } 7032 }, 7033 else => unreachable, 7034 } 7035 } 7036 } 7037 7038 const result = try gz.addAsm(.{ 7039 .node = node, 7040 .asm_source = asm_source.index, 7041 .is_volatile = full.volatile_token != null, 7042 .output_type_bits = output_type_bits, 7043 .outputs = outputs, 7044 .inputs = inputs, 7045 .clobbers = clobbers_buffer[0..clobber_i], 7046 }); 7047 return rvalue(gz, rl, result, node); 7048 } 7049 7050 fn as( 7051 gz: *GenZir, 7052 scope: *Scope, 7053 rl: ResultLoc, 7054 node: Ast.Node.Index, 7055 lhs: Ast.Node.Index, 7056 rhs: Ast.Node.Index, 7057 ) InnerError!Zir.Inst.Ref { 7058 const dest_type = try typeExpr(gz, scope, lhs); 7059 switch (rl) { 7060 .none, .discard, .ref, .ty, .coerced_ty => { 7061 const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node); 7062 return rvalue(gz, rl, result, node); 7063 }, 7064 .ptr, .inferred_ptr => |result_ptr| { 7065 return asRlPtr(gz, scope, rl, node, result_ptr, rhs, dest_type); 7066 }, 7067 .block_ptr => |block_scope| { 7068 return asRlPtr(gz, scope, rl, node, block_scope.rl_ptr, rhs, dest_type); 7069 }, 7070 } 7071 } 7072 7073 fn unionInit( 7074 gz: *GenZir, 7075 scope: *Scope, 7076 rl: ResultLoc, 7077 node: Ast.Node.Index, 7078 params: []const Ast.Node.Index, 7079 ) InnerError!Zir.Inst.Ref { 7080 const union_type = try typeExpr(gz, scope, params[0]); 7081 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); 7082 const field_type = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{ 7083 .container_type = union_type, 7084 .field_name = field_name, 7085 }); 7086 const init = try reachableExpr(gz, scope, .{ .ty = field_type }, params[2], node); 7087 const result = try gz.addPlNode(.union_init, node, Zir.Inst.UnionInit{ 7088 .union_type = union_type, 7089 .init = init, 7090 .field_name = field_name, 7091 }); 7092 return rvalue(gz, rl, result, node); 7093 } 7094 7095 fn asRlPtr( 7096 parent_gz: *GenZir, 7097 scope: *Scope, 7098 rl: ResultLoc, 7099 src_node: Ast.Node.Index, 7100 result_ptr: Zir.Inst.Ref, 7101 operand_node: Ast.Node.Index, 7102 dest_type: Zir.Inst.Ref, 7103 ) InnerError!Zir.Inst.Ref { 7104 var as_scope = try parent_gz.makeCoercionScope(scope, dest_type, result_ptr, src_node); 7105 defer as_scope.unstack(); 7106 7107 const result = try reachableExpr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node, src_node); 7108 return as_scope.finishCoercion(parent_gz, rl, operand_node, result, dest_type); 7109 } 7110 7111 fn bitCast( 7112 gz: *GenZir, 7113 scope: *Scope, 7114 rl: ResultLoc, 7115 node: Ast.Node.Index, 7116 lhs: Ast.Node.Index, 7117 rhs: Ast.Node.Index, 7118 ) InnerError!Zir.Inst.Ref { 7119 const dest_type = try reachableTypeExpr(gz, scope, lhs, node); 7120 const operand = try reachableExpr(gz, scope, .none, rhs, node); 7121 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{ 7122 .lhs = dest_type, 7123 .rhs = operand, 7124 }); 7125 return rvalue(gz, rl, result, node); 7126 } 7127 7128 fn typeOf( 7129 gz: *GenZir, 7130 scope: *Scope, 7131 rl: ResultLoc, 7132 node: Ast.Node.Index, 7133 args: []const Ast.Node.Index, 7134 ) InnerError!Zir.Inst.Ref { 7135 const astgen = gz.astgen; 7136 if (args.len < 1) { 7137 return astgen.failNode(node, "expected at least 1 argument, found 0", .{}); 7138 } 7139 const gpa = astgen.gpa; 7140 if (args.len == 1) { 7141 const typeof_inst = try gz.makeBlockInst(.typeof_builtin, node); 7142 7143 var typeof_scope = gz.makeSubBlock(scope); 7144 typeof_scope.force_comptime = false; 7145 defer typeof_scope.unstack(); 7146 7147 const ty_expr = try reachableExpr(&typeof_scope, &typeof_scope.base, .none, args[0], node); 7148 if (!gz.refIsNoReturn(ty_expr)) { 7149 _ = try typeof_scope.addBreak(.break_inline, typeof_inst, ty_expr); 7150 } 7151 try typeof_scope.setBlockBody(typeof_inst); 7152 7153 // typeof_scope unstacked now, can add new instructions to gz 7154 try gz.instructions.append(gpa, typeof_inst); 7155 return rvalue(gz, rl, indexToRef(typeof_inst), node); 7156 } 7157 const payload_size: u32 = std.meta.fields(Zir.Inst.TypeOfPeer).len; 7158 const payload_index = try reserveExtra(astgen, payload_size + args.len); 7159 var args_index = payload_index + payload_size; 7160 7161 const typeof_inst = try gz.addExtendedMultiOpPayloadIndex(.typeof_peer, payload_index, args.len); 7162 7163 var typeof_scope = gz.makeSubBlock(scope); 7164 typeof_scope.force_comptime = false; 7165 7166 for (args) |arg, i| { 7167 const param_ref = try reachableExpr(&typeof_scope, &typeof_scope.base, .none, arg, node); 7168 astgen.extra.items[args_index + i] = @enumToInt(param_ref); 7169 } 7170 _ = try typeof_scope.addBreak(.break_inline, refToIndex(typeof_inst).?, .void_value); 7171 7172 const body = typeof_scope.instructionsSlice(); 7173 const body_len = astgen.countBodyLenAfterFixups(body); 7174 astgen.setExtra(payload_index, Zir.Inst.TypeOfPeer{ 7175 .body_len = @intCast(u32, body_len), 7176 .body_index = @intCast(u32, astgen.extra.items.len), 7177 .src_node = gz.nodeIndexToRelative(node), 7178 }); 7179 try astgen.extra.ensureUnusedCapacity(gpa, body_len); 7180 astgen.appendBodyWithFixups(body); 7181 typeof_scope.unstack(); 7182 7183 return rvalue(gz, rl, typeof_inst, node); 7184 } 7185 7186 fn builtinCall( 7187 gz: *GenZir, 7188 scope: *Scope, 7189 rl: ResultLoc, 7190 node: Ast.Node.Index, 7191 params: []const Ast.Node.Index, 7192 ) InnerError!Zir.Inst.Ref { 7193 const astgen = gz.astgen; 7194 const tree = astgen.tree; 7195 const main_tokens = tree.nodes.items(.main_token); 7196 7197 const builtin_token = main_tokens[node]; 7198 const builtin_name = tree.tokenSlice(builtin_token); 7199 7200 // We handle the different builtins manually because they have different semantics depending 7201 // on the function. For example, `@as` and others participate in result location semantics, 7202 // and `@cImport` creates a special scope that collects a .c source code text buffer. 7203 // Also, some builtins have a variable number of parameters. 7204 7205 const info = BuiltinFn.list.get(builtin_name) orelse { 7206 return astgen.failNode(node, "invalid builtin function: '{s}'", .{ 7207 builtin_name, 7208 }); 7209 }; 7210 if (info.param_count) |expected| { 7211 if (expected != params.len) { 7212 const s = if (expected == 1) "" else "s"; 7213 return astgen.failNode(node, "expected {d} argument{s}, found {d}", .{ 7214 expected, s, params.len, 7215 }); 7216 } 7217 } 7218 7219 switch (info.tag) { 7220 .import => { 7221 const node_tags = tree.nodes.items(.tag); 7222 const operand_node = params[0]; 7223 7224 if (node_tags[operand_node] != .string_literal) { 7225 // Spec reference: https://github.com/ziglang/zig/issues/2206 7226 return astgen.failNode(operand_node, "@import operand must be a string literal", .{}); 7227 } 7228 const str_lit_token = main_tokens[operand_node]; 7229 const str = try astgen.strLitAsString(str_lit_token); 7230 const result = try gz.addStrTok(.import, str.index, str_lit_token); 7231 const gop = try astgen.imports.getOrPut(astgen.gpa, str.index); 7232 if (!gop.found_existing) { 7233 gop.value_ptr.* = str_lit_token; 7234 } 7235 return rvalue(gz, rl, result, node); 7236 }, 7237 .compile_log => { 7238 const payload_index = try addExtra(gz.astgen, Zir.Inst.NodeMultiOp{ 7239 .src_node = gz.nodeIndexToRelative(node), 7240 }); 7241 var extra_index = try reserveExtra(gz.astgen, params.len); 7242 for (params) |param| { 7243 const param_ref = try expr(gz, scope, .none, param); 7244 astgen.extra.items[extra_index] = @enumToInt(param_ref); 7245 extra_index += 1; 7246 } 7247 const result = try gz.addExtendedMultiOpPayloadIndex(.compile_log, payload_index, params.len); 7248 return rvalue(gz, rl, result, node); 7249 }, 7250 .field => { 7251 if (rl == .ref) { 7252 return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{ 7253 .lhs = try expr(gz, scope, .ref, params[0]), 7254 .field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]), 7255 }); 7256 } 7257 const result = try gz.addPlNode(.field_val_named, node, Zir.Inst.FieldNamed{ 7258 .lhs = try expr(gz, scope, .none, params[0]), 7259 .field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]), 7260 }); 7261 return rvalue(gz, rl, result, node); 7262 }, 7263 7264 // zig fmt: off 7265 .as => return as( gz, scope, rl, node, params[0], params[1]), 7266 .bit_cast => return bitCast( gz, scope, rl, node, params[0], params[1]), 7267 .TypeOf => return typeOf( gz, scope, rl, node, params), 7268 .union_init => return unionInit(gz, scope, rl, node, params), 7269 .c_import => return cImport( gz, scope, node, params[0]), 7270 // zig fmt: on 7271 7272 .@"export" => { 7273 const node_tags = tree.nodes.items(.tag); 7274 const node_datas = tree.nodes.items(.data); 7275 // This function causes a Decl to be exported. The first parameter is not an expression, 7276 // but an identifier of the Decl to be exported. 7277 var namespace: Zir.Inst.Ref = .none; 7278 var decl_name: u32 = 0; 7279 switch (node_tags[params[0]]) { 7280 .identifier => { 7281 const ident_token = main_tokens[params[0]]; 7282 decl_name = try astgen.identAsString(ident_token); 7283 7284 var s = scope; 7285 var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already 7286 while (true) switch (s.tag) { 7287 .local_val => { 7288 const local_val = s.cast(Scope.LocalVal).?; 7289 if (local_val.name == decl_name) { 7290 local_val.used = true; 7291 _ = try gz.addPlNode(.export_value, node, Zir.Inst.ExportValue{ 7292 .operand = local_val.inst, 7293 .options = try comptimeExpr(gz, scope, .{ .coerced_ty = .export_options_type }, params[1]), 7294 }); 7295 return rvalue(gz, rl, .void_value, node); 7296 } 7297 s = local_val.parent; 7298 }, 7299 .local_ptr => { 7300 const local_ptr = s.cast(Scope.LocalPtr).?; 7301 if (local_ptr.name == decl_name) { 7302 if (!local_ptr.maybe_comptime) 7303 return astgen.failNode(params[0], "unable to export runtime-known value", .{}); 7304 local_ptr.used = true; 7305 const loaded = try gz.addUnNode(.load, local_ptr.ptr, node); 7306 _ = try gz.addPlNode(.export_value, node, Zir.Inst.ExportValue{ 7307 .operand = loaded, 7308 .options = try comptimeExpr(gz, scope, .{ .coerced_ty = .export_options_type }, params[1]), 7309 }); 7310 return rvalue(gz, rl, .void_value, node); 7311 } 7312 s = local_ptr.parent; 7313 }, 7314 .gen_zir => s = s.cast(GenZir).?.parent, 7315 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, 7316 .namespace => { 7317 const ns = s.cast(Scope.Namespace).?; 7318 if (ns.decls.get(decl_name)) |i| { 7319 if (found_already) |f| { 7320 return astgen.failNodeNotes(node, "ambiguous reference", .{}, &.{ 7321 try astgen.errNoteNode(f, "declared here", .{}), 7322 try astgen.errNoteNode(i, "also declared here", .{}), 7323 }); 7324 } 7325 // We found a match but must continue looking for ambiguous references to decls. 7326 found_already = i; 7327 } 7328 s = ns.parent; 7329 }, 7330 .top => break, 7331 }; 7332 }, 7333 .field_access => { 7334 const namespace_node = node_datas[params[0]].lhs; 7335 namespace = try typeExpr(gz, scope, namespace_node); 7336 const dot_token = main_tokens[params[0]]; 7337 const field_ident = dot_token + 1; 7338 decl_name = try astgen.identAsString(field_ident); 7339 }, 7340 else => return astgen.failNode(params[0], "symbol to export must identify a declaration", .{}), 7341 } 7342 const options = try comptimeExpr(gz, scope, .{ .ty = .export_options_type }, params[1]); 7343 _ = try gz.addPlNode(.@"export", node, Zir.Inst.Export{ 7344 .namespace = namespace, 7345 .decl_name = decl_name, 7346 .options = options, 7347 }); 7348 return rvalue(gz, rl, .void_value, node); 7349 }, 7350 .@"extern" => { 7351 const type_inst = try typeExpr(gz, scope, params[0]); 7352 const options = try comptimeExpr(gz, scope, .{ .ty = .extern_options_type }, params[1]); 7353 const result = try gz.addExtendedPayload(.builtin_extern, Zir.Inst.BinNode{ 7354 .node = gz.nodeIndexToRelative(node), 7355 .lhs = type_inst, 7356 .rhs = options, 7357 }); 7358 return rvalue(gz, rl, result, node); 7359 }, 7360 .fence => { 7361 const order = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[0]); 7362 const result = try gz.addExtendedPayload(.fence, Zir.Inst.UnNode{ 7363 .node = gz.nodeIndexToRelative(node), 7364 .operand = order, 7365 }); 7366 return rvalue(gz, rl, result, node); 7367 }, 7368 .set_float_mode => { 7369 const order = try expr(gz, scope, .{ .coerced_ty = .float_mode_type }, params[0]); 7370 const result = try gz.addExtendedPayload(.set_float_mode, Zir.Inst.UnNode{ 7371 .node = gz.nodeIndexToRelative(node), 7372 .operand = order, 7373 }); 7374 return rvalue(gz, rl, result, node); 7375 }, 7376 .set_align_stack => { 7377 const order = try expr(gz, scope, align_rl, params[0]); 7378 const result = try gz.addExtendedPayload(.set_align_stack, Zir.Inst.UnNode{ 7379 .node = gz.nodeIndexToRelative(node), 7380 .operand = order, 7381 }); 7382 return rvalue(gz, rl, result, node); 7383 }, 7384 7385 .src => { 7386 const token_starts = tree.tokens.items(.start); 7387 const node_start = token_starts[tree.firstToken(node)]; 7388 astgen.advanceSourceCursor(node_start); 7389 const result = try gz.addExtendedPayload(.builtin_src, Zir.Inst.LineColumn{ 7390 .line = astgen.source_line, 7391 .column = astgen.source_column, 7392 }); 7393 return rvalue(gz, rl, result, node); 7394 }, 7395 7396 // zig fmt: off 7397 .This => return rvalue(gz, rl, try gz.addNodeExtended(.this, node), node), 7398 .return_address => return rvalue(gz, rl, try gz.addNodeExtended(.ret_addr, node), node), 7399 .error_return_trace => return rvalue(gz, rl, try gz.addNodeExtended(.error_return_trace, node), node), 7400 .frame => return rvalue(gz, rl, try gz.addNodeExtended(.frame, node), node), 7401 .frame_address => return rvalue(gz, rl, try gz.addNodeExtended(.frame_address, node), node), 7402 .breakpoint => return rvalue(gz, rl, try gz.addNodeExtended(.breakpoint, node), node), 7403 7404 .type_info => return simpleUnOpType(gz, scope, rl, node, params[0], .type_info), 7405 .size_of => return simpleUnOpType(gz, scope, rl, node, params[0], .size_of), 7406 .bit_size_of => return simpleUnOpType(gz, scope, rl, node, params[0], .bit_size_of), 7407 .align_of => return simpleUnOpType(gz, scope, rl, node, params[0], .align_of), 7408 7409 .ptr_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .ptr_to_int), 7410 .compile_error => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .compile_error), 7411 .set_eval_branch_quota => return simpleUnOp(gz, scope, rl, node, .{ .coerced_ty = .u32_type }, params[0], .set_eval_branch_quota), 7412 .enum_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .enum_to_int), 7413 .bool_to_int => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .bool_to_int), 7414 .embed_file => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .embed_file), 7415 .error_name => return simpleUnOp(gz, scope, rl, node, .{ .ty = .anyerror_type }, params[0], .error_name), 7416 .panic => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], if (gz.force_comptime) .panic_comptime else .panic), 7417 .set_cold => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .set_cold), 7418 .set_runtime_safety => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .set_runtime_safety), 7419 .sqrt => return simpleUnOp(gz, scope, rl, node, .none, params[0], .sqrt), 7420 .sin => return simpleUnOp(gz, scope, rl, node, .none, params[0], .sin), 7421 .cos => return simpleUnOp(gz, scope, rl, node, .none, params[0], .cos), 7422 .tan => return simpleUnOp(gz, scope, rl, node, .none, params[0], .tan), 7423 .exp => return simpleUnOp(gz, scope, rl, node, .none, params[0], .exp), 7424 .exp2 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .exp2), 7425 .log => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log), 7426 .log2 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log2), 7427 .log10 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log10), 7428 .fabs => return simpleUnOp(gz, scope, rl, node, .none, params[0], .fabs), 7429 .floor => return simpleUnOp(gz, scope, rl, node, .none, params[0], .floor), 7430 .ceil => return simpleUnOp(gz, scope, rl, node, .none, params[0], .ceil), 7431 .trunc => return simpleUnOp(gz, scope, rl, node, .none, params[0], .trunc), 7432 .round => return simpleUnOp(gz, scope, rl, node, .none, params[0], .round), 7433 .tag_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .tag_name), 7434 .Type => return simpleUnOp(gz, scope, rl, node, .{ .coerced_ty = .type_info_type }, params[0], .reify), 7435 .type_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .type_name), 7436 .Frame => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_type), 7437 .frame_size => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_size), 7438 7439 .float_to_int => return typeCast(gz, scope, rl, node, params[0], params[1], .float_to_int), 7440 .int_to_float => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_float), 7441 .int_to_ptr => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_ptr), 7442 .int_to_enum => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_enum), 7443 .float_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .float_cast), 7444 .int_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .int_cast), 7445 .ptr_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .ptr_cast), 7446 .truncate => return typeCast(gz, scope, rl, node, params[0], params[1], .truncate), 7447 // zig fmt: on 7448 7449 .error_to_int => { 7450 const operand = try expr(gz, scope, .none, params[0]); 7451 const result = try gz.addExtendedPayload(.error_to_int, Zir.Inst.UnNode{ 7452 .node = gz.nodeIndexToRelative(node), 7453 .operand = operand, 7454 }); 7455 return rvalue(gz, rl, result, node); 7456 }, 7457 .int_to_error => { 7458 const operand = try expr(gz, scope, .{ .coerced_ty = .u16_type }, params[0]); 7459 const result = try gz.addExtendedPayload(.int_to_error, Zir.Inst.UnNode{ 7460 .node = gz.nodeIndexToRelative(node), 7461 .operand = operand, 7462 }); 7463 return rvalue(gz, rl, result, node); 7464 }, 7465 .align_cast => { 7466 const dest_align = try comptimeExpr(gz, scope, align_rl, params[0]); 7467 const rhs = try expr(gz, scope, .none, params[1]); 7468 const result = try gz.addPlNode(.align_cast, node, Zir.Inst.Bin{ 7469 .lhs = dest_align, 7470 .rhs = rhs, 7471 }); 7472 return rvalue(gz, rl, result, node); 7473 }, 7474 .err_set_cast => { 7475 const result = try gz.addExtendedPayload(.err_set_cast, Zir.Inst.BinNode{ 7476 .lhs = try typeExpr(gz, scope, params[0]), 7477 .rhs = try expr(gz, scope, .none, params[1]), 7478 .node = gz.nodeIndexToRelative(node), 7479 }); 7480 return rvalue(gz, rl, result, node); 7481 }, 7482 7483 // zig fmt: off 7484 .has_decl => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_decl), 7485 .has_field => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_field), 7486 7487 .clz => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .clz), 7488 .ctz => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .ctz), 7489 .pop_count => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .pop_count), 7490 .byte_swap => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .byte_swap), 7491 .bit_reverse => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .bit_reverse), 7492 7493 .div_exact => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_exact), 7494 .div_floor => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_floor), 7495 .div_trunc => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_trunc), 7496 .mod => return divBuiltin(gz, scope, rl, node, params[0], params[1], .mod), 7497 .rem => return divBuiltin(gz, scope, rl, node, params[0], params[1], .rem), 7498 7499 .shl_exact => return shiftOp(gz, scope, rl, node, params[0], params[1], .shl_exact), 7500 .shr_exact => return shiftOp(gz, scope, rl, node, params[0], params[1], .shr_exact), 7501 7502 .bit_offset_of => return offsetOf(gz, scope, rl, node, params[0], params[1], .bit_offset_of), 7503 .offset_of => return offsetOf(gz, scope, rl, node, params[0], params[1], .offset_of), 7504 7505 .c_undef => return simpleCBuiltin(gz, scope, rl, node, params[0], .c_undef), 7506 .c_include => return simpleCBuiltin(gz, scope, rl, node, params[0], .c_include), 7507 7508 .cmpxchg_strong => return cmpxchg(gz, scope, rl, node, params, .cmpxchg_strong), 7509 .cmpxchg_weak => return cmpxchg(gz, scope, rl, node, params, .cmpxchg_weak), 7510 // zig fmt: on 7511 7512 .wasm_memory_size => { 7513 const operand = try comptimeExpr(gz, scope, .{ .coerced_ty = .u32_type }, params[0]); 7514 const result = try gz.addExtendedPayload(.wasm_memory_size, Zir.Inst.UnNode{ 7515 .node = gz.nodeIndexToRelative(node), 7516 .operand = operand, 7517 }); 7518 return rvalue(gz, rl, result, node); 7519 }, 7520 .wasm_memory_grow => { 7521 const index_arg = try comptimeExpr(gz, scope, .{ .coerced_ty = .u32_type }, params[0]); 7522 const delta_arg = try expr(gz, scope, .{ .coerced_ty = .u32_type }, params[1]); 7523 const result = try gz.addExtendedPayload(.wasm_memory_grow, Zir.Inst.BinNode{ 7524 .node = gz.nodeIndexToRelative(node), 7525 .lhs = index_arg, 7526 .rhs = delta_arg, 7527 }); 7528 return rvalue(gz, rl, result, node); 7529 }, 7530 .c_define => { 7531 if (!gz.c_import) return gz.astgen.failNode(node, "C define valid only inside C import block", .{}); 7532 const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[0]); 7533 const value = try comptimeExpr(gz, scope, .none, params[1]); 7534 const result = try gz.addExtendedPayload(.c_define, Zir.Inst.BinNode{ 7535 .node = gz.nodeIndexToRelative(node), 7536 .lhs = name, 7537 .rhs = value, 7538 }); 7539 return rvalue(gz, rl, result, node); 7540 }, 7541 7542 .splat => { 7543 const len = try expr(gz, scope, .{ .coerced_ty = .u32_type }, params[0]); 7544 const scalar = try expr(gz, scope, .none, params[1]); 7545 const result = try gz.addPlNode(.splat, node, Zir.Inst.Bin{ 7546 .lhs = len, 7547 .rhs = scalar, 7548 }); 7549 return rvalue(gz, rl, result, node); 7550 }, 7551 .reduce => { 7552 const op = try expr(gz, scope, .{ .ty = .reduce_op_type }, params[0]); 7553 const scalar = try expr(gz, scope, .none, params[1]); 7554 const result = try gz.addPlNode(.reduce, node, Zir.Inst.Bin{ 7555 .lhs = op, 7556 .rhs = scalar, 7557 }); 7558 return rvalue(gz, rl, result, node); 7559 }, 7560 7561 .maximum => { 7562 const a = try expr(gz, scope, .none, params[0]); 7563 const b = try expr(gz, scope, .none, params[1]); 7564 const result = try gz.addPlNode(.maximum, node, Zir.Inst.Bin{ 7565 .lhs = a, 7566 .rhs = b, 7567 }); 7568 return rvalue(gz, rl, result, node); 7569 }, 7570 .minimum => { 7571 const a = try expr(gz, scope, .none, params[0]); 7572 const b = try expr(gz, scope, .none, params[1]); 7573 const result = try gz.addPlNode(.minimum, node, Zir.Inst.Bin{ 7574 .lhs = a, 7575 .rhs = b, 7576 }); 7577 return rvalue(gz, rl, result, node); 7578 }, 7579 7580 .add_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .add_with_overflow), 7581 .sub_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .sub_with_overflow), 7582 .mul_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .mul_with_overflow), 7583 .shl_with_overflow => { 7584 const int_type = try typeExpr(gz, scope, params[0]); 7585 const log2_int_type = try gz.addUnNode(.log2_int_type, int_type, params[0]); 7586 const ptr_type = try gz.addUnNode(.overflow_arithmetic_ptr, int_type, params[0]); 7587 const lhs = try expr(gz, scope, .{ .ty = int_type }, params[1]); 7588 const rhs = try expr(gz, scope, .{ .ty = log2_int_type }, params[2]); 7589 const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[3]); 7590 const result = try gz.addExtendedPayload(.shl_with_overflow, Zir.Inst.OverflowArithmetic{ 7591 .node = gz.nodeIndexToRelative(node), 7592 .lhs = lhs, 7593 .rhs = rhs, 7594 .ptr = ptr, 7595 }); 7596 return rvalue(gz, rl, result, node); 7597 }, 7598 7599 .atomic_load => { 7600 const result = try gz.addPlNode(.atomic_load, node, Zir.Inst.AtomicLoad{ 7601 // zig fmt: off 7602 .elem_type = try typeExpr(gz, scope, params[0]), 7603 .ptr = try expr (gz, scope, .none, params[1]), 7604 .ordering = try expr (gz, scope, .{ .coerced_ty = .atomic_order_type }, params[2]), 7605 // zig fmt: on 7606 }); 7607 return rvalue(gz, rl, result, node); 7608 }, 7609 .atomic_rmw => { 7610 const int_type = try typeExpr(gz, scope, params[0]); 7611 const result = try gz.addPlNode(.atomic_rmw, node, Zir.Inst.AtomicRmw{ 7612 // zig fmt: off 7613 .ptr = try expr(gz, scope, .none, params[1]), 7614 .operation = try expr(gz, scope, .{ .coerced_ty = .atomic_rmw_op_type }, params[2]), 7615 .operand = try expr(gz, scope, .{ .ty = int_type }, params[3]), 7616 .ordering = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[4]), 7617 // zig fmt: on 7618 }); 7619 return rvalue(gz, rl, result, node); 7620 }, 7621 .atomic_store => { 7622 const int_type = try typeExpr(gz, scope, params[0]); 7623 const result = try gz.addPlNode(.atomic_store, node, Zir.Inst.AtomicStore{ 7624 // zig fmt: off 7625 .ptr = try expr(gz, scope, .none, params[1]), 7626 .operand = try expr(gz, scope, .{ .ty = int_type }, params[2]), 7627 .ordering = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[3]), 7628 // zig fmt: on 7629 }); 7630 return rvalue(gz, rl, result, node); 7631 }, 7632 .mul_add => { 7633 const float_type = try typeExpr(gz, scope, params[0]); 7634 const mulend1 = try expr(gz, scope, .{ .coerced_ty = float_type }, params[1]); 7635 const mulend2 = try expr(gz, scope, .{ .coerced_ty = float_type }, params[2]); 7636 const addend = try expr(gz, scope, .{ .ty = float_type }, params[3]); 7637 const result = try gz.addPlNode(.mul_add, node, Zir.Inst.MulAdd{ 7638 .mulend1 = mulend1, 7639 .mulend2 = mulend2, 7640 .addend = addend, 7641 }); 7642 return rvalue(gz, rl, result, node); 7643 }, 7644 .call => { 7645 const options = try comptimeExpr(gz, scope, .{ .ty = .call_options_type }, params[0]); 7646 const callee = try calleeExpr(gz, scope, params[1]); 7647 const args = try expr(gz, scope, .none, params[2]); 7648 const result = try gz.addPlNode(.builtin_call, node, Zir.Inst.BuiltinCall{ 7649 .options = options, 7650 .callee = callee, 7651 .args = args, 7652 .flags = .{ 7653 .is_nosuspend = gz.nosuspend_node != 0, 7654 .is_comptime = gz.force_comptime, 7655 .ensure_result_used = false, 7656 }, 7657 }); 7658 return rvalue(gz, rl, result, node); 7659 }, 7660 .field_parent_ptr => { 7661 const parent_type = try typeExpr(gz, scope, params[0]); 7662 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); 7663 const result = try gz.addPlNode(.field_parent_ptr, node, Zir.Inst.FieldParentPtr{ 7664 .parent_type = parent_type, 7665 .field_name = field_name, 7666 .field_ptr = try expr(gz, scope, .none, params[2]), 7667 }); 7668 return rvalue(gz, rl, result, node); 7669 }, 7670 .memcpy => { 7671 const result = try gz.addPlNode(.memcpy, node, Zir.Inst.Memcpy{ 7672 .dest = try expr(gz, scope, .{ .coerced_ty = .manyptr_u8_type }, params[0]), 7673 .source = try expr(gz, scope, .{ .coerced_ty = .manyptr_const_u8_type }, params[1]), 7674 .byte_count = try expr(gz, scope, .{ .coerced_ty = .usize_type }, params[2]), 7675 }); 7676 return rvalue(gz, rl, result, node); 7677 }, 7678 .memset => { 7679 const result = try gz.addPlNode(.memset, node, Zir.Inst.Memset{ 7680 .dest = try expr(gz, scope, .{ .coerced_ty = .manyptr_u8_type }, params[0]), 7681 .byte = try expr(gz, scope, .{ .coerced_ty = .u8_type }, params[1]), 7682 .byte_count = try expr(gz, scope, .{ .coerced_ty = .usize_type }, params[2]), 7683 }); 7684 return rvalue(gz, rl, result, node); 7685 }, 7686 .shuffle => { 7687 const result = try gz.addPlNode(.shuffle, node, Zir.Inst.Shuffle{ 7688 .elem_type = try typeExpr(gz, scope, params[0]), 7689 .a = try expr(gz, scope, .none, params[1]), 7690 .b = try expr(gz, scope, .none, params[2]), 7691 .mask = try comptimeExpr(gz, scope, .none, params[3]), 7692 }); 7693 return rvalue(gz, rl, result, node); 7694 }, 7695 .select => { 7696 const result = try gz.addExtendedPayload(.select, Zir.Inst.Select{ 7697 .node = gz.nodeIndexToRelative(node), 7698 .elem_type = try typeExpr(gz, scope, params[0]), 7699 .pred = try expr(gz, scope, .none, params[1]), 7700 .a = try expr(gz, scope, .none, params[2]), 7701 .b = try expr(gz, scope, .none, params[3]), 7702 }); 7703 return rvalue(gz, rl, result, node); 7704 }, 7705 .async_call => { 7706 const result = try gz.addPlNode(.builtin_async_call, node, Zir.Inst.AsyncCall{ 7707 .frame_buffer = try expr(gz, scope, .none, params[0]), 7708 .result_ptr = try expr(gz, scope, .none, params[1]), 7709 .fn_ptr = try expr(gz, scope, .none, params[2]), 7710 .args = try expr(gz, scope, .none, params[3]), 7711 }); 7712 return rvalue(gz, rl, result, node); 7713 }, 7714 .Vector => { 7715 const result = try gz.addPlNode(.vector_type, node, Zir.Inst.Bin{ 7716 .lhs = try comptimeExpr(gz, scope, .{ .coerced_ty = .u32_type }, params[0]), 7717 .rhs = try typeExpr(gz, scope, params[1]), 7718 }); 7719 return rvalue(gz, rl, result, node); 7720 }, 7721 .prefetch => { 7722 const ptr = try expr(gz, scope, .none, params[0]); 7723 const options = try comptimeExpr(gz, scope, .{ .ty = .prefetch_options_type }, params[1]); 7724 const result = try gz.addExtendedPayload(.prefetch, Zir.Inst.BinNode{ 7725 .node = gz.nodeIndexToRelative(node), 7726 .lhs = ptr, 7727 .rhs = options, 7728 }); 7729 return rvalue(gz, rl, result, node); 7730 }, 7731 } 7732 } 7733 7734 fn simpleNoOpVoid( 7735 gz: *GenZir, 7736 rl: ResultLoc, 7737 node: Ast.Node.Index, 7738 tag: Zir.Inst.Tag, 7739 ) InnerError!Zir.Inst.Ref { 7740 _ = try gz.addNode(tag, node); 7741 return rvalue(gz, rl, .void_value, node); 7742 } 7743 7744 fn hasDeclOrField( 7745 gz: *GenZir, 7746 scope: *Scope, 7747 rl: ResultLoc, 7748 node: Ast.Node.Index, 7749 lhs_node: Ast.Node.Index, 7750 rhs_node: Ast.Node.Index, 7751 tag: Zir.Inst.Tag, 7752 ) InnerError!Zir.Inst.Ref { 7753 const container_type = try typeExpr(gz, scope, lhs_node); 7754 const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, rhs_node); 7755 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 7756 .lhs = container_type, 7757 .rhs = name, 7758 }); 7759 return rvalue(gz, rl, result, node); 7760 } 7761 7762 fn typeCast( 7763 gz: *GenZir, 7764 scope: *Scope, 7765 rl: ResultLoc, 7766 node: Ast.Node.Index, 7767 lhs_node: Ast.Node.Index, 7768 rhs_node: Ast.Node.Index, 7769 tag: Zir.Inst.Tag, 7770 ) InnerError!Zir.Inst.Ref { 7771 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 7772 .lhs = try typeExpr(gz, scope, lhs_node), 7773 .rhs = try expr(gz, scope, .none, rhs_node), 7774 }); 7775 return rvalue(gz, rl, result, node); 7776 } 7777 7778 fn simpleUnOpType( 7779 gz: *GenZir, 7780 scope: *Scope, 7781 rl: ResultLoc, 7782 node: Ast.Node.Index, 7783 operand_node: Ast.Node.Index, 7784 tag: Zir.Inst.Tag, 7785 ) InnerError!Zir.Inst.Ref { 7786 const operand = try typeExpr(gz, scope, operand_node); 7787 const result = try gz.addUnNode(tag, operand, node); 7788 return rvalue(gz, rl, result, node); 7789 } 7790 7791 fn simpleUnOp( 7792 gz: *GenZir, 7793 scope: *Scope, 7794 rl: ResultLoc, 7795 node: Ast.Node.Index, 7796 operand_rl: ResultLoc, 7797 operand_node: Ast.Node.Index, 7798 tag: Zir.Inst.Tag, 7799 ) InnerError!Zir.Inst.Ref { 7800 const operand = try expr(gz, scope, operand_rl, operand_node); 7801 const result = try gz.addUnNode(tag, operand, node); 7802 return rvalue(gz, rl, result, node); 7803 } 7804 7805 fn negation( 7806 gz: *GenZir, 7807 scope: *Scope, 7808 rl: ResultLoc, 7809 node: Ast.Node.Index, 7810 ) InnerError!Zir.Inst.Ref { 7811 const astgen = gz.astgen; 7812 const tree = astgen.tree; 7813 const node_tags = tree.nodes.items(.tag); 7814 const node_datas = tree.nodes.items(.data); 7815 7816 // Check for float literal as the sub-expression because we want to preserve 7817 // its negativity rather than having it go through comptime subtraction. 7818 const operand_node = node_datas[node].lhs; 7819 if (node_tags[operand_node] == .float_literal) { 7820 return floatLiteral(gz, rl, operand_node, .negative); 7821 } 7822 7823 const operand = try expr(gz, scope, .none, operand_node); 7824 const result = try gz.addUnNode(.negate, operand, node); 7825 return rvalue(gz, rl, result, node); 7826 } 7827 7828 fn cmpxchg( 7829 gz: *GenZir, 7830 scope: *Scope, 7831 rl: ResultLoc, 7832 node: Ast.Node.Index, 7833 params: []const Ast.Node.Index, 7834 tag: Zir.Inst.Tag, 7835 ) InnerError!Zir.Inst.Ref { 7836 const int_type = try typeExpr(gz, scope, params[0]); 7837 const result = try gz.addPlNode(tag, node, Zir.Inst.Cmpxchg{ 7838 // zig fmt: off 7839 .ptr = try expr(gz, scope, .none, params[1]), 7840 .expected_value = try expr(gz, scope, .{ .ty = int_type }, params[2]), 7841 .new_value = try expr(gz, scope, .{ .coerced_ty = int_type }, params[3]), 7842 .success_order = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[4]), 7843 .failure_order = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[5]), 7844 // zig fmt: on 7845 }); 7846 return rvalue(gz, rl, result, node); 7847 } 7848 7849 fn bitBuiltin( 7850 gz: *GenZir, 7851 scope: *Scope, 7852 rl: ResultLoc, 7853 node: Ast.Node.Index, 7854 int_type_node: Ast.Node.Index, 7855 operand_node: Ast.Node.Index, 7856 tag: Zir.Inst.Tag, 7857 ) InnerError!Zir.Inst.Ref { 7858 // The accepted proposal https://github.com/ziglang/zig/issues/6835 7859 // tells us to remove the type parameter from these builtins. To stay 7860 // source-compatible with stage1, we still observe the parameter here, 7861 // but we do not encode it into the ZIR. To implement this proposal in 7862 // stage2, only AstGen code will need to be changed. 7863 _ = try typeExpr(gz, scope, int_type_node); 7864 7865 const operand = try expr(gz, scope, .none, operand_node); 7866 const result = try gz.addUnNode(tag, operand, node); 7867 return rvalue(gz, rl, result, node); 7868 } 7869 7870 fn divBuiltin( 7871 gz: *GenZir, 7872 scope: *Scope, 7873 rl: ResultLoc, 7874 node: Ast.Node.Index, 7875 lhs_node: Ast.Node.Index, 7876 rhs_node: Ast.Node.Index, 7877 tag: Zir.Inst.Tag, 7878 ) InnerError!Zir.Inst.Ref { 7879 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 7880 .lhs = try expr(gz, scope, .none, lhs_node), 7881 .rhs = try expr(gz, scope, .none, rhs_node), 7882 }); 7883 return rvalue(gz, rl, result, node); 7884 } 7885 7886 fn simpleCBuiltin( 7887 gz: *GenZir, 7888 scope: *Scope, 7889 rl: ResultLoc, 7890 node: Ast.Node.Index, 7891 operand_node: Ast.Node.Index, 7892 tag: Zir.Inst.Extended, 7893 ) InnerError!Zir.Inst.Ref { 7894 const name: []const u8 = if (tag == .c_undef) "C undef" else "C include"; 7895 if (!gz.c_import) return gz.astgen.failNode(node, "{s} valid only inside C import block", .{name}); 7896 const operand = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, operand_node); 7897 _ = try gz.addExtendedPayload(tag, Zir.Inst.UnNode{ 7898 .node = gz.nodeIndexToRelative(node), 7899 .operand = operand, 7900 }); 7901 return rvalue(gz, rl, .void_value, node); 7902 } 7903 7904 fn offsetOf( 7905 gz: *GenZir, 7906 scope: *Scope, 7907 rl: ResultLoc, 7908 node: Ast.Node.Index, 7909 lhs_node: Ast.Node.Index, 7910 rhs_node: Ast.Node.Index, 7911 tag: Zir.Inst.Tag, 7912 ) InnerError!Zir.Inst.Ref { 7913 const type_inst = try typeExpr(gz, scope, lhs_node); 7914 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, rhs_node); 7915 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 7916 .lhs = type_inst, 7917 .rhs = field_name, 7918 }); 7919 return rvalue(gz, rl, result, node); 7920 } 7921 7922 fn shiftOp( 7923 gz: *GenZir, 7924 scope: *Scope, 7925 rl: ResultLoc, 7926 node: Ast.Node.Index, 7927 lhs_node: Ast.Node.Index, 7928 rhs_node: Ast.Node.Index, 7929 tag: Zir.Inst.Tag, 7930 ) InnerError!Zir.Inst.Ref { 7931 const lhs = try expr(gz, scope, .none, lhs_node); 7932 const log2_int_type = try gz.addUnNode(.typeof_log2_int_type, lhs, lhs_node); 7933 const rhs = try expr(gz, scope, .{ .ty = log2_int_type }, rhs_node); 7934 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 7935 .lhs = lhs, 7936 .rhs = rhs, 7937 }); 7938 return rvalue(gz, rl, result, node); 7939 } 7940 7941 fn cImport( 7942 gz: *GenZir, 7943 scope: *Scope, 7944 node: Ast.Node.Index, 7945 body_node: Ast.Node.Index, 7946 ) InnerError!Zir.Inst.Ref { 7947 const astgen = gz.astgen; 7948 const gpa = astgen.gpa; 7949 7950 var block_scope = gz.makeSubBlock(scope); 7951 block_scope.force_comptime = true; 7952 block_scope.c_import = true; 7953 defer block_scope.unstack(); 7954 7955 const block_inst = try gz.makeBlockInst(.c_import, node); 7956 const block_result = try expr(&block_scope, &block_scope.base, .none, body_node); 7957 _ = try gz.addUnNode(.ensure_result_used, block_result, node); 7958 if (!gz.refIsNoReturn(block_result)) { 7959 _ = try block_scope.addBreak(.break_inline, block_inst, .void_value); 7960 } 7961 try block_scope.setBlockBody(block_inst); 7962 // block_scope unstacked now, can add new instructions to gz 7963 try gz.instructions.append(gpa, block_inst); 7964 7965 return indexToRef(block_inst); 7966 } 7967 7968 fn overflowArithmetic( 7969 gz: *GenZir, 7970 scope: *Scope, 7971 rl: ResultLoc, 7972 node: Ast.Node.Index, 7973 params: []const Ast.Node.Index, 7974 tag: Zir.Inst.Extended, 7975 ) InnerError!Zir.Inst.Ref { 7976 const int_type = try typeExpr(gz, scope, params[0]); 7977 const ptr_type = try gz.addUnNode(.overflow_arithmetic_ptr, int_type, params[0]); 7978 const lhs = try expr(gz, scope, .{ .ty = int_type }, params[1]); 7979 const rhs = try expr(gz, scope, .{ .ty = int_type }, params[2]); 7980 const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[3]); 7981 const result = try gz.addExtendedPayload(tag, Zir.Inst.OverflowArithmetic{ 7982 .node = gz.nodeIndexToRelative(node), 7983 .lhs = lhs, 7984 .rhs = rhs, 7985 .ptr = ptr, 7986 }); 7987 return rvalue(gz, rl, result, node); 7988 } 7989 7990 fn callExpr( 7991 gz: *GenZir, 7992 scope: *Scope, 7993 rl: ResultLoc, 7994 node: Ast.Node.Index, 7995 call: Ast.full.Call, 7996 ) InnerError!Zir.Inst.Ref { 7997 const astgen = gz.astgen; 7998 7999 const callee = try calleeExpr(gz, scope, call.ast.fn_expr); 8000 const modifier: std.builtin.CallOptions.Modifier = blk: { 8001 if (gz.force_comptime) { 8002 break :blk .compile_time; 8003 } 8004 if (call.async_token != null) { 8005 break :blk .async_kw; 8006 } 8007 if (gz.nosuspend_node != 0) { 8008 break :blk .no_async; 8009 } 8010 break :blk .auto; 8011 }; 8012 8013 { 8014 astgen.advanceSourceCursor(astgen.tree.tokens.items(.start)[call.ast.lparen]); 8015 const line = astgen.source_line - gz.decl_line; 8016 const column = astgen.source_column; 8017 8018 _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{ 8019 .dbg_stmt = .{ 8020 .line = line, 8021 .column = column, 8022 }, 8023 } }); 8024 } 8025 8026 assert(callee != .none); 8027 assert(node != 0); 8028 8029 const payload_index = try addExtra(astgen, Zir.Inst.Call{ 8030 .callee = callee, 8031 .flags = .{ 8032 .packed_modifier = @intCast(Zir.Inst.Call.Flags.PackedModifier, @enumToInt(modifier)), 8033 .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len), 8034 }, 8035 }); 8036 var extra_index = try reserveExtra(astgen, call.ast.params.len); 8037 8038 for (call.ast.params) |param_node, i| { 8039 const param_type = try gz.add(.{ 8040 .tag = .param_type, 8041 .data = .{ .param_type = .{ 8042 .callee = callee, 8043 .param_index = @intCast(u32, i), 8044 } }, 8045 }); 8046 const arg_ref = try expr(gz, scope, .{ .coerced_ty = param_type }, param_node); 8047 astgen.extra.items[extra_index] = @enumToInt(arg_ref); 8048 extra_index += 1; 8049 } 8050 8051 const call_inst = try gz.addPlNodePayloadIndex(.call, node, payload_index); 8052 return rvalue(gz, rl, call_inst, node); // TODO function call with result location 8053 } 8054 8055 /// calleeExpr generates the function part of a call expression (f in f(x)), or the 8056 /// callee argument to the @call() builtin. If the lhs is a field access or the 8057 /// @field() builtin, we need to generate a special field_call_bind instruction 8058 /// instead of the normal field_val or field_ptr. If this is a inst.func() call, 8059 /// this instruction will capture the value of the first argument before evaluating 8060 /// the other arguments. We need to use .ref here to guarantee we will be able to 8061 /// promote an lvalue to an address if the first parameter requires it. This 8062 /// unfortunately also means we need to take a reference to any types on the lhs. 8063 fn calleeExpr( 8064 gz: *GenZir, 8065 scope: *Scope, 8066 node: Ast.Node.Index, 8067 ) InnerError!Zir.Inst.Ref { 8068 const astgen = gz.astgen; 8069 const tree = astgen.tree; 8070 8071 const tag = tree.nodes.items(.tag)[node]; 8072 switch (tag) { 8073 .field_access => return addFieldAccess(.field_call_bind, gz, scope, .ref, node), 8074 8075 .builtin_call_two, 8076 .builtin_call_two_comma, 8077 .builtin_call, 8078 .builtin_call_comma, 8079 => { 8080 const node_datas = tree.nodes.items(.data); 8081 const main_tokens = tree.nodes.items(.main_token); 8082 const builtin_token = main_tokens[node]; 8083 const builtin_name = tree.tokenSlice(builtin_token); 8084 8085 var inline_params: [2]Ast.Node.Index = undefined; 8086 var params: []Ast.Node.Index = switch (tag) { 8087 .builtin_call, 8088 .builtin_call_comma, 8089 => tree.extra_data[node_datas[node].lhs..node_datas[node].rhs], 8090 8091 .builtin_call_two, 8092 .builtin_call_two_comma, 8093 => blk: { 8094 inline_params = .{ node_datas[node].lhs, node_datas[node].rhs }; 8095 const len: usize = if (inline_params[0] == 0) @as(usize, 0) else if (inline_params[1] == 0) @as(usize, 1) else @as(usize, 2); 8096 break :blk inline_params[0..len]; 8097 }, 8098 8099 else => unreachable, 8100 }; 8101 8102 // If anything is wrong, fall back to builtinCall. 8103 // It will emit any necessary compile errors and notes. 8104 if (std.mem.eql(u8, builtin_name, "@field") and params.len == 2) { 8105 const lhs = try expr(gz, scope, .ref, params[0]); 8106 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); 8107 return gz.addExtendedPayload(.field_call_bind_named, Zir.Inst.FieldNamedNode{ 8108 .node = gz.nodeIndexToRelative(node), 8109 .lhs = lhs, 8110 .field_name = field_name, 8111 }); 8112 } 8113 8114 return builtinCall(gz, scope, .none, node, params); 8115 }, 8116 else => return expr(gz, scope, .none, node), 8117 } 8118 } 8119 8120 const primitives = std.ComptimeStringMap(Zir.Inst.Ref, .{ 8121 .{ "anyerror", .anyerror_type }, 8122 .{ "anyframe", .anyframe_type }, 8123 .{ "anyopaque", .anyopaque_type }, 8124 .{ "bool", .bool_type }, 8125 .{ "c_int", .c_int_type }, 8126 .{ "c_long", .c_long_type }, 8127 .{ "c_longdouble", .c_longdouble_type }, 8128 .{ "c_longlong", .c_longlong_type }, 8129 .{ "c_short", .c_short_type }, 8130 .{ "c_uint", .c_uint_type }, 8131 .{ "c_ulong", .c_ulong_type }, 8132 .{ "c_ulonglong", .c_ulonglong_type }, 8133 .{ "c_ushort", .c_ushort_type }, 8134 .{ "comptime_float", .comptime_float_type }, 8135 .{ "comptime_int", .comptime_int_type }, 8136 .{ "f128", .f128_type }, 8137 .{ "f16", .f16_type }, 8138 .{ "f32", .f32_type }, 8139 .{ "f64", .f64_type }, 8140 .{ "f80", .f80_type }, 8141 .{ "false", .bool_false }, 8142 .{ "i16", .i16_type }, 8143 .{ "i32", .i32_type }, 8144 .{ "i64", .i64_type }, 8145 .{ "i128", .i128_type }, 8146 .{ "i8", .i8_type }, 8147 .{ "isize", .isize_type }, 8148 .{ "noreturn", .noreturn_type }, 8149 .{ "null", .null_value }, 8150 .{ "true", .bool_true }, 8151 .{ "type", .type_type }, 8152 .{ "u16", .u16_type }, 8153 .{ "u29", .u29_type }, 8154 .{ "u32", .u32_type }, 8155 .{ "u64", .u64_type }, 8156 .{ "u128", .u128_type }, 8157 .{ "u1", .u1_type }, 8158 .{ "u8", .u8_type }, 8159 .{ "undefined", .undef }, 8160 .{ "usize", .usize_type }, 8161 .{ "void", .void_type }, 8162 }); 8163 8164 fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index, have_res_ty: bool) bool { 8165 const node_tags = tree.nodes.items(.tag); 8166 const node_datas = tree.nodes.items(.data); 8167 const main_tokens = tree.nodes.items(.main_token); 8168 const token_tags = tree.tokens.items(.tag); 8169 8170 var node = start_node; 8171 while (true) { 8172 switch (node_tags[node]) { 8173 .root, 8174 .@"usingnamespace", 8175 .test_decl, 8176 .switch_case, 8177 .switch_case_one, 8178 .container_field_init, 8179 .container_field_align, 8180 .container_field, 8181 .asm_output, 8182 .asm_input, 8183 => unreachable, 8184 8185 .@"return", 8186 .@"break", 8187 .@"continue", 8188 .bit_not, 8189 .bool_not, 8190 .global_var_decl, 8191 .local_var_decl, 8192 .simple_var_decl, 8193 .aligned_var_decl, 8194 .@"defer", 8195 .@"errdefer", 8196 .address_of, 8197 .optional_type, 8198 .negation, 8199 .negation_wrap, 8200 .@"resume", 8201 .array_type, 8202 .array_type_sentinel, 8203 .ptr_type_aligned, 8204 .ptr_type_sentinel, 8205 .ptr_type, 8206 .ptr_type_bit_range, 8207 .@"suspend", 8208 .fn_proto_simple, 8209 .fn_proto_multi, 8210 .fn_proto_one, 8211 .fn_proto, 8212 .fn_decl, 8213 .anyframe_type, 8214 .anyframe_literal, 8215 .integer_literal, 8216 .float_literal, 8217 .enum_literal, 8218 .string_literal, 8219 .multiline_string_literal, 8220 .char_literal, 8221 .unreachable_literal, 8222 .identifier, 8223 .error_set_decl, 8224 .container_decl, 8225 .container_decl_trailing, 8226 .container_decl_two, 8227 .container_decl_two_trailing, 8228 .container_decl_arg, 8229 .container_decl_arg_trailing, 8230 .tagged_union, 8231 .tagged_union_trailing, 8232 .tagged_union_two, 8233 .tagged_union_two_trailing, 8234 .tagged_union_enum_tag, 8235 .tagged_union_enum_tag_trailing, 8236 .@"asm", 8237 .asm_simple, 8238 .add, 8239 .add_wrap, 8240 .add_sat, 8241 .array_cat, 8242 .array_mult, 8243 .assign, 8244 .assign_bit_and, 8245 .assign_bit_or, 8246 .assign_shl, 8247 .assign_shl_sat, 8248 .assign_shr, 8249 .assign_bit_xor, 8250 .assign_div, 8251 .assign_sub, 8252 .assign_sub_wrap, 8253 .assign_sub_sat, 8254 .assign_mod, 8255 .assign_add, 8256 .assign_add_wrap, 8257 .assign_add_sat, 8258 .assign_mul, 8259 .assign_mul_wrap, 8260 .assign_mul_sat, 8261 .bang_equal, 8262 .bit_and, 8263 .bit_or, 8264 .shl, 8265 .shl_sat, 8266 .shr, 8267 .bit_xor, 8268 .bool_and, 8269 .bool_or, 8270 .div, 8271 .equal_equal, 8272 .error_union, 8273 .greater_or_equal, 8274 .greater_than, 8275 .less_or_equal, 8276 .less_than, 8277 .merge_error_sets, 8278 .mod, 8279 .mul, 8280 .mul_wrap, 8281 .mul_sat, 8282 .switch_range, 8283 .field_access, 8284 .sub, 8285 .sub_wrap, 8286 .sub_sat, 8287 .slice, 8288 .slice_open, 8289 .slice_sentinel, 8290 .deref, 8291 .array_access, 8292 .error_value, 8293 .while_simple, // This variant cannot have an else expression. 8294 .while_cont, // This variant cannot have an else expression. 8295 .for_simple, // This variant cannot have an else expression. 8296 .if_simple, // This variant cannot have an else expression. 8297 => return false, 8298 8299 // Forward the question to the LHS sub-expression. 8300 .grouped_expression, 8301 .@"try", 8302 .@"await", 8303 .@"comptime", 8304 .@"nosuspend", 8305 .unwrap_optional, 8306 => node = node_datas[node].lhs, 8307 8308 // Forward the question to the RHS sub-expression. 8309 .@"catch", 8310 .@"orelse", 8311 => node = node_datas[node].rhs, 8312 8313 // Array and struct init exprs write to result locs, but anon literals do not. 8314 .array_init_one, 8315 .array_init_one_comma, 8316 .struct_init_one, 8317 .struct_init_one_comma, 8318 .array_init, 8319 .array_init_comma, 8320 .struct_init, 8321 .struct_init_comma, 8322 => return have_res_ty or node_datas[node].lhs != 0, 8323 8324 // Anon literals do not need result location. 8325 .array_init_dot_two, 8326 .array_init_dot_two_comma, 8327 .array_init_dot, 8328 .array_init_dot_comma, 8329 .struct_init_dot_two, 8330 .struct_init_dot_two_comma, 8331 .struct_init_dot, 8332 .struct_init_dot_comma, 8333 => return have_res_ty, 8334 8335 // True because depending on comptime conditions, sub-expressions 8336 // may be the kind that need memory locations. 8337 .@"while", // This variant always has an else expression. 8338 .@"if", // This variant always has an else expression. 8339 .@"for", // This variant always has an else expression. 8340 .@"switch", 8341 .switch_comma, 8342 .call_one, 8343 .call_one_comma, 8344 .async_call_one, 8345 .async_call_one_comma, 8346 .call, 8347 .call_comma, 8348 .async_call, 8349 .async_call_comma, 8350 => return true, 8351 8352 .block_two, 8353 .block_two_semicolon, 8354 .block, 8355 .block_semicolon, 8356 => { 8357 const lbrace = main_tokens[node]; 8358 if (token_tags[lbrace - 1] == .colon) { 8359 // Labeled blocks may need a memory location to forward 8360 // to their break statements. 8361 return true; 8362 } else { 8363 return false; 8364 } 8365 }, 8366 8367 .builtin_call_two, .builtin_call_two_comma => { 8368 const builtin_token = main_tokens[node]; 8369 const builtin_name = tree.tokenSlice(builtin_token); 8370 // If the builtin is an invalid name, we don't cause an error here; instead 8371 // let it pass, and the error will be "invalid builtin function" later. 8372 const builtin_info = BuiltinFn.list.get(builtin_name) orelse return false; 8373 switch (builtin_info.needs_mem_loc) { 8374 .never => return false, 8375 .always => return true, 8376 .forward1 => node = node_datas[node].rhs, 8377 } 8378 }, 8379 8380 .builtin_call, .builtin_call_comma => { 8381 const params = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs]; 8382 const builtin_token = main_tokens[node]; 8383 const builtin_name = tree.tokenSlice(builtin_token); 8384 // If the builtin is an invalid name, we don't cause an error here; instead 8385 // let it pass, and the error will be "invalid builtin function" later. 8386 const builtin_info = BuiltinFn.list.get(builtin_name) orelse return false; 8387 switch (builtin_info.needs_mem_loc) { 8388 .never => return false, 8389 .always => return true, 8390 .forward1 => node = params[1], 8391 } 8392 }, 8393 } 8394 } 8395 } 8396 8397 fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.EvalToError { 8398 const node_tags = tree.nodes.items(.tag); 8399 const node_datas = tree.nodes.items(.data); 8400 const main_tokens = tree.nodes.items(.main_token); 8401 const token_tags = tree.tokens.items(.tag); 8402 8403 var node = start_node; 8404 while (true) { 8405 switch (node_tags[node]) { 8406 .root, 8407 .@"usingnamespace", 8408 .test_decl, 8409 .switch_case, 8410 .switch_case_one, 8411 .container_field_init, 8412 .container_field_align, 8413 .container_field, 8414 .asm_output, 8415 .asm_input, 8416 => unreachable, 8417 8418 .error_value => return .always, 8419 8420 .@"asm", 8421 .asm_simple, 8422 .identifier, 8423 .field_access, 8424 .deref, 8425 .array_access, 8426 .while_simple, 8427 .while_cont, 8428 .for_simple, 8429 .if_simple, 8430 .@"while", 8431 .@"if", 8432 .@"for", 8433 .@"switch", 8434 .switch_comma, 8435 .call_one, 8436 .call_one_comma, 8437 .async_call_one, 8438 .async_call_one_comma, 8439 .call, 8440 .call_comma, 8441 .async_call, 8442 .async_call_comma, 8443 => return .maybe, 8444 8445 .@"return", 8446 .@"break", 8447 .@"continue", 8448 .bit_not, 8449 .bool_not, 8450 .global_var_decl, 8451 .local_var_decl, 8452 .simple_var_decl, 8453 .aligned_var_decl, 8454 .@"defer", 8455 .@"errdefer", 8456 .address_of, 8457 .optional_type, 8458 .negation, 8459 .negation_wrap, 8460 .@"resume", 8461 .array_type, 8462 .array_type_sentinel, 8463 .ptr_type_aligned, 8464 .ptr_type_sentinel, 8465 .ptr_type, 8466 .ptr_type_bit_range, 8467 .@"suspend", 8468 .fn_proto_simple, 8469 .fn_proto_multi, 8470 .fn_proto_one, 8471 .fn_proto, 8472 .fn_decl, 8473 .anyframe_type, 8474 .anyframe_literal, 8475 .integer_literal, 8476 .float_literal, 8477 .enum_literal, 8478 .string_literal, 8479 .multiline_string_literal, 8480 .char_literal, 8481 .unreachable_literal, 8482 .error_set_decl, 8483 .container_decl, 8484 .container_decl_trailing, 8485 .container_decl_two, 8486 .container_decl_two_trailing, 8487 .container_decl_arg, 8488 .container_decl_arg_trailing, 8489 .tagged_union, 8490 .tagged_union_trailing, 8491 .tagged_union_two, 8492 .tagged_union_two_trailing, 8493 .tagged_union_enum_tag, 8494 .tagged_union_enum_tag_trailing, 8495 .add, 8496 .add_wrap, 8497 .add_sat, 8498 .array_cat, 8499 .array_mult, 8500 .assign, 8501 .assign_bit_and, 8502 .assign_bit_or, 8503 .assign_shl, 8504 .assign_shl_sat, 8505 .assign_shr, 8506 .assign_bit_xor, 8507 .assign_div, 8508 .assign_sub, 8509 .assign_sub_wrap, 8510 .assign_sub_sat, 8511 .assign_mod, 8512 .assign_add, 8513 .assign_add_wrap, 8514 .assign_add_sat, 8515 .assign_mul, 8516 .assign_mul_wrap, 8517 .assign_mul_sat, 8518 .bang_equal, 8519 .bit_and, 8520 .bit_or, 8521 .shl, 8522 .shl_sat, 8523 .shr, 8524 .bit_xor, 8525 .bool_and, 8526 .bool_or, 8527 .div, 8528 .equal_equal, 8529 .error_union, 8530 .greater_or_equal, 8531 .greater_than, 8532 .less_or_equal, 8533 .less_than, 8534 .merge_error_sets, 8535 .mod, 8536 .mul, 8537 .mul_wrap, 8538 .mul_sat, 8539 .switch_range, 8540 .sub, 8541 .sub_wrap, 8542 .sub_sat, 8543 .slice, 8544 .slice_open, 8545 .slice_sentinel, 8546 .array_init_one, 8547 .array_init_one_comma, 8548 .array_init_dot_two, 8549 .array_init_dot_two_comma, 8550 .array_init_dot, 8551 .array_init_dot_comma, 8552 .array_init, 8553 .array_init_comma, 8554 .struct_init_one, 8555 .struct_init_one_comma, 8556 .struct_init_dot_two, 8557 .struct_init_dot_two_comma, 8558 .struct_init_dot, 8559 .struct_init_dot_comma, 8560 .struct_init, 8561 .struct_init_comma, 8562 => return .never, 8563 8564 // Forward the question to the LHS sub-expression. 8565 .grouped_expression, 8566 .@"try", 8567 .@"await", 8568 .@"comptime", 8569 .@"nosuspend", 8570 .unwrap_optional, 8571 => node = node_datas[node].lhs, 8572 8573 // LHS sub-expression may still be an error under the outer optional or error union 8574 .@"catch", 8575 .@"orelse", 8576 => return .maybe, 8577 8578 .block_two, 8579 .block_two_semicolon, 8580 .block, 8581 .block_semicolon, 8582 => { 8583 const lbrace = main_tokens[node]; 8584 if (token_tags[lbrace - 1] == .colon) { 8585 // Labeled blocks may need a memory location to forward 8586 // to their break statements. 8587 return .maybe; 8588 } else { 8589 return .never; 8590 } 8591 }, 8592 8593 .builtin_call, 8594 .builtin_call_comma, 8595 .builtin_call_two, 8596 .builtin_call_two_comma, 8597 => { 8598 const builtin_token = main_tokens[node]; 8599 const builtin_name = tree.tokenSlice(builtin_token); 8600 // If the builtin is an invalid name, we don't cause an error here; instead 8601 // let it pass, and the error will be "invalid builtin function" later. 8602 const builtin_info = BuiltinFn.list.get(builtin_name) orelse return .maybe; 8603 return builtin_info.eval_to_error; 8604 }, 8605 } 8606 } 8607 } 8608 8609 /// Returns `true` if it is known the type expression has more than one possible value; 8610 /// `false` otherwise. 8611 fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.Index) bool { 8612 const node_tags = tree.nodes.items(.tag); 8613 const node_datas = tree.nodes.items(.data); 8614 8615 var node = start_node; 8616 while (true) { 8617 switch (node_tags[node]) { 8618 .root, 8619 .@"usingnamespace", 8620 .test_decl, 8621 .switch_case, 8622 .switch_case_one, 8623 .container_field_init, 8624 .container_field_align, 8625 .container_field, 8626 .asm_output, 8627 .asm_input, 8628 .global_var_decl, 8629 .local_var_decl, 8630 .simple_var_decl, 8631 .aligned_var_decl, 8632 => unreachable, 8633 8634 .@"return", 8635 .@"break", 8636 .@"continue", 8637 .bit_not, 8638 .bool_not, 8639 .@"defer", 8640 .@"errdefer", 8641 .address_of, 8642 .negation, 8643 .negation_wrap, 8644 .@"resume", 8645 .array_type, 8646 .@"suspend", 8647 .fn_decl, 8648 .anyframe_literal, 8649 .integer_literal, 8650 .float_literal, 8651 .enum_literal, 8652 .string_literal, 8653 .multiline_string_literal, 8654 .char_literal, 8655 .unreachable_literal, 8656 .error_set_decl, 8657 .container_decl, 8658 .container_decl_trailing, 8659 .container_decl_two, 8660 .container_decl_two_trailing, 8661 .container_decl_arg, 8662 .container_decl_arg_trailing, 8663 .tagged_union, 8664 .tagged_union_trailing, 8665 .tagged_union_two, 8666 .tagged_union_two_trailing, 8667 .tagged_union_enum_tag, 8668 .tagged_union_enum_tag_trailing, 8669 .@"asm", 8670 .asm_simple, 8671 .add, 8672 .add_wrap, 8673 .add_sat, 8674 .array_cat, 8675 .array_mult, 8676 .assign, 8677 .assign_bit_and, 8678 .assign_bit_or, 8679 .assign_shl, 8680 .assign_shl_sat, 8681 .assign_shr, 8682 .assign_bit_xor, 8683 .assign_div, 8684 .assign_sub, 8685 .assign_sub_wrap, 8686 .assign_sub_sat, 8687 .assign_mod, 8688 .assign_add, 8689 .assign_add_wrap, 8690 .assign_add_sat, 8691 .assign_mul, 8692 .assign_mul_wrap, 8693 .assign_mul_sat, 8694 .bang_equal, 8695 .bit_and, 8696 .bit_or, 8697 .shl, 8698 .shl_sat, 8699 .shr, 8700 .bit_xor, 8701 .bool_and, 8702 .bool_or, 8703 .div, 8704 .equal_equal, 8705 .error_union, 8706 .greater_or_equal, 8707 .greater_than, 8708 .less_or_equal, 8709 .less_than, 8710 .merge_error_sets, 8711 .mod, 8712 .mul, 8713 .mul_wrap, 8714 .mul_sat, 8715 .switch_range, 8716 .field_access, 8717 .sub, 8718 .sub_wrap, 8719 .sub_sat, 8720 .slice, 8721 .slice_open, 8722 .slice_sentinel, 8723 .deref, 8724 .array_access, 8725 .error_value, 8726 .while_simple, 8727 .while_cont, 8728 .for_simple, 8729 .if_simple, 8730 .@"catch", 8731 .@"orelse", 8732 .array_init_one, 8733 .array_init_one_comma, 8734 .array_init_dot_two, 8735 .array_init_dot_two_comma, 8736 .array_init_dot, 8737 .array_init_dot_comma, 8738 .array_init, 8739 .array_init_comma, 8740 .struct_init_one, 8741 .struct_init_one_comma, 8742 .struct_init_dot_two, 8743 .struct_init_dot_two_comma, 8744 .struct_init_dot, 8745 .struct_init_dot_comma, 8746 .struct_init, 8747 .struct_init_comma, 8748 .@"while", 8749 .@"if", 8750 .@"for", 8751 .@"switch", 8752 .switch_comma, 8753 .call_one, 8754 .call_one_comma, 8755 .async_call_one, 8756 .async_call_one_comma, 8757 .call, 8758 .call_comma, 8759 .async_call, 8760 .async_call_comma, 8761 .block_two, 8762 .block_two_semicolon, 8763 .block, 8764 .block_semicolon, 8765 .builtin_call, 8766 .builtin_call_comma, 8767 .builtin_call_two, 8768 .builtin_call_two_comma, 8769 // these are function bodies, not pointers 8770 .fn_proto_simple, 8771 .fn_proto_multi, 8772 .fn_proto_one, 8773 .fn_proto, 8774 => return false, 8775 8776 // Forward the question to the LHS sub-expression. 8777 .grouped_expression, 8778 .@"try", 8779 .@"await", 8780 .@"comptime", 8781 .@"nosuspend", 8782 .unwrap_optional, 8783 => node = node_datas[node].lhs, 8784 8785 .ptr_type_aligned, 8786 .ptr_type_sentinel, 8787 .ptr_type, 8788 .ptr_type_bit_range, 8789 .optional_type, 8790 .anyframe_type, 8791 .array_type_sentinel, 8792 => return true, 8793 8794 .identifier => { 8795 const main_tokens = tree.nodes.items(.main_token); 8796 const ident_bytes = tree.tokenSlice(main_tokens[node]); 8797 if (primitives.get(ident_bytes)) |primitive| switch (primitive) { 8798 .anyerror_type, 8799 .anyframe_type, 8800 .anyopaque_type, 8801 .bool_type, 8802 .c_int_type, 8803 .c_long_type, 8804 .c_longdouble_type, 8805 .c_longlong_type, 8806 .c_short_type, 8807 .c_uint_type, 8808 .c_ulong_type, 8809 .c_ulonglong_type, 8810 .c_ushort_type, 8811 .comptime_float_type, 8812 .comptime_int_type, 8813 .f16_type, 8814 .f32_type, 8815 .f64_type, 8816 .f80_type, 8817 .f128_type, 8818 .i16_type, 8819 .i32_type, 8820 .i64_type, 8821 .i128_type, 8822 .i8_type, 8823 .isize_type, 8824 .type_type, 8825 .u16_type, 8826 .u29_type, 8827 .u32_type, 8828 .u64_type, 8829 .u128_type, 8830 .u1_type, 8831 .u8_type, 8832 .usize_type, 8833 => return true, 8834 8835 .void_type, 8836 .bool_false, 8837 .bool_true, 8838 .null_value, 8839 .undef, 8840 .noreturn_type, 8841 => return false, 8842 8843 else => unreachable, // that's all the values from `primitives`. 8844 } else { 8845 return false; 8846 } 8847 }, 8848 } 8849 } 8850 } 8851 8852 /// Returns `true` if it is known the expression is a type that cannot be used at runtime; 8853 /// `false` otherwise. 8854 fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool { 8855 const node_tags = tree.nodes.items(.tag); 8856 const node_datas = tree.nodes.items(.data); 8857 8858 var node = start_node; 8859 while (true) { 8860 switch (node_tags[node]) { 8861 .root, 8862 .@"usingnamespace", 8863 .test_decl, 8864 .switch_case, 8865 .switch_case_one, 8866 .container_field_init, 8867 .container_field_align, 8868 .container_field, 8869 .asm_output, 8870 .asm_input, 8871 .global_var_decl, 8872 .local_var_decl, 8873 .simple_var_decl, 8874 .aligned_var_decl, 8875 => unreachable, 8876 8877 .@"return", 8878 .@"break", 8879 .@"continue", 8880 .bit_not, 8881 .bool_not, 8882 .@"defer", 8883 .@"errdefer", 8884 .address_of, 8885 .negation, 8886 .negation_wrap, 8887 .@"resume", 8888 .array_type, 8889 .@"suspend", 8890 .fn_decl, 8891 .anyframe_literal, 8892 .integer_literal, 8893 .float_literal, 8894 .enum_literal, 8895 .string_literal, 8896 .multiline_string_literal, 8897 .char_literal, 8898 .unreachable_literal, 8899 .error_set_decl, 8900 .container_decl, 8901 .container_decl_trailing, 8902 .container_decl_two, 8903 .container_decl_two_trailing, 8904 .container_decl_arg, 8905 .container_decl_arg_trailing, 8906 .tagged_union, 8907 .tagged_union_trailing, 8908 .tagged_union_two, 8909 .tagged_union_two_trailing, 8910 .tagged_union_enum_tag, 8911 .tagged_union_enum_tag_trailing, 8912 .@"asm", 8913 .asm_simple, 8914 .add, 8915 .add_wrap, 8916 .add_sat, 8917 .array_cat, 8918 .array_mult, 8919 .assign, 8920 .assign_bit_and, 8921 .assign_bit_or, 8922 .assign_shl, 8923 .assign_shl_sat, 8924 .assign_shr, 8925 .assign_bit_xor, 8926 .assign_div, 8927 .assign_sub, 8928 .assign_sub_wrap, 8929 .assign_sub_sat, 8930 .assign_mod, 8931 .assign_add, 8932 .assign_add_wrap, 8933 .assign_add_sat, 8934 .assign_mul, 8935 .assign_mul_wrap, 8936 .assign_mul_sat, 8937 .bang_equal, 8938 .bit_and, 8939 .bit_or, 8940 .shl, 8941 .shl_sat, 8942 .shr, 8943 .bit_xor, 8944 .bool_and, 8945 .bool_or, 8946 .div, 8947 .equal_equal, 8948 .error_union, 8949 .greater_or_equal, 8950 .greater_than, 8951 .less_or_equal, 8952 .less_than, 8953 .merge_error_sets, 8954 .mod, 8955 .mul, 8956 .mul_wrap, 8957 .mul_sat, 8958 .switch_range, 8959 .field_access, 8960 .sub, 8961 .sub_wrap, 8962 .sub_sat, 8963 .slice, 8964 .slice_open, 8965 .slice_sentinel, 8966 .deref, 8967 .array_access, 8968 .error_value, 8969 .while_simple, 8970 .while_cont, 8971 .for_simple, 8972 .if_simple, 8973 .@"catch", 8974 .@"orelse", 8975 .array_init_one, 8976 .array_init_one_comma, 8977 .array_init_dot_two, 8978 .array_init_dot_two_comma, 8979 .array_init_dot, 8980 .array_init_dot_comma, 8981 .array_init, 8982 .array_init_comma, 8983 .struct_init_one, 8984 .struct_init_one_comma, 8985 .struct_init_dot_two, 8986 .struct_init_dot_two_comma, 8987 .struct_init_dot, 8988 .struct_init_dot_comma, 8989 .struct_init, 8990 .struct_init_comma, 8991 .@"while", 8992 .@"if", 8993 .@"for", 8994 .@"switch", 8995 .switch_comma, 8996 .call_one, 8997 .call_one_comma, 8998 .async_call_one, 8999 .async_call_one_comma, 9000 .call, 9001 .call_comma, 9002 .async_call, 9003 .async_call_comma, 9004 .block_two, 9005 .block_two_semicolon, 9006 .block, 9007 .block_semicolon, 9008 .builtin_call, 9009 .builtin_call_comma, 9010 .builtin_call_two, 9011 .builtin_call_two_comma, 9012 .ptr_type_aligned, 9013 .ptr_type_sentinel, 9014 .ptr_type, 9015 .ptr_type_bit_range, 9016 .optional_type, 9017 .anyframe_type, 9018 .array_type_sentinel, 9019 => return false, 9020 9021 // these are function bodies, not pointers 9022 .fn_proto_simple, 9023 .fn_proto_multi, 9024 .fn_proto_one, 9025 .fn_proto, 9026 => return true, 9027 9028 // Forward the question to the LHS sub-expression. 9029 .grouped_expression, 9030 .@"try", 9031 .@"await", 9032 .@"comptime", 9033 .@"nosuspend", 9034 .unwrap_optional, 9035 => node = node_datas[node].lhs, 9036 9037 .identifier => { 9038 const main_tokens = tree.nodes.items(.main_token); 9039 const ident_bytes = tree.tokenSlice(main_tokens[node]); 9040 if (primitives.get(ident_bytes)) |primitive| switch (primitive) { 9041 .anyerror_type, 9042 .anyframe_type, 9043 .anyopaque_type, 9044 .bool_type, 9045 .c_int_type, 9046 .c_long_type, 9047 .c_longdouble_type, 9048 .c_longlong_type, 9049 .c_short_type, 9050 .c_uint_type, 9051 .c_ulong_type, 9052 .c_ulonglong_type, 9053 .c_ushort_type, 9054 .f16_type, 9055 .f32_type, 9056 .f64_type, 9057 .f80_type, 9058 .f128_type, 9059 .i16_type, 9060 .i32_type, 9061 .i64_type, 9062 .i128_type, 9063 .i8_type, 9064 .isize_type, 9065 .u16_type, 9066 .u29_type, 9067 .u32_type, 9068 .u64_type, 9069 .u128_type, 9070 .u1_type, 9071 .u8_type, 9072 .usize_type, 9073 .void_type, 9074 .bool_false, 9075 .bool_true, 9076 .null_value, 9077 .undef, 9078 .noreturn_type, 9079 => return false, 9080 9081 .comptime_float_type, 9082 .comptime_int_type, 9083 .type_type, 9084 => return true, 9085 9086 else => unreachable, // that's all the values from `primitives`. 9087 } else { 9088 return false; 9089 } 9090 }, 9091 } 9092 } 9093 } 9094 9095 /// Applies `rl` semantics to `result`. Expressions which do not do their own handling of 9096 /// result locations must call this function on their result. 9097 /// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer. 9098 /// If the `ResultLoc` is `ty`, it will coerce the result to the type. 9099 /// Assumes nothing stacked on `gz`. 9100 fn rvalue( 9101 gz: *GenZir, 9102 rl: ResultLoc, 9103 raw_result: Zir.Inst.Ref, 9104 src_node: Ast.Node.Index, 9105 ) InnerError!Zir.Inst.Ref { 9106 const result = r: { 9107 if (refToIndex(raw_result)) |result_index| { 9108 const zir_tags = gz.astgen.instructions.items(.tag); 9109 const data = gz.astgen.instructions.items(.data)[result_index]; 9110 if (zir_tags[result_index].isAlwaysVoid(data)) { 9111 break :r Zir.Inst.Ref.void_value; 9112 } 9113 } 9114 break :r raw_result; 9115 }; 9116 if (gz.endsWithNoReturn()) return result; 9117 switch (rl) { 9118 .none, .coerced_ty => return result, 9119 .discard => { 9120 // Emit a compile error for discarding error values. 9121 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node); 9122 return result; 9123 }, 9124 .ref => { 9125 // We need a pointer but we have a value. 9126 // Unfortunately it's not quite as simple as directly emitting a ref 9127 // instruction here because we need subsequent address-of operator on 9128 // const locals to return the same address. 9129 const astgen = gz.astgen; 9130 const tree = astgen.tree; 9131 const src_token = tree.firstToken(src_node); 9132 const result_index = refToIndex(result) orelse 9133 return gz.addUnTok(.ref, result, src_token); 9134 const zir_tags = gz.astgen.instructions.items(.tag); 9135 if (zir_tags[result_index].isParam()) 9136 return gz.addUnTok(.ref, result, src_token); 9137 const gop = try astgen.ref_table.getOrPut(astgen.gpa, result_index); 9138 if (!gop.found_existing) { 9139 gop.value_ptr.* = try gz.makeUnTok(.ref, result, src_token); 9140 } 9141 return indexToRef(gop.value_ptr.*); 9142 }, 9143 .ty => |ty_inst| { 9144 // Quickly eliminate some common, unnecessary type coercion. 9145 const as_ty = @as(u64, @enumToInt(Zir.Inst.Ref.type_type)) << 32; 9146 const as_comptime_int = @as(u64, @enumToInt(Zir.Inst.Ref.comptime_int_type)) << 32; 9147 const as_bool = @as(u64, @enumToInt(Zir.Inst.Ref.bool_type)) << 32; 9148 const as_usize = @as(u64, @enumToInt(Zir.Inst.Ref.usize_type)) << 32; 9149 const as_void = @as(u64, @enumToInt(Zir.Inst.Ref.void_type)) << 32; 9150 switch ((@as(u64, @enumToInt(ty_inst)) << 32) | @as(u64, @enumToInt(result))) { 9151 as_ty | @enumToInt(Zir.Inst.Ref.u1_type), 9152 as_ty | @enumToInt(Zir.Inst.Ref.u8_type), 9153 as_ty | @enumToInt(Zir.Inst.Ref.i8_type), 9154 as_ty | @enumToInt(Zir.Inst.Ref.u16_type), 9155 as_ty | @enumToInt(Zir.Inst.Ref.u29_type), 9156 as_ty | @enumToInt(Zir.Inst.Ref.i16_type), 9157 as_ty | @enumToInt(Zir.Inst.Ref.u32_type), 9158 as_ty | @enumToInt(Zir.Inst.Ref.i32_type), 9159 as_ty | @enumToInt(Zir.Inst.Ref.u64_type), 9160 as_ty | @enumToInt(Zir.Inst.Ref.i64_type), 9161 as_ty | @enumToInt(Zir.Inst.Ref.usize_type), 9162 as_ty | @enumToInt(Zir.Inst.Ref.isize_type), 9163 as_ty | @enumToInt(Zir.Inst.Ref.c_short_type), 9164 as_ty | @enumToInt(Zir.Inst.Ref.c_ushort_type), 9165 as_ty | @enumToInt(Zir.Inst.Ref.c_int_type), 9166 as_ty | @enumToInt(Zir.Inst.Ref.c_uint_type), 9167 as_ty | @enumToInt(Zir.Inst.Ref.c_long_type), 9168 as_ty | @enumToInt(Zir.Inst.Ref.c_ulong_type), 9169 as_ty | @enumToInt(Zir.Inst.Ref.c_longlong_type), 9170 as_ty | @enumToInt(Zir.Inst.Ref.c_ulonglong_type), 9171 as_ty | @enumToInt(Zir.Inst.Ref.c_longdouble_type), 9172 as_ty | @enumToInt(Zir.Inst.Ref.f16_type), 9173 as_ty | @enumToInt(Zir.Inst.Ref.f32_type), 9174 as_ty | @enumToInt(Zir.Inst.Ref.f64_type), 9175 as_ty | @enumToInt(Zir.Inst.Ref.f80_type), 9176 as_ty | @enumToInt(Zir.Inst.Ref.f128_type), 9177 as_ty | @enumToInt(Zir.Inst.Ref.anyopaque_type), 9178 as_ty | @enumToInt(Zir.Inst.Ref.bool_type), 9179 as_ty | @enumToInt(Zir.Inst.Ref.void_type), 9180 as_ty | @enumToInt(Zir.Inst.Ref.type_type), 9181 as_ty | @enumToInt(Zir.Inst.Ref.anyerror_type), 9182 as_ty | @enumToInt(Zir.Inst.Ref.comptime_int_type), 9183 as_ty | @enumToInt(Zir.Inst.Ref.comptime_float_type), 9184 as_ty | @enumToInt(Zir.Inst.Ref.noreturn_type), 9185 as_ty | @enumToInt(Zir.Inst.Ref.null_type), 9186 as_ty | @enumToInt(Zir.Inst.Ref.undefined_type), 9187 as_ty | @enumToInt(Zir.Inst.Ref.fn_noreturn_no_args_type), 9188 as_ty | @enumToInt(Zir.Inst.Ref.fn_void_no_args_type), 9189 as_ty | @enumToInt(Zir.Inst.Ref.fn_naked_noreturn_no_args_type), 9190 as_ty | @enumToInt(Zir.Inst.Ref.fn_ccc_void_no_args_type), 9191 as_ty | @enumToInt(Zir.Inst.Ref.single_const_pointer_to_comptime_int_type), 9192 as_ty | @enumToInt(Zir.Inst.Ref.const_slice_u8_type), 9193 as_ty | @enumToInt(Zir.Inst.Ref.enum_literal_type), 9194 as_comptime_int | @enumToInt(Zir.Inst.Ref.zero), 9195 as_comptime_int | @enumToInt(Zir.Inst.Ref.one), 9196 as_bool | @enumToInt(Zir.Inst.Ref.bool_true), 9197 as_bool | @enumToInt(Zir.Inst.Ref.bool_false), 9198 as_usize | @enumToInt(Zir.Inst.Ref.zero_usize), 9199 as_usize | @enumToInt(Zir.Inst.Ref.one_usize), 9200 as_void | @enumToInt(Zir.Inst.Ref.void_value), 9201 => return result, // type of result is already correct 9202 9203 // Need an explicit type coercion instruction. 9204 else => return gz.addPlNode(.as_node, src_node, Zir.Inst.As{ 9205 .dest_type = ty_inst, 9206 .operand = result, 9207 }), 9208 } 9209 }, 9210 .ptr => |ptr_inst| { 9211 if (gz.rvalue_noresult != ptr_inst) { 9212 _ = try gz.addPlNode(.store_node, src_node, Zir.Inst.Bin{ 9213 .lhs = ptr_inst, 9214 .rhs = result, 9215 }); 9216 } 9217 return result; 9218 }, 9219 .inferred_ptr => |alloc| { 9220 if (gz.rvalue_noresult != alloc) { 9221 _ = try gz.addBin(.store_to_inferred_ptr, alloc, result); 9222 } 9223 return result; 9224 }, 9225 .block_ptr => |block_scope| { 9226 if (gz.rvalue_noresult != block_scope.rl_ptr) { 9227 block_scope.rvalue_rl_count += 1; 9228 _ = try gz.addBin(.store_to_block_ptr, block_scope.rl_ptr, result); 9229 } 9230 return result; 9231 }, 9232 } 9233 } 9234 9235 /// Given an identifier token, obtain the string for it. 9236 /// If the token uses @"" syntax, parses as a string, reports errors if applicable, 9237 /// and allocates the result within `astgen.arena`. 9238 /// Otherwise, returns a reference to the source code bytes directly. 9239 /// See also `appendIdentStr` and `parseStrLit`. 9240 fn identifierTokenString(astgen: *AstGen, token: Ast.TokenIndex) InnerError![]const u8 { 9241 const tree = astgen.tree; 9242 const token_tags = tree.tokens.items(.tag); 9243 assert(token_tags[token] == .identifier); 9244 const ident_name = tree.tokenSlice(token); 9245 if (!mem.startsWith(u8, ident_name, "@")) { 9246 return ident_name; 9247 } 9248 var buf: ArrayListUnmanaged(u8) = .{}; 9249 defer buf.deinit(astgen.gpa); 9250 try astgen.parseStrLit(token, &buf, ident_name, 1); 9251 const duped = try astgen.arena.dupe(u8, buf.items); 9252 return duped; 9253 } 9254 9255 /// Given an identifier token, obtain the string for it (possibly parsing as a string 9256 /// literal if it is @"" syntax), and append the string to `buf`. 9257 /// See also `identifierTokenString` and `parseStrLit`. 9258 fn appendIdentStr( 9259 astgen: *AstGen, 9260 token: Ast.TokenIndex, 9261 buf: *ArrayListUnmanaged(u8), 9262 ) InnerError!void { 9263 const tree = astgen.tree; 9264 const token_tags = tree.tokens.items(.tag); 9265 assert(token_tags[token] == .identifier); 9266 const ident_name = tree.tokenSlice(token); 9267 if (!mem.startsWith(u8, ident_name, "@")) { 9268 return buf.appendSlice(astgen.gpa, ident_name); 9269 } else { 9270 return astgen.parseStrLit(token, buf, ident_name, 1); 9271 } 9272 } 9273 9274 /// Appends the result to `buf`. 9275 fn parseStrLit( 9276 astgen: *AstGen, 9277 token: Ast.TokenIndex, 9278 buf: *ArrayListUnmanaged(u8), 9279 bytes: []const u8, 9280 offset: u32, 9281 ) InnerError!void { 9282 const raw_string = bytes[offset..]; 9283 var buf_managed = buf.toManaged(astgen.gpa); 9284 const result = std.zig.string_literal.parseAppend(&buf_managed, raw_string); 9285 buf.* = buf_managed.moveToUnmanaged(); 9286 switch (try result) { 9287 .success => return, 9288 .failure => |err| return astgen.failWithStrLitError(err, token, bytes, offset), 9289 } 9290 } 9291 9292 fn failWithStrLitError(astgen: *AstGen, err: std.zig.string_literal.Error, token: Ast.TokenIndex, bytes: []const u8, offset: u32) InnerError { 9293 const raw_string = bytes[offset..]; 9294 switch (err) { 9295 .invalid_escape_character => |bad_index| { 9296 return astgen.failOff( 9297 token, 9298 offset + @intCast(u32, bad_index), 9299 "invalid escape character: '{c}'", 9300 .{raw_string[bad_index]}, 9301 ); 9302 }, 9303 .expected_hex_digit => |bad_index| { 9304 return astgen.failOff( 9305 token, 9306 offset + @intCast(u32, bad_index), 9307 "expected hex digit, found '{c}'", 9308 .{raw_string[bad_index]}, 9309 ); 9310 }, 9311 .empty_unicode_escape_sequence => |bad_index| { 9312 return astgen.failOff( 9313 token, 9314 offset + @intCast(u32, bad_index), 9315 "empty unicode escape sequence", 9316 .{}, 9317 ); 9318 }, 9319 .expected_hex_digit_or_rbrace => |bad_index| { 9320 return astgen.failOff( 9321 token, 9322 offset + @intCast(u32, bad_index), 9323 "expected hex digit or '}}', found '{c}'", 9324 .{raw_string[bad_index]}, 9325 ); 9326 }, 9327 .invalid_unicode_codepoint => |bad_index| { 9328 return astgen.failOff( 9329 token, 9330 offset + @intCast(u32, bad_index), 9331 "unicode escape does not correspond to a valid codepoint", 9332 .{}, 9333 ); 9334 }, 9335 .expected_lbrace => |bad_index| { 9336 return astgen.failOff( 9337 token, 9338 offset + @intCast(u32, bad_index), 9339 "expected '{{', found '{c}", 9340 .{raw_string[bad_index]}, 9341 ); 9342 }, 9343 .expected_rbrace => |bad_index| { 9344 return astgen.failOff( 9345 token, 9346 offset + @intCast(u32, bad_index), 9347 "expected '}}', found '{c}", 9348 .{raw_string[bad_index]}, 9349 ); 9350 }, 9351 .expected_single_quote => |bad_index| { 9352 return astgen.failOff( 9353 token, 9354 offset + @intCast(u32, bad_index), 9355 "expected single quote ('), found '{c}", 9356 .{raw_string[bad_index]}, 9357 ); 9358 }, 9359 .invalid_character => |bad_index| { 9360 return astgen.failOff( 9361 token, 9362 offset + @intCast(u32, bad_index), 9363 "invalid byte in string or character literal: '{c}'", 9364 .{raw_string[bad_index]}, 9365 ); 9366 }, 9367 } 9368 } 9369 9370 fn failNode( 9371 astgen: *AstGen, 9372 node: Ast.Node.Index, 9373 comptime format: []const u8, 9374 args: anytype, 9375 ) InnerError { 9376 return astgen.failNodeNotes(node, format, args, &[0]u32{}); 9377 } 9378 9379 fn appendErrorNode( 9380 astgen: *AstGen, 9381 node: Ast.Node.Index, 9382 comptime format: []const u8, 9383 args: anytype, 9384 ) Allocator.Error!void { 9385 try astgen.appendErrorNodeNotes(node, format, args, &[0]u32{}); 9386 } 9387 9388 fn appendErrorNodeNotes( 9389 astgen: *AstGen, 9390 node: Ast.Node.Index, 9391 comptime format: []const u8, 9392 args: anytype, 9393 notes: []const u32, 9394 ) Allocator.Error!void { 9395 @setCold(true); 9396 const string_bytes = &astgen.string_bytes; 9397 const msg = @intCast(u32, string_bytes.items.len); 9398 try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); 9399 const notes_index: u32 = if (notes.len != 0) blk: { 9400 const notes_start = astgen.extra.items.len; 9401 try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len); 9402 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len)); 9403 astgen.extra.appendSliceAssumeCapacity(notes); 9404 break :blk @intCast(u32, notes_start); 9405 } else 0; 9406 try astgen.compile_errors.append(astgen.gpa, .{ 9407 .msg = msg, 9408 .node = node, 9409 .token = 0, 9410 .byte_offset = 0, 9411 .notes = notes_index, 9412 }); 9413 } 9414 9415 fn failNodeNotes( 9416 astgen: *AstGen, 9417 node: Ast.Node.Index, 9418 comptime format: []const u8, 9419 args: anytype, 9420 notes: []const u32, 9421 ) InnerError { 9422 try appendErrorNodeNotes(astgen, node, format, args, notes); 9423 return error.AnalysisFail; 9424 } 9425 9426 fn failTok( 9427 astgen: *AstGen, 9428 token: Ast.TokenIndex, 9429 comptime format: []const u8, 9430 args: anytype, 9431 ) InnerError { 9432 return astgen.failTokNotes(token, format, args, &[0]u32{}); 9433 } 9434 9435 fn appendErrorTok( 9436 astgen: *AstGen, 9437 token: Ast.TokenIndex, 9438 comptime format: []const u8, 9439 args: anytype, 9440 ) !void { 9441 try astgen.appendErrorTokNotes(token, format, args, &[0]u32{}); 9442 } 9443 9444 fn failTokNotes( 9445 astgen: *AstGen, 9446 token: Ast.TokenIndex, 9447 comptime format: []const u8, 9448 args: anytype, 9449 notes: []const u32, 9450 ) InnerError { 9451 try appendErrorTokNotes(astgen, token, format, args, notes); 9452 return error.AnalysisFail; 9453 } 9454 9455 fn appendErrorTokNotes( 9456 astgen: *AstGen, 9457 token: Ast.TokenIndex, 9458 comptime format: []const u8, 9459 args: anytype, 9460 notes: []const u32, 9461 ) !void { 9462 @setCold(true); 9463 const string_bytes = &astgen.string_bytes; 9464 const msg = @intCast(u32, string_bytes.items.len); 9465 try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); 9466 const notes_index: u32 = if (notes.len != 0) blk: { 9467 const notes_start = astgen.extra.items.len; 9468 try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len); 9469 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len)); 9470 astgen.extra.appendSliceAssumeCapacity(notes); 9471 break :blk @intCast(u32, notes_start); 9472 } else 0; 9473 try astgen.compile_errors.append(astgen.gpa, .{ 9474 .msg = msg, 9475 .node = 0, 9476 .token = token, 9477 .byte_offset = 0, 9478 .notes = notes_index, 9479 }); 9480 } 9481 9482 /// Same as `fail`, except given an absolute byte offset. 9483 fn failOff( 9484 astgen: *AstGen, 9485 token: Ast.TokenIndex, 9486 byte_offset: u32, 9487 comptime format: []const u8, 9488 args: anytype, 9489 ) InnerError { 9490 try appendErrorOff(astgen, token, byte_offset, format, args); 9491 return error.AnalysisFail; 9492 } 9493 9494 fn appendErrorOff( 9495 astgen: *AstGen, 9496 token: Ast.TokenIndex, 9497 byte_offset: u32, 9498 comptime format: []const u8, 9499 args: anytype, 9500 ) Allocator.Error!void { 9501 @setCold(true); 9502 const string_bytes = &astgen.string_bytes; 9503 const msg = @intCast(u32, string_bytes.items.len); 9504 try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); 9505 try astgen.compile_errors.append(astgen.gpa, .{ 9506 .msg = msg, 9507 .node = 0, 9508 .token = token, 9509 .byte_offset = byte_offset, 9510 .notes = 0, 9511 }); 9512 } 9513 9514 fn errNoteTok( 9515 astgen: *AstGen, 9516 token: Ast.TokenIndex, 9517 comptime format: []const u8, 9518 args: anytype, 9519 ) Allocator.Error!u32 { 9520 @setCold(true); 9521 const string_bytes = &astgen.string_bytes; 9522 const msg = @intCast(u32, string_bytes.items.len); 9523 try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); 9524 return astgen.addExtra(Zir.Inst.CompileErrors.Item{ 9525 .msg = msg, 9526 .node = 0, 9527 .token = token, 9528 .byte_offset = 0, 9529 .notes = 0, 9530 }); 9531 } 9532 9533 fn errNoteNode( 9534 astgen: *AstGen, 9535 node: Ast.Node.Index, 9536 comptime format: []const u8, 9537 args: anytype, 9538 ) Allocator.Error!u32 { 9539 @setCold(true); 9540 const string_bytes = &astgen.string_bytes; 9541 const msg = @intCast(u32, string_bytes.items.len); 9542 try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); 9543 return astgen.addExtra(Zir.Inst.CompileErrors.Item{ 9544 .msg = msg, 9545 .node = node, 9546 .token = 0, 9547 .byte_offset = 0, 9548 .notes = 0, 9549 }); 9550 } 9551 9552 fn identAsString(astgen: *AstGen, ident_token: Ast.TokenIndex) !u32 { 9553 const gpa = astgen.gpa; 9554 const string_bytes = &astgen.string_bytes; 9555 const str_index = @intCast(u32, string_bytes.items.len); 9556 try astgen.appendIdentStr(ident_token, string_bytes); 9557 const key = string_bytes.items[str_index..]; 9558 const gop = try astgen.string_table.getOrPutContextAdapted(gpa, @as([]const u8, key), StringIndexAdapter{ 9559 .bytes = string_bytes, 9560 }, StringIndexContext{ 9561 .bytes = string_bytes, 9562 }); 9563 if (gop.found_existing) { 9564 string_bytes.shrinkRetainingCapacity(str_index); 9565 return gop.key_ptr.*; 9566 } else { 9567 gop.key_ptr.* = str_index; 9568 try string_bytes.append(gpa, 0); 9569 return str_index; 9570 } 9571 } 9572 9573 /// Adds a doc comment block to `string_bytes` by walking backwards from `end_token`. 9574 /// `end_token` must point at the first token after the last doc coment line. 9575 /// Returns 0 if no doc comment is present. 9576 fn docCommentAsString(astgen: *AstGen, end_token: Ast.TokenIndex) !u32 { 9577 if (end_token == 0) return @as(u32, 0); 9578 9579 const token_tags = astgen.tree.tokens.items(.tag); 9580 9581 var tok = end_token - 1; 9582 while (token_tags[tok] == .doc_comment) { 9583 if (tok == 0) break; 9584 tok -= 1; 9585 } else { 9586 tok += 1; 9587 } 9588 return docCommentAsStringFromFirst(astgen, end_token, tok); 9589 } 9590 9591 /// end_token must be > the index of the last doc comment. 9592 fn docCommentAsStringFromFirst( 9593 astgen: *AstGen, 9594 end_token: Ast.TokenIndex, 9595 start_token: Ast.TokenIndex, 9596 ) !u32 { 9597 if (start_token == end_token) return 0; 9598 9599 const gpa = astgen.gpa; 9600 const string_bytes = &astgen.string_bytes; 9601 const str_index = @intCast(u32, string_bytes.items.len); 9602 const token_starts = astgen.tree.tokens.items(.start); 9603 const token_tags = astgen.tree.tokens.items(.tag); 9604 9605 const total_bytes = token_starts[end_token] - token_starts[start_token]; 9606 try string_bytes.ensureUnusedCapacity(gpa, total_bytes); 9607 9608 var current_token = start_token; 9609 while (current_token < end_token) : (current_token += 1) { 9610 switch (token_tags[current_token]) { 9611 .doc_comment => { 9612 const tok_bytes = astgen.tree.tokenSlice(current_token)[3..]; 9613 string_bytes.appendSliceAssumeCapacity(tok_bytes); 9614 if (current_token != end_token - 1) { 9615 string_bytes.appendAssumeCapacity('\n'); 9616 } 9617 }, 9618 else => break, 9619 } 9620 } 9621 9622 const key = string_bytes.items[str_index..]; 9623 const gop = try astgen.string_table.getOrPutContextAdapted(gpa, @as([]const u8, key), StringIndexAdapter{ 9624 .bytes = string_bytes, 9625 }, StringIndexContext{ 9626 .bytes = string_bytes, 9627 }); 9628 9629 if (gop.found_existing) { 9630 string_bytes.shrinkRetainingCapacity(str_index); 9631 return gop.key_ptr.*; 9632 } else { 9633 gop.key_ptr.* = str_index; 9634 try string_bytes.append(gpa, 0); 9635 return str_index; 9636 } 9637 } 9638 9639 const IndexSlice = struct { index: u32, len: u32 }; 9640 9641 fn strLitAsString(astgen: *AstGen, str_lit_token: Ast.TokenIndex) !IndexSlice { 9642 const gpa = astgen.gpa; 9643 const string_bytes = &astgen.string_bytes; 9644 const str_index = @intCast(u32, string_bytes.items.len); 9645 const token_bytes = astgen.tree.tokenSlice(str_lit_token); 9646 try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0); 9647 const key = string_bytes.items[str_index..]; 9648 const gop = try astgen.string_table.getOrPutContextAdapted(gpa, @as([]const u8, key), StringIndexAdapter{ 9649 .bytes = string_bytes, 9650 }, StringIndexContext{ 9651 .bytes = string_bytes, 9652 }); 9653 if (gop.found_existing) { 9654 string_bytes.shrinkRetainingCapacity(str_index); 9655 return IndexSlice{ 9656 .index = gop.key_ptr.*, 9657 .len = @intCast(u32, key.len), 9658 }; 9659 } else { 9660 gop.key_ptr.* = str_index; 9661 // Still need a null byte because we are using the same table 9662 // to lookup null terminated strings, so if we get a match, it has to 9663 // be null terminated for that to work. 9664 try string_bytes.append(gpa, 0); 9665 return IndexSlice{ 9666 .index = str_index, 9667 .len = @intCast(u32, key.len), 9668 }; 9669 } 9670 } 9671 9672 fn strLitNodeAsString(astgen: *AstGen, node: Ast.Node.Index) !IndexSlice { 9673 const tree = astgen.tree; 9674 const node_datas = tree.nodes.items(.data); 9675 9676 const start = node_datas[node].lhs; 9677 const end = node_datas[node].rhs; 9678 9679 const gpa = astgen.gpa; 9680 const string_bytes = &astgen.string_bytes; 9681 const str_index = string_bytes.items.len; 9682 9683 // First line: do not append a newline. 9684 var tok_i = start; 9685 { 9686 const slice = tree.tokenSlice(tok_i); 9687 const line_bytes = slice[2 .. slice.len - 1]; 9688 try string_bytes.appendSlice(gpa, line_bytes); 9689 tok_i += 1; 9690 } 9691 // Following lines: each line prepends a newline. 9692 while (tok_i <= end) : (tok_i += 1) { 9693 const slice = tree.tokenSlice(tok_i); 9694 const line_bytes = slice[2 .. slice.len - 1]; 9695 try string_bytes.ensureUnusedCapacity(gpa, line_bytes.len + 1); 9696 string_bytes.appendAssumeCapacity('\n'); 9697 string_bytes.appendSliceAssumeCapacity(line_bytes); 9698 } 9699 const len = string_bytes.items.len - str_index; 9700 try string_bytes.append(gpa, 0); 9701 return IndexSlice{ 9702 .index = @intCast(u32, str_index), 9703 .len = @intCast(u32, len), 9704 }; 9705 } 9706 9707 fn testNameString(astgen: *AstGen, str_lit_token: Ast.TokenIndex) !u32 { 9708 const gpa = astgen.gpa; 9709 const string_bytes = &astgen.string_bytes; 9710 const str_index = @intCast(u32, string_bytes.items.len); 9711 const token_bytes = astgen.tree.tokenSlice(str_lit_token); 9712 try string_bytes.append(gpa, 0); // Indicates this is a test. 9713 try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0); 9714 try string_bytes.append(gpa, 0); 9715 return str_index; 9716 } 9717 9718 const Scope = struct { 9719 tag: Tag, 9720 9721 fn cast(base: *Scope, comptime T: type) ?*T { 9722 if (T == Defer) { 9723 switch (base.tag) { 9724 .defer_normal, .defer_error => return @fieldParentPtr(T, "base", base), 9725 else => return null, 9726 } 9727 } 9728 if (base.tag != T.base_tag) 9729 return null; 9730 9731 return @fieldParentPtr(T, "base", base); 9732 } 9733 9734 fn parent(base: *Scope) ?*Scope { 9735 return switch (base.tag) { 9736 .gen_zir => base.cast(GenZir).?.parent, 9737 .local_val => base.cast(LocalVal).?.parent, 9738 .local_ptr => base.cast(LocalPtr).?.parent, 9739 .defer_normal, .defer_error => base.cast(Defer).?.parent, 9740 .namespace => base.cast(Namespace).?.parent, 9741 .top => null, 9742 }; 9743 } 9744 9745 const Tag = enum { 9746 gen_zir, 9747 local_val, 9748 local_ptr, 9749 defer_normal, 9750 defer_error, 9751 namespace, 9752 top, 9753 }; 9754 9755 /// The category of identifier. These tag names are user-visible in compile errors. 9756 const IdCat = enum { 9757 @"function parameter", 9758 @"local constant", 9759 @"local variable", 9760 @"loop index capture", 9761 @"capture", 9762 }; 9763 9764 /// This is always a `const` local and importantly the `inst` is a value type, not a pointer. 9765 /// This structure lives as long as the AST generation of the Block 9766 /// node that contains the variable. 9767 const LocalVal = struct { 9768 const base_tag: Tag = .local_val; 9769 base: Scope = Scope{ .tag = base_tag }, 9770 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`. 9771 parent: *Scope, 9772 gen_zir: *GenZir, 9773 inst: Zir.Inst.Ref, 9774 /// Source location of the corresponding variable declaration. 9775 token_src: Ast.TokenIndex, 9776 /// String table index. 9777 name: u32, 9778 id_cat: IdCat, 9779 /// Track whether the name has been referenced. 9780 used: bool = false, 9781 }; 9782 9783 /// This could be a `const` or `var` local. It has a pointer instead of a value. 9784 /// This structure lives as long as the AST generation of the Block 9785 /// node that contains the variable. 9786 const LocalPtr = struct { 9787 const base_tag: Tag = .local_ptr; 9788 base: Scope = Scope{ .tag = base_tag }, 9789 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`. 9790 parent: *Scope, 9791 gen_zir: *GenZir, 9792 ptr: Zir.Inst.Ref, 9793 /// Source location of the corresponding variable declaration. 9794 token_src: Ast.TokenIndex, 9795 /// String table index. 9796 name: u32, 9797 id_cat: IdCat, 9798 /// true means we find out during Sema whether the value is comptime. 9799 /// false means it is already known at AstGen the value is runtime-known. 9800 maybe_comptime: bool, 9801 /// Track whether the name has been referenced. 9802 used: bool = false, 9803 }; 9804 9805 const Defer = struct { 9806 base: Scope, 9807 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`. 9808 parent: *Scope, 9809 defer_node: Ast.Node.Index, 9810 source_offset: u32, 9811 source_line: u32, 9812 source_column: u32, 9813 }; 9814 9815 /// Represents a global scope that has any number of declarations in it. 9816 /// Each declaration has this as the parent scope. 9817 const Namespace = struct { 9818 const base_tag: Tag = .namespace; 9819 base: Scope = Scope{ .tag = base_tag }, 9820 9821 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`. 9822 parent: *Scope, 9823 /// Maps string table index to the source location of declaration, 9824 /// for the purposes of reporting name shadowing compile errors. 9825 decls: std.AutoHashMapUnmanaged(u32, Ast.Node.Index) = .{}, 9826 node: Ast.Node.Index, 9827 inst: Zir.Inst.Index, 9828 9829 /// The astgen scope containing this namespace. 9830 /// Only valid during astgen. 9831 declaring_gz: ?*GenZir, 9832 9833 /// Map from the raw captured value to the instruction 9834 /// ref of the capture for decls in this namespace 9835 captures: std.AutoArrayHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}, 9836 9837 pub fn deinit(self: *Namespace, gpa: Allocator) void { 9838 self.decls.deinit(gpa); 9839 self.captures.deinit(gpa); 9840 self.* = undefined; 9841 } 9842 }; 9843 9844 const Top = struct { 9845 const base_tag: Scope.Tag = .top; 9846 base: Scope = Scope{ .tag = base_tag }, 9847 }; 9848 }; 9849 9850 /// This is a temporary structure; references to it are valid only 9851 /// while constructing a `Zir`. 9852 const GenZir = struct { 9853 const base_tag: Scope.Tag = .gen_zir; 9854 base: Scope = Scope{ .tag = base_tag }, 9855 force_comptime: bool, 9856 /// This is set to true for inline loops; false otherwise. 9857 is_inline: bool = false, 9858 in_defer: bool, 9859 c_import: bool = false, 9860 /// How decls created in this scope should be named. 9861 anon_name_strategy: Zir.Inst.NameStrategy = .anon, 9862 /// The containing decl AST node. 9863 decl_node_index: Ast.Node.Index, 9864 /// The containing decl line index, absolute. 9865 decl_line: u32, 9866 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`. 9867 parent: *Scope, 9868 /// All `GenZir` scopes for the same ZIR share this. 9869 astgen: *AstGen, 9870 /// Keeps track of the list of instructions in this scope. Possibly shared. 9871 /// Indexes to instructions in `astgen`. 9872 instructions: *ArrayListUnmanaged(Zir.Inst.Index), 9873 /// A sub-block may share its instructions ArrayList with containing GenZir, 9874 /// if use is strictly nested. This saves prior size of list for unstacking. 9875 instructions_top: usize, 9876 label: ?Label = null, 9877 break_block: Zir.Inst.Index = 0, 9878 continue_block: Zir.Inst.Index = 0, 9879 /// Only valid when setBreakResultLoc is called. 9880 break_result_loc: AstGen.ResultLoc = undefined, 9881 /// When a block has a pointer result location, here it is. 9882 rl_ptr: Zir.Inst.Ref = .none, 9883 /// When a block has a type result location, here it is. 9884 rl_ty_inst: Zir.Inst.Ref = .none, 9885 rvalue_noresult: Zir.Inst.Ref = .none, 9886 /// Keeps track of how many branches of a block did not actually 9887 /// consume the result location. astgen uses this to figure out 9888 /// whether to rely on break instructions or writing to the result 9889 /// pointer for the result instruction. 9890 rvalue_rl_count: usize = 0, 9891 /// Keeps track of how many break instructions there are. When astgen is finished 9892 /// with a block, it can check this against rvalue_rl_count to find out whether 9893 /// the break instructions should be downgraded to break_void. 9894 break_count: usize = 0, 9895 /// Tracks `break :foo bar` instructions so they can possibly be elided later if 9896 /// the labeled block ends up not needing a result location pointer. 9897 labeled_breaks: ArrayListUnmanaged(struct { br: Zir.Inst.Index, search: Zir.Inst.Index }) = .{}, 9898 9899 suspend_node: Ast.Node.Index = 0, 9900 nosuspend_node: Ast.Node.Index = 0, 9901 9902 /// Namespace members are lazy. When executing a decl within a namespace, 9903 /// any references to external instructions need to be treated specially. 9904 /// This list tracks those references. See also .closure_capture and .closure_get. 9905 /// Keys are the raw instruction index, values are the closure_capture instruction. 9906 captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}, 9907 9908 const unstacked_top = std.math.maxInt(usize); 9909 /// Call unstack before adding any new instructions to containing GenZir. 9910 fn unstack(self: *GenZir) void { 9911 if (self.instructions_top != unstacked_top) { 9912 self.instructions.items.len = self.instructions_top; 9913 self.instructions_top = unstacked_top; 9914 } 9915 } 9916 9917 fn isEmpty(self: *const GenZir) bool { 9918 return (self.instructions_top == unstacked_top) or 9919 (self.instructions.items.len == self.instructions_top); 9920 } 9921 9922 fn instructionsSlice(self: *const GenZir) []Zir.Inst.Index { 9923 return if (self.instructions_top == unstacked_top) 9924 &[0]Zir.Inst.Index{} 9925 else 9926 self.instructions.items[self.instructions_top..]; 9927 } 9928 9929 fn instructionsSliceUpto(self: *const GenZir, stacked_gz: *GenZir) []Zir.Inst.Index { 9930 return if (self.instructions_top == unstacked_top) 9931 &[0]Zir.Inst.Index{} 9932 else if (self.instructions == stacked_gz.instructions and stacked_gz.instructions_top != unstacked_top) 9933 self.instructions.items[self.instructions_top..stacked_gz.instructions_top] 9934 else 9935 self.instructions.items[self.instructions_top..]; 9936 } 9937 9938 fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir { 9939 return .{ 9940 .force_comptime = gz.force_comptime, 9941 .in_defer = gz.in_defer, 9942 .c_import = gz.c_import, 9943 .decl_node_index = gz.decl_node_index, 9944 .decl_line = gz.decl_line, 9945 .parent = scope, 9946 .rl_ty_inst = gz.rl_ty_inst, 9947 .astgen = gz.astgen, 9948 .suspend_node = gz.suspend_node, 9949 .nosuspend_node = gz.nosuspend_node, 9950 .instructions = gz.instructions, 9951 .instructions_top = gz.instructions.items.len, 9952 }; 9953 } 9954 9955 fn makeCoercionScope( 9956 parent_gz: *GenZir, 9957 scope: *Scope, 9958 dest_type: Zir.Inst.Ref, 9959 result_ptr: Zir.Inst.Ref, 9960 src_node: Ast.Node.Index, 9961 ) !GenZir { 9962 // Detect whether this expr() call goes into rvalue() to store the result into the 9963 // result location. If it does, elide the coerce_result_ptr instruction 9964 // as well as the store instruction, instead passing the result as an rvalue. 9965 var as_scope = parent_gz.makeSubBlock(scope); 9966 errdefer as_scope.unstack(); 9967 as_scope.rl_ptr = try as_scope.addPlNode(.coerce_result_ptr, src_node, Zir.Inst.Bin{ .lhs = dest_type, .rhs = result_ptr }); 9968 9969 // `rl_ty_inst` needs to be set in case the stores to `rl_ptr` are eliminated. 9970 as_scope.rl_ty_inst = dest_type; 9971 9972 return as_scope; 9973 } 9974 9975 /// Assumes `as_scope` is stacked immediately on top of `parent_gz`. Unstacks `as_scope`. 9976 fn finishCoercion( 9977 as_scope: *GenZir, 9978 parent_gz: *GenZir, 9979 rl: ResultLoc, 9980 src_node: Ast.Node.Index, 9981 result: Zir.Inst.Ref, 9982 dest_type: Zir.Inst.Ref, 9983 ) InnerError!Zir.Inst.Ref { 9984 assert(as_scope.instructions == parent_gz.instructions); 9985 const astgen = as_scope.astgen; 9986 if (as_scope.rvalue_rl_count == 1) { 9987 // Busted! This expression didn't actually need a pointer. 9988 const zir_tags = astgen.instructions.items(.tag); 9989 const zir_datas = astgen.instructions.items(.data); 9990 var src: usize = as_scope.instructions_top; 9991 var dst: usize = src; 9992 while (src < as_scope.instructions.items.len) : (src += 1) { 9993 const src_inst = as_scope.instructions.items[src]; 9994 if (indexToRef(src_inst) == as_scope.rl_ptr) continue; 9995 if (zir_tags[src_inst] == .store_to_block_ptr) { 9996 if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue; 9997 } 9998 as_scope.instructions.items[dst] = src_inst; 9999 dst += 1; 10000 } 10001 parent_gz.instructions.items.len -= src - dst; 10002 as_scope.instructions_top = GenZir.unstacked_top; 10003 // as_scope now unstacked, can add new instructions to parent_gz 10004 const casted_result = try parent_gz.addBin(.as, dest_type, result); 10005 return rvalue(parent_gz, rl, casted_result, src_node); 10006 } else { 10007 // implicitly move all as_scope instructions to parent_gz 10008 as_scope.instructions_top = GenZir.unstacked_top; 10009 return result; 10010 } 10011 } 10012 10013 const Label = struct { 10014 token: Ast.TokenIndex, 10015 block_inst: Zir.Inst.Index, 10016 used: bool = false, 10017 }; 10018 10019 /// Assumes nothing stacked on `gz`. 10020 fn endsWithNoReturn(gz: GenZir) bool { 10021 if (gz.isEmpty()) return false; 10022 const tags = gz.astgen.instructions.items(.tag); 10023 const last_inst = gz.instructions.items[gz.instructions.items.len - 1]; 10024 return tags[last_inst].isNoReturn(); 10025 } 10026 10027 /// TODO all uses of this should be replaced with uses of `endsWithNoReturn`. 10028 fn refIsNoReturn(gz: GenZir, inst_ref: Zir.Inst.Ref) bool { 10029 if (inst_ref == .unreachable_value) return true; 10030 if (refToIndex(inst_ref)) |inst_index| { 10031 return gz.astgen.instructions.items(.tag)[inst_index].isNoReturn(); 10032 } 10033 return false; 10034 } 10035 10036 fn nodeIndexToRelative(gz: GenZir, node_index: Ast.Node.Index) i32 { 10037 return @bitCast(i32, node_index) - @bitCast(i32, gz.decl_node_index); 10038 } 10039 10040 fn tokenIndexToRelative(gz: GenZir, token: Ast.TokenIndex) u32 { 10041 return token - gz.srcToken(); 10042 } 10043 10044 fn srcToken(gz: GenZir) Ast.TokenIndex { 10045 return gz.astgen.tree.firstToken(gz.decl_node_index); 10046 } 10047 10048 fn setBreakResultLoc(gz: *GenZir, parent_rl: AstGen.ResultLoc) void { 10049 // Depending on whether the result location is a pointer or value, different 10050 // ZIR needs to be generated. In the former case we rely on storing to the 10051 // pointer to communicate the result, and use breakvoid; in the latter case 10052 // the block break instructions will have the result values. 10053 // One more complication: when the result location is a pointer, we detect 10054 // the scenario where the result location is not consumed. In this case 10055 // we emit ZIR for the block break instructions to have the result values, 10056 // and then rvalue() on that to pass the value to the result location. 10057 switch (parent_rl) { 10058 .ty, .coerced_ty => |ty_inst| { 10059 gz.rl_ty_inst = ty_inst; 10060 gz.break_result_loc = parent_rl; 10061 }, 10062 10063 .discard, .none, .ptr, .ref => { 10064 gz.rl_ty_inst = .none; 10065 gz.break_result_loc = parent_rl; 10066 }, 10067 10068 .inferred_ptr => |ptr| { 10069 gz.rl_ty_inst = .none; 10070 gz.rl_ptr = ptr; 10071 gz.break_result_loc = .{ .block_ptr = gz }; 10072 }, 10073 10074 .block_ptr => |parent_block_scope| { 10075 gz.rl_ty_inst = parent_block_scope.rl_ty_inst; 10076 gz.rl_ptr = parent_block_scope.rl_ptr; 10077 gz.break_result_loc = .{ .block_ptr = gz }; 10078 }, 10079 } 10080 } 10081 10082 /// Assumes nothing stacked on `gz`. Unstacks `gz`. 10083 fn setBoolBrBody(gz: *GenZir, inst: Zir.Inst.Index) !void { 10084 const astgen = gz.astgen; 10085 const gpa = astgen.gpa; 10086 const body = gz.instructionsSlice(); 10087 const body_len = astgen.countBodyLenAfterFixups(body); 10088 try astgen.extra.ensureUnusedCapacity( 10089 gpa, 10090 @typeInfo(Zir.Inst.Block).Struct.fields.len + body_len, 10091 ); 10092 const zir_datas = astgen.instructions.items(.data); 10093 zir_datas[inst].bool_br.payload_index = astgen.addExtraAssumeCapacity( 10094 Zir.Inst.Block{ .body_len = body_len }, 10095 ); 10096 astgen.appendBodyWithFixups(body); 10097 gz.unstack(); 10098 } 10099 10100 /// Assumes nothing stacked on `gz`. Unstacks `gz`. 10101 fn setBlockBody(gz: *GenZir, inst: Zir.Inst.Index) !void { 10102 const astgen = gz.astgen; 10103 const gpa = astgen.gpa; 10104 const body = gz.instructionsSlice(); 10105 const body_len = astgen.countBodyLenAfterFixups(body); 10106 try astgen.extra.ensureUnusedCapacity( 10107 gpa, 10108 @typeInfo(Zir.Inst.Block).Struct.fields.len + body_len, 10109 ); 10110 const zir_datas = astgen.instructions.items(.data); 10111 zir_datas[inst].pl_node.payload_index = astgen.addExtraAssumeCapacity( 10112 Zir.Inst.Block{ .body_len = body_len }, 10113 ); 10114 astgen.appendBodyWithFixups(body); 10115 gz.unstack(); 10116 } 10117 10118 /// Assumes nothing stacked on `gz`. Unstacks `gz`. 10119 fn setTryBody(gz: *GenZir, inst: Zir.Inst.Index, operand: Zir.Inst.Ref) !void { 10120 const astgen = gz.astgen; 10121 const gpa = astgen.gpa; 10122 const body = gz.instructionsSlice(); 10123 const body_len = astgen.countBodyLenAfterFixups(body); 10124 try astgen.extra.ensureUnusedCapacity( 10125 gpa, 10126 @typeInfo(Zir.Inst.Try).Struct.fields.len + body_len, 10127 ); 10128 const zir_datas = astgen.instructions.items(.data); 10129 zir_datas[inst].pl_node.payload_index = astgen.addExtraAssumeCapacity( 10130 Zir.Inst.Try{ 10131 .operand = operand, 10132 .body_len = body_len, 10133 }, 10134 ); 10135 astgen.appendBodyWithFixups(body); 10136 gz.unstack(); 10137 } 10138 10139 /// Must be called with the following stack set up: 10140 /// * gz (bottom) 10141 /// * align_gz 10142 /// * addrspace_gz 10143 /// * section_gz 10144 /// * cc_gz 10145 /// * ret_gz 10146 /// * body_gz (top) 10147 /// Unstacks all of those except for `gz`. 10148 fn addFunc(gz: *GenZir, args: struct { 10149 src_node: Ast.Node.Index, 10150 lbrace_line: u32 = 0, 10151 lbrace_column: u32 = 0, 10152 param_block: Zir.Inst.Index, 10153 10154 align_gz: ?*GenZir, 10155 addrspace_gz: ?*GenZir, 10156 section_gz: ?*GenZir, 10157 cc_gz: ?*GenZir, 10158 ret_gz: ?*GenZir, 10159 body_gz: ?*GenZir, 10160 10161 align_ref: Zir.Inst.Ref, 10162 addrspace_ref: Zir.Inst.Ref, 10163 section_ref: Zir.Inst.Ref, 10164 cc_ref: Zir.Inst.Ref, 10165 ret_ref: Zir.Inst.Ref, 10166 10167 lib_name: u32, 10168 noalias_bits: u32, 10169 is_var_args: bool, 10170 is_inferred_error: bool, 10171 is_test: bool, 10172 is_extern: bool, 10173 }) !Zir.Inst.Ref { 10174 assert(args.src_node != 0); 10175 const astgen = gz.astgen; 10176 const gpa = astgen.gpa; 10177 const ret_ref = if (args.ret_ref == .void_type) .none else args.ret_ref; 10178 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 10179 10180 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 10181 10182 var body: []Zir.Inst.Index = &[0]Zir.Inst.Index{}; 10183 var ret_body: []Zir.Inst.Index = &[0]Zir.Inst.Index{}; 10184 var src_locs_buffer: [3]u32 = undefined; 10185 var src_locs: []u32 = src_locs_buffer[0..0]; 10186 if (args.body_gz) |body_gz| { 10187 const tree = astgen.tree; 10188 const node_tags = tree.nodes.items(.tag); 10189 const node_datas = tree.nodes.items(.data); 10190 const token_starts = tree.tokens.items(.start); 10191 const fn_decl = args.src_node; 10192 assert(node_tags[fn_decl] == .fn_decl or node_tags[fn_decl] == .test_decl); 10193 const block = node_datas[fn_decl].rhs; 10194 const rbrace_start = token_starts[tree.lastToken(block)]; 10195 astgen.advanceSourceCursor(rbrace_start); 10196 const rbrace_line = @intCast(u32, astgen.source_line - gz.decl_line); 10197 const rbrace_column = @intCast(u32, astgen.source_column); 10198 10199 const columns = args.lbrace_column | (rbrace_column << 16); 10200 src_locs_buffer[0] = args.lbrace_line; 10201 src_locs_buffer[1] = rbrace_line; 10202 src_locs_buffer[2] = columns; 10203 src_locs = &src_locs_buffer; 10204 10205 body = body_gz.instructionsSlice(); 10206 if (args.ret_gz) |ret_gz| 10207 ret_body = ret_gz.instructionsSliceUpto(body_gz); 10208 } else { 10209 if (args.ret_gz) |ret_gz| 10210 ret_body = ret_gz.instructionsSlice(); 10211 } 10212 const body_len = astgen.countBodyLenAfterFixups(body); 10213 10214 if (args.cc_ref != .none or args.lib_name != 0 or 10215 args.is_var_args or args.is_test or args.is_extern or 10216 args.align_ref != .none or args.section_ref != .none or 10217 args.addrspace_ref != .none or args.noalias_bits != 0) 10218 { 10219 var align_body: []Zir.Inst.Index = &.{}; 10220 var addrspace_body: []Zir.Inst.Index = &.{}; 10221 var section_body: []Zir.Inst.Index = &.{}; 10222 var cc_body: []Zir.Inst.Index = &.{}; 10223 if (args.ret_gz != null) { 10224 align_body = args.align_gz.?.instructionsSliceUpto(args.addrspace_gz.?); 10225 addrspace_body = args.addrspace_gz.?.instructionsSliceUpto(args.section_gz.?); 10226 section_body = args.section_gz.?.instructionsSliceUpto(args.cc_gz.?); 10227 cc_body = args.cc_gz.?.instructionsSliceUpto(args.ret_gz.?); 10228 } 10229 10230 try astgen.extra.ensureUnusedCapacity( 10231 gpa, 10232 @typeInfo(Zir.Inst.FuncFancy).Struct.fields.len + 10233 fancyFnExprExtraLen(align_body, args.align_ref) + 10234 fancyFnExprExtraLen(addrspace_body, args.addrspace_ref) + 10235 fancyFnExprExtraLen(section_body, args.section_ref) + 10236 fancyFnExprExtraLen(cc_body, args.cc_ref) + 10237 fancyFnExprExtraLen(ret_body, ret_ref) + 10238 body_len + src_locs.len + 10239 @boolToInt(args.lib_name != 0) + 10240 @boolToInt(args.noalias_bits != 0), 10241 ); 10242 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.FuncFancy{ 10243 .param_block = args.param_block, 10244 .body_len = body_len, 10245 .bits = .{ 10246 .is_var_args = args.is_var_args, 10247 .is_inferred_error = args.is_inferred_error, 10248 .is_test = args.is_test, 10249 .is_extern = args.is_extern, 10250 .has_lib_name = args.lib_name != 0, 10251 .has_any_noalias = args.noalias_bits != 0, 10252 10253 .has_align_ref = args.align_ref != .none, 10254 .has_addrspace_ref = args.addrspace_ref != .none, 10255 .has_section_ref = args.section_ref != .none, 10256 .has_cc_ref = args.cc_ref != .none, 10257 .has_ret_ty_ref = ret_ref != .none, 10258 10259 .has_align_body = align_body.len != 0, 10260 .has_addrspace_body = addrspace_body.len != 0, 10261 .has_section_body = section_body.len != 0, 10262 .has_cc_body = cc_body.len != 0, 10263 .has_ret_ty_body = ret_body.len != 0, 10264 }, 10265 }); 10266 if (args.lib_name != 0) { 10267 astgen.extra.appendAssumeCapacity(args.lib_name); 10268 } 10269 10270 const zir_datas = astgen.instructions.items(.data); 10271 if (align_body.len != 0) { 10272 astgen.extra.appendAssumeCapacity(@intCast(u32, align_body.len)); 10273 astgen.extra.appendSliceAssumeCapacity(align_body); 10274 zir_datas[align_body[align_body.len - 1]].@"break".block_inst = new_index; 10275 } else if (args.align_ref != .none) { 10276 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_ref)); 10277 } 10278 if (addrspace_body.len != 0) { 10279 astgen.extra.appendAssumeCapacity(@intCast(u32, addrspace_body.len)); 10280 astgen.extra.appendSliceAssumeCapacity(addrspace_body); 10281 zir_datas[addrspace_body[addrspace_body.len - 1]].@"break".block_inst = new_index; 10282 } else if (args.addrspace_ref != .none) { 10283 astgen.extra.appendAssumeCapacity(@enumToInt(args.addrspace_ref)); 10284 } 10285 if (section_body.len != 0) { 10286 astgen.extra.appendAssumeCapacity(@intCast(u32, section_body.len)); 10287 astgen.extra.appendSliceAssumeCapacity(section_body); 10288 zir_datas[section_body[section_body.len - 1]].@"break".block_inst = new_index; 10289 } else if (args.section_ref != .none) { 10290 astgen.extra.appendAssumeCapacity(@enumToInt(args.section_ref)); 10291 } 10292 if (cc_body.len != 0) { 10293 astgen.extra.appendAssumeCapacity(@intCast(u32, cc_body.len)); 10294 astgen.extra.appendSliceAssumeCapacity(cc_body); 10295 zir_datas[cc_body[cc_body.len - 1]].@"break".block_inst = new_index; 10296 } else if (args.cc_ref != .none) { 10297 astgen.extra.appendAssumeCapacity(@enumToInt(args.cc_ref)); 10298 } 10299 if (ret_body.len != 0) { 10300 astgen.extra.appendAssumeCapacity(@intCast(u32, ret_body.len)); 10301 astgen.extra.appendSliceAssumeCapacity(ret_body); 10302 zir_datas[ret_body[ret_body.len - 1]].@"break".block_inst = new_index; 10303 } else if (ret_ref != .none) { 10304 astgen.extra.appendAssumeCapacity(@enumToInt(ret_ref)); 10305 } 10306 10307 if (args.noalias_bits != 0) { 10308 astgen.extra.appendAssumeCapacity(args.noalias_bits); 10309 } 10310 10311 astgen.appendBodyWithFixups(body); 10312 astgen.extra.appendSliceAssumeCapacity(src_locs); 10313 10314 // Order is important when unstacking. 10315 if (args.body_gz) |body_gz| body_gz.unstack(); 10316 if (args.ret_gz != null) { 10317 args.ret_gz.?.unstack(); 10318 args.cc_gz.?.unstack(); 10319 args.section_gz.?.unstack(); 10320 args.addrspace_gz.?.unstack(); 10321 args.align_gz.?.unstack(); 10322 } 10323 10324 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10325 10326 astgen.instructions.appendAssumeCapacity(.{ 10327 .tag = .func_fancy, 10328 .data = .{ .pl_node = .{ 10329 .src_node = gz.nodeIndexToRelative(args.src_node), 10330 .payload_index = payload_index, 10331 } }, 10332 }); 10333 gz.instructions.appendAssumeCapacity(new_index); 10334 return indexToRef(new_index); 10335 } else { 10336 try astgen.extra.ensureUnusedCapacity( 10337 gpa, 10338 @typeInfo(Zir.Inst.Func).Struct.fields.len + 1 + 10339 @maximum(ret_body.len, @boolToInt(ret_ref != .none)) + 10340 body_len + src_locs.len, 10341 ); 10342 const ret_body_len = if (ret_body.len != 0) 10343 @intCast(u32, ret_body.len) 10344 else 10345 @boolToInt(ret_ref != .none); 10346 10347 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.Func{ 10348 .param_block = args.param_block, 10349 .ret_body_len = ret_body_len, 10350 .body_len = body_len, 10351 }); 10352 const zir_datas = astgen.instructions.items(.data); 10353 if (ret_body.len != 0) { 10354 astgen.extra.appendSliceAssumeCapacity(ret_body); 10355 zir_datas[ret_body[ret_body.len - 1]].@"break".block_inst = new_index; 10356 } else if (ret_ref != .none) { 10357 astgen.extra.appendAssumeCapacity(@enumToInt(ret_ref)); 10358 } 10359 astgen.appendBodyWithFixups(body); 10360 astgen.extra.appendSliceAssumeCapacity(src_locs); 10361 10362 // Order is important when unstacking. 10363 if (args.body_gz) |body_gz| body_gz.unstack(); 10364 if (args.ret_gz) |ret_gz| ret_gz.unstack(); 10365 if (args.cc_gz) |cc_gz| cc_gz.unstack(); 10366 if (args.section_gz) |section_gz| section_gz.unstack(); 10367 if (args.addrspace_gz) |addrspace_gz| addrspace_gz.unstack(); 10368 if (args.align_gz) |align_gz| align_gz.unstack(); 10369 10370 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10371 10372 const tag: Zir.Inst.Tag = if (args.is_inferred_error) .func_inferred else .func; 10373 astgen.instructions.appendAssumeCapacity(.{ 10374 .tag = tag, 10375 .data = .{ .pl_node = .{ 10376 .src_node = gz.nodeIndexToRelative(args.src_node), 10377 .payload_index = payload_index, 10378 } }, 10379 }); 10380 gz.instructions.appendAssumeCapacity(new_index); 10381 return indexToRef(new_index); 10382 } 10383 } 10384 10385 fn fancyFnExprExtraLen(body: []Zir.Inst.Index, ref: Zir.Inst.Ref) usize { 10386 // In the case of non-empty body, there is one for the body length, 10387 // and then one for each instruction. 10388 return body.len + @boolToInt(ref != .none); 10389 } 10390 10391 fn addVar(gz: *GenZir, args: struct { 10392 align_inst: Zir.Inst.Ref, 10393 lib_name: u32, 10394 var_type: Zir.Inst.Ref, 10395 init: Zir.Inst.Ref, 10396 is_extern: bool, 10397 is_threadlocal: bool, 10398 }) !Zir.Inst.Ref { 10399 const astgen = gz.astgen; 10400 const gpa = astgen.gpa; 10401 10402 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10403 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 10404 10405 try astgen.extra.ensureUnusedCapacity( 10406 gpa, 10407 @typeInfo(Zir.Inst.ExtendedVar).Struct.fields.len + 10408 @boolToInt(args.lib_name != 0) + 10409 @boolToInt(args.align_inst != .none) + 10410 @boolToInt(args.init != .none), 10411 ); 10412 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedVar{ 10413 .var_type = args.var_type, 10414 }); 10415 if (args.lib_name != 0) { 10416 astgen.extra.appendAssumeCapacity(args.lib_name); 10417 } 10418 if (args.align_inst != .none) { 10419 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); 10420 } 10421 if (args.init != .none) { 10422 astgen.extra.appendAssumeCapacity(@enumToInt(args.init)); 10423 } 10424 10425 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 10426 astgen.instructions.appendAssumeCapacity(.{ 10427 .tag = .extended, 10428 .data = .{ .extended = .{ 10429 .opcode = .variable, 10430 .small = @bitCast(u16, Zir.Inst.ExtendedVar.Small{ 10431 .has_lib_name = args.lib_name != 0, 10432 .has_align = args.align_inst != .none, 10433 .has_init = args.init != .none, 10434 .is_extern = args.is_extern, 10435 .is_threadlocal = args.is_threadlocal, 10436 }), 10437 .operand = payload_index, 10438 } }, 10439 }); 10440 gz.instructions.appendAssumeCapacity(new_index); 10441 return indexToRef(new_index); 10442 } 10443 10444 /// Note that this returns a `Zir.Inst.Index` not a ref. 10445 /// Leaves the `payload_index` field undefined. 10446 fn addBoolBr( 10447 gz: *GenZir, 10448 tag: Zir.Inst.Tag, 10449 lhs: Zir.Inst.Ref, 10450 ) !Zir.Inst.Index { 10451 assert(lhs != .none); 10452 const gpa = gz.astgen.gpa; 10453 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10454 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 10455 10456 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 10457 gz.astgen.instructions.appendAssumeCapacity(.{ 10458 .tag = tag, 10459 .data = .{ .bool_br = .{ 10460 .lhs = lhs, 10461 .payload_index = undefined, 10462 } }, 10463 }); 10464 gz.instructions.appendAssumeCapacity(new_index); 10465 return new_index; 10466 } 10467 10468 fn addInt(gz: *GenZir, integer: u64) !Zir.Inst.Ref { 10469 return gz.add(.{ 10470 .tag = .int, 10471 .data = .{ .int = integer }, 10472 }); 10473 } 10474 10475 fn addIntBig(gz: *GenZir, limbs: []const std.math.big.Limb) !Zir.Inst.Ref { 10476 const astgen = gz.astgen; 10477 const gpa = astgen.gpa; 10478 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10479 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 10480 try astgen.string_bytes.ensureUnusedCapacity(gpa, @sizeOf(std.math.big.Limb) * limbs.len); 10481 10482 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 10483 astgen.instructions.appendAssumeCapacity(.{ 10484 .tag = .int_big, 10485 .data = .{ .str = .{ 10486 .start = @intCast(u32, astgen.string_bytes.items.len), 10487 .len = @intCast(u32, limbs.len), 10488 } }, 10489 }); 10490 gz.instructions.appendAssumeCapacity(new_index); 10491 astgen.string_bytes.appendSliceAssumeCapacity(mem.sliceAsBytes(limbs)); 10492 return indexToRef(new_index); 10493 } 10494 10495 fn addFloat(gz: *GenZir, number: f64) !Zir.Inst.Ref { 10496 return gz.add(.{ 10497 .tag = .float, 10498 .data = .{ .float = number }, 10499 }); 10500 } 10501 10502 fn addUnNode( 10503 gz: *GenZir, 10504 tag: Zir.Inst.Tag, 10505 operand: Zir.Inst.Ref, 10506 /// Absolute node index. This function does the conversion to offset from Decl. 10507 src_node: Ast.Node.Index, 10508 ) !Zir.Inst.Ref { 10509 assert(operand != .none); 10510 return gz.add(.{ 10511 .tag = tag, 10512 .data = .{ .un_node = .{ 10513 .operand = operand, 10514 .src_node = gz.nodeIndexToRelative(src_node), 10515 } }, 10516 }); 10517 } 10518 10519 fn makeUnNode( 10520 gz: *GenZir, 10521 tag: Zir.Inst.Tag, 10522 operand: Zir.Inst.Ref, 10523 /// Absolute node index. This function does the conversion to offset from Decl. 10524 src_node: Ast.Node.Index, 10525 ) !Zir.Inst.Index { 10526 assert(operand != .none); 10527 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 10528 try gz.astgen.instructions.append(gz.astgen.gpa, .{ 10529 .tag = tag, 10530 .data = .{ .un_node = .{ 10531 .operand = operand, 10532 .src_node = gz.nodeIndexToRelative(src_node), 10533 } }, 10534 }); 10535 return new_index; 10536 } 10537 10538 fn addPlNode( 10539 gz: *GenZir, 10540 tag: Zir.Inst.Tag, 10541 /// Absolute node index. This function does the conversion to offset from Decl. 10542 src_node: Ast.Node.Index, 10543 extra: anytype, 10544 ) !Zir.Inst.Ref { 10545 const gpa = gz.astgen.gpa; 10546 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10547 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 10548 10549 const payload_index = try gz.astgen.addExtra(extra); 10550 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 10551 gz.astgen.instructions.appendAssumeCapacity(.{ 10552 .tag = tag, 10553 .data = .{ .pl_node = .{ 10554 .src_node = gz.nodeIndexToRelative(src_node), 10555 .payload_index = payload_index, 10556 } }, 10557 }); 10558 gz.instructions.appendAssumeCapacity(new_index); 10559 return indexToRef(new_index); 10560 } 10561 10562 fn addPlNodePayloadIndex( 10563 gz: *GenZir, 10564 tag: Zir.Inst.Tag, 10565 /// Absolute node index. This function does the conversion to offset from Decl. 10566 src_node: Ast.Node.Index, 10567 payload_index: u32, 10568 ) !Zir.Inst.Ref { 10569 return try gz.add(.{ 10570 .tag = tag, 10571 .data = .{ .pl_node = .{ 10572 .src_node = gz.nodeIndexToRelative(src_node), 10573 .payload_index = payload_index, 10574 } }, 10575 }); 10576 } 10577 10578 /// Supports `param_gz` stacked on `gz`. Assumes nothing stacked on `param_gz`. Unstacks `param_gz`. 10579 fn addParam( 10580 gz: *GenZir, 10581 param_gz: *GenZir, 10582 tag: Zir.Inst.Tag, 10583 /// Absolute token index. This function does the conversion to Decl offset. 10584 abs_tok_index: Ast.TokenIndex, 10585 name: u32, 10586 first_doc_comment: ?Ast.TokenIndex, 10587 ) !Zir.Inst.Index { 10588 const gpa = gz.astgen.gpa; 10589 const param_body = param_gz.instructionsSlice(); 10590 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 10591 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Param).Struct.fields.len + 10592 param_body.len); 10593 10594 const doc_comment_index = if (first_doc_comment) |first| 10595 try gz.astgen.docCommentAsStringFromFirst(abs_tok_index, first) 10596 else 10597 0; 10598 10599 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Param{ 10600 .name = name, 10601 .doc_comment = doc_comment_index, 10602 .body_len = @intCast(u32, param_body.len), 10603 }); 10604 gz.astgen.extra.appendSliceAssumeCapacity(param_body); 10605 param_gz.unstack(); 10606 10607 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 10608 gz.astgen.instructions.appendAssumeCapacity(.{ 10609 .tag = tag, 10610 .data = .{ .pl_tok = .{ 10611 .src_tok = gz.tokenIndexToRelative(abs_tok_index), 10612 .payload_index = payload_index, 10613 } }, 10614 }); 10615 gz.instructions.appendAssumeCapacity(new_index); 10616 return new_index; 10617 } 10618 10619 fn addExtendedPayload( 10620 gz: *GenZir, 10621 opcode: Zir.Inst.Extended, 10622 extra: anytype, 10623 ) !Zir.Inst.Ref { 10624 const gpa = gz.astgen.gpa; 10625 10626 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10627 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 10628 10629 const payload_index = try gz.astgen.addExtra(extra); 10630 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 10631 gz.astgen.instructions.appendAssumeCapacity(.{ 10632 .tag = .extended, 10633 .data = .{ .extended = .{ 10634 .opcode = opcode, 10635 .small = undefined, 10636 .operand = payload_index, 10637 } }, 10638 }); 10639 gz.instructions.appendAssumeCapacity(new_index); 10640 return indexToRef(new_index); 10641 } 10642 10643 fn addExtendedMultiOp( 10644 gz: *GenZir, 10645 opcode: Zir.Inst.Extended, 10646 node: Ast.Node.Index, 10647 operands: []const Zir.Inst.Ref, 10648 ) !Zir.Inst.Ref { 10649 const astgen = gz.astgen; 10650 const gpa = astgen.gpa; 10651 10652 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10653 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 10654 try astgen.extra.ensureUnusedCapacity( 10655 gpa, 10656 @typeInfo(Zir.Inst.NodeMultiOp).Struct.fields.len + operands.len, 10657 ); 10658 10659 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.NodeMultiOp{ 10660 .src_node = gz.nodeIndexToRelative(node), 10661 }); 10662 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 10663 astgen.instructions.appendAssumeCapacity(.{ 10664 .tag = .extended, 10665 .data = .{ .extended = .{ 10666 .opcode = opcode, 10667 .small = @intCast(u16, operands.len), 10668 .operand = payload_index, 10669 } }, 10670 }); 10671 gz.instructions.appendAssumeCapacity(new_index); 10672 astgen.appendRefsAssumeCapacity(operands); 10673 return indexToRef(new_index); 10674 } 10675 10676 fn addExtendedMultiOpPayloadIndex( 10677 gz: *GenZir, 10678 opcode: Zir.Inst.Extended, 10679 payload_index: u32, 10680 trailing_len: usize, 10681 ) !Zir.Inst.Ref { 10682 const astgen = gz.astgen; 10683 const gpa = astgen.gpa; 10684 10685 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10686 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 10687 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 10688 astgen.instructions.appendAssumeCapacity(.{ 10689 .tag = .extended, 10690 .data = .{ .extended = .{ 10691 .opcode = opcode, 10692 .small = @intCast(u16, trailing_len), 10693 .operand = payload_index, 10694 } }, 10695 }); 10696 gz.instructions.appendAssumeCapacity(new_index); 10697 return indexToRef(new_index); 10698 } 10699 10700 fn addUnTok( 10701 gz: *GenZir, 10702 tag: Zir.Inst.Tag, 10703 operand: Zir.Inst.Ref, 10704 /// Absolute token index. This function does the conversion to Decl offset. 10705 abs_tok_index: Ast.TokenIndex, 10706 ) !Zir.Inst.Ref { 10707 assert(operand != .none); 10708 return gz.add(.{ 10709 .tag = tag, 10710 .data = .{ .un_tok = .{ 10711 .operand = operand, 10712 .src_tok = gz.tokenIndexToRelative(abs_tok_index), 10713 } }, 10714 }); 10715 } 10716 10717 fn makeUnTok( 10718 gz: *GenZir, 10719 tag: Zir.Inst.Tag, 10720 operand: Zir.Inst.Ref, 10721 /// Absolute token index. This function does the conversion to Decl offset. 10722 abs_tok_index: Ast.TokenIndex, 10723 ) !Zir.Inst.Index { 10724 const astgen = gz.astgen; 10725 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 10726 assert(operand != .none); 10727 try astgen.instructions.append(astgen.gpa, .{ 10728 .tag = tag, 10729 .data = .{ .un_tok = .{ 10730 .operand = operand, 10731 .src_tok = gz.tokenIndexToRelative(abs_tok_index), 10732 } }, 10733 }); 10734 return new_index; 10735 } 10736 10737 fn addStrTok( 10738 gz: *GenZir, 10739 tag: Zir.Inst.Tag, 10740 str_index: u32, 10741 /// Absolute token index. This function does the conversion to Decl offset. 10742 abs_tok_index: Ast.TokenIndex, 10743 ) !Zir.Inst.Ref { 10744 return gz.add(.{ 10745 .tag = tag, 10746 .data = .{ .str_tok = .{ 10747 .start = str_index, 10748 .src_tok = gz.tokenIndexToRelative(abs_tok_index), 10749 } }, 10750 }); 10751 } 10752 10753 fn addBreak( 10754 gz: *GenZir, 10755 tag: Zir.Inst.Tag, 10756 break_block: Zir.Inst.Index, 10757 operand: Zir.Inst.Ref, 10758 ) !Zir.Inst.Index { 10759 return gz.addAsIndex(.{ 10760 .tag = tag, 10761 .data = .{ .@"break" = .{ 10762 .block_inst = break_block, 10763 .operand = operand, 10764 } }, 10765 }); 10766 } 10767 10768 fn makeBreak( 10769 gz: *GenZir, 10770 tag: Zir.Inst.Tag, 10771 break_block: Zir.Inst.Index, 10772 operand: Zir.Inst.Ref, 10773 ) !Zir.Inst.Index { 10774 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 10775 try gz.astgen.instructions.append(gz.astgen.gpa, .{ 10776 .tag = tag, 10777 .data = .{ .@"break" = .{ 10778 .block_inst = break_block, 10779 .operand = operand, 10780 } }, 10781 }); 10782 return new_index; 10783 } 10784 10785 fn addBin( 10786 gz: *GenZir, 10787 tag: Zir.Inst.Tag, 10788 lhs: Zir.Inst.Ref, 10789 rhs: Zir.Inst.Ref, 10790 ) !Zir.Inst.Ref { 10791 assert(lhs != .none); 10792 assert(rhs != .none); 10793 return gz.add(.{ 10794 .tag = tag, 10795 .data = .{ .bin = .{ 10796 .lhs = lhs, 10797 .rhs = rhs, 10798 } }, 10799 }); 10800 } 10801 10802 fn addDecl( 10803 gz: *GenZir, 10804 tag: Zir.Inst.Tag, 10805 decl_index: u32, 10806 src_node: Ast.Node.Index, 10807 ) !Zir.Inst.Ref { 10808 return gz.add(.{ 10809 .tag = tag, 10810 .data = .{ .pl_node = .{ 10811 .src_node = gz.nodeIndexToRelative(src_node), 10812 .payload_index = decl_index, 10813 } }, 10814 }); 10815 } 10816 10817 fn addNode( 10818 gz: *GenZir, 10819 tag: Zir.Inst.Tag, 10820 /// Absolute node index. This function does the conversion to offset from Decl. 10821 src_node: Ast.Node.Index, 10822 ) !Zir.Inst.Ref { 10823 return gz.add(.{ 10824 .tag = tag, 10825 .data = .{ .node = gz.nodeIndexToRelative(src_node) }, 10826 }); 10827 } 10828 10829 fn addInstNode( 10830 gz: *GenZir, 10831 tag: Zir.Inst.Tag, 10832 inst: Zir.Inst.Index, 10833 /// Absolute node index. This function does the conversion to offset from Decl. 10834 src_node: Ast.Node.Index, 10835 ) !Zir.Inst.Ref { 10836 return gz.add(.{ 10837 .tag = tag, 10838 .data = .{ .inst_node = .{ 10839 .inst = inst, 10840 .src_node = gz.nodeIndexToRelative(src_node), 10841 } }, 10842 }); 10843 } 10844 10845 fn addNodeExtended( 10846 gz: *GenZir, 10847 opcode: Zir.Inst.Extended, 10848 /// Absolute node index. This function does the conversion to offset from Decl. 10849 src_node: Ast.Node.Index, 10850 ) !Zir.Inst.Ref { 10851 return gz.add(.{ 10852 .tag = .extended, 10853 .data = .{ .extended = .{ 10854 .opcode = opcode, 10855 .small = undefined, 10856 .operand = @bitCast(u32, gz.nodeIndexToRelative(src_node)), 10857 } }, 10858 }); 10859 } 10860 10861 fn addAllocExtended( 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 type_inst: Zir.Inst.Ref, 10867 align_inst: Zir.Inst.Ref, 10868 is_const: bool, 10869 is_comptime: bool, 10870 }, 10871 ) !Zir.Inst.Ref { 10872 const astgen = gz.astgen; 10873 const gpa = astgen.gpa; 10874 10875 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10876 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 10877 try astgen.extra.ensureUnusedCapacity( 10878 gpa, 10879 @typeInfo(Zir.Inst.AllocExtended).Struct.fields.len + 10880 @as(usize, @boolToInt(args.type_inst != .none)) + 10881 @as(usize, @boolToInt(args.align_inst != .none)), 10882 ); 10883 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.AllocExtended{ 10884 .src_node = gz.nodeIndexToRelative(args.node), 10885 }); 10886 if (args.type_inst != .none) { 10887 astgen.extra.appendAssumeCapacity(@enumToInt(args.type_inst)); 10888 } 10889 if (args.align_inst != .none) { 10890 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); 10891 } 10892 10893 const has_type: u4 = @boolToInt(args.type_inst != .none); 10894 const has_align: u4 = @boolToInt(args.align_inst != .none); 10895 const is_const: u4 = @boolToInt(args.is_const); 10896 const is_comptime: u4 = @boolToInt(args.is_comptime); 10897 const small: u16 = has_type | (has_align << 1) | (is_const << 2) | (is_comptime << 3); 10898 10899 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 10900 astgen.instructions.appendAssumeCapacity(.{ 10901 .tag = .extended, 10902 .data = .{ .extended = .{ 10903 .opcode = .alloc, 10904 .small = small, 10905 .operand = payload_index, 10906 } }, 10907 }); 10908 gz.instructions.appendAssumeCapacity(new_index); 10909 return indexToRef(new_index); 10910 } 10911 10912 fn addAsm( 10913 gz: *GenZir, 10914 args: struct { 10915 /// Absolute node index. This function does the conversion to offset from Decl. 10916 node: Ast.Node.Index, 10917 asm_source: u32, 10918 output_type_bits: u32, 10919 is_volatile: bool, 10920 outputs: []const Zir.Inst.Asm.Output, 10921 inputs: []const Zir.Inst.Asm.Input, 10922 clobbers: []const u32, 10923 }, 10924 ) !Zir.Inst.Ref { 10925 const astgen = gz.astgen; 10926 const gpa = astgen.gpa; 10927 10928 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10929 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 10930 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Asm).Struct.fields.len + 10931 args.outputs.len * @typeInfo(Zir.Inst.Asm.Output).Struct.fields.len + 10932 args.inputs.len * @typeInfo(Zir.Inst.Asm.Input).Struct.fields.len + 10933 args.clobbers.len); 10934 10935 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Asm{ 10936 .src_node = gz.nodeIndexToRelative(args.node), 10937 .asm_source = args.asm_source, 10938 .output_type_bits = args.output_type_bits, 10939 }); 10940 for (args.outputs) |output| { 10941 _ = gz.astgen.addExtraAssumeCapacity(output); 10942 } 10943 for (args.inputs) |input| { 10944 _ = gz.astgen.addExtraAssumeCapacity(input); 10945 } 10946 gz.astgen.extra.appendSliceAssumeCapacity(args.clobbers); 10947 10948 // * 0b00000000_000XXXXX - `outputs_len`. 10949 // * 0b000000XX_XXX00000 - `inputs_len`. 10950 // * 0b0XXXXX00_00000000 - `clobbers_len`. 10951 // * 0bX0000000_00000000 - is volatile 10952 const small: u16 = @intCast(u16, args.outputs.len) | 10953 @intCast(u16, args.inputs.len << 5) | 10954 @intCast(u16, args.clobbers.len << 10) | 10955 (@as(u16, @boolToInt(args.is_volatile)) << 15); 10956 10957 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 10958 astgen.instructions.appendAssumeCapacity(.{ 10959 .tag = .extended, 10960 .data = .{ .extended = .{ 10961 .opcode = .@"asm", 10962 .small = small, 10963 .operand = payload_index, 10964 } }, 10965 }); 10966 gz.instructions.appendAssumeCapacity(new_index); 10967 return indexToRef(new_index); 10968 } 10969 10970 /// Note that this returns a `Zir.Inst.Index` not a ref. 10971 /// Does *not* append the block instruction to the scope. 10972 /// Leaves the `payload_index` field undefined. 10973 fn makeBlockInst(gz: *GenZir, tag: Zir.Inst.Tag, node: Ast.Node.Index) !Zir.Inst.Index { 10974 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 10975 const gpa = gz.astgen.gpa; 10976 try gz.astgen.instructions.append(gpa, .{ 10977 .tag = tag, 10978 .data = .{ .pl_node = .{ 10979 .src_node = gz.nodeIndexToRelative(node), 10980 .payload_index = undefined, 10981 } }, 10982 }); 10983 return new_index; 10984 } 10985 10986 /// Note that this returns a `Zir.Inst.Index` not a ref. 10987 /// Leaves the `payload_index` field undefined. 10988 fn addCondBr(gz: *GenZir, tag: Zir.Inst.Tag, node: Ast.Node.Index) !Zir.Inst.Index { 10989 const gpa = gz.astgen.gpa; 10990 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10991 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 10992 try gz.astgen.instructions.append(gpa, .{ 10993 .tag = tag, 10994 .data = .{ .pl_node = .{ 10995 .src_node = gz.nodeIndexToRelative(node), 10996 .payload_index = undefined, 10997 } }, 10998 }); 10999 gz.instructions.appendAssumeCapacity(new_index); 11000 return new_index; 11001 } 11002 11003 fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct { 11004 src_node: Ast.Node.Index, 11005 fields_len: u32, 11006 decls_len: u32, 11007 layout: std.builtin.Type.ContainerLayout, 11008 known_non_opv: bool, 11009 known_comptime_only: bool, 11010 }) !void { 11011 const astgen = gz.astgen; 11012 const gpa = astgen.gpa; 11013 11014 try astgen.extra.ensureUnusedCapacity(gpa, 4); 11015 const payload_index = @intCast(u32, astgen.extra.items.len); 11016 11017 if (args.src_node != 0) { 11018 const node_offset = gz.nodeIndexToRelative(args.src_node); 11019 astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset)); 11020 } 11021 if (args.fields_len != 0) { 11022 astgen.extra.appendAssumeCapacity(args.fields_len); 11023 } 11024 if (args.decls_len != 0) { 11025 astgen.extra.appendAssumeCapacity(args.decls_len); 11026 } 11027 astgen.instructions.set(inst, .{ 11028 .tag = .extended, 11029 .data = .{ .extended = .{ 11030 .opcode = .struct_decl, 11031 .small = @bitCast(u16, Zir.Inst.StructDecl.Small{ 11032 .has_src_node = args.src_node != 0, 11033 .has_fields_len = args.fields_len != 0, 11034 .has_decls_len = args.decls_len != 0, 11035 .known_non_opv = args.known_non_opv, 11036 .known_comptime_only = args.known_comptime_only, 11037 .name_strategy = gz.anon_name_strategy, 11038 .layout = args.layout, 11039 }), 11040 .operand = payload_index, 11041 } }, 11042 }); 11043 } 11044 11045 fn setUnion(gz: *GenZir, inst: Zir.Inst.Index, args: struct { 11046 src_node: Ast.Node.Index, 11047 tag_type: Zir.Inst.Ref, 11048 body_len: u32, 11049 fields_len: u32, 11050 decls_len: u32, 11051 layout: std.builtin.Type.ContainerLayout, 11052 auto_enum_tag: bool, 11053 }) !void { 11054 const astgen = gz.astgen; 11055 const gpa = astgen.gpa; 11056 11057 try astgen.extra.ensureUnusedCapacity(gpa, 5); 11058 const payload_index = @intCast(u32, astgen.extra.items.len); 11059 11060 if (args.src_node != 0) { 11061 const node_offset = gz.nodeIndexToRelative(args.src_node); 11062 astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset)); 11063 } 11064 if (args.tag_type != .none) { 11065 astgen.extra.appendAssumeCapacity(@enumToInt(args.tag_type)); 11066 } 11067 if (args.body_len != 0) { 11068 astgen.extra.appendAssumeCapacity(args.body_len); 11069 } 11070 if (args.fields_len != 0) { 11071 astgen.extra.appendAssumeCapacity(args.fields_len); 11072 } 11073 if (args.decls_len != 0) { 11074 astgen.extra.appendAssumeCapacity(args.decls_len); 11075 } 11076 astgen.instructions.set(inst, .{ 11077 .tag = .extended, 11078 .data = .{ .extended = .{ 11079 .opcode = .union_decl, 11080 .small = @bitCast(u16, Zir.Inst.UnionDecl.Small{ 11081 .has_src_node = args.src_node != 0, 11082 .has_tag_type = args.tag_type != .none, 11083 .has_body_len = args.body_len != 0, 11084 .has_fields_len = args.fields_len != 0, 11085 .has_decls_len = args.decls_len != 0, 11086 .name_strategy = gz.anon_name_strategy, 11087 .layout = args.layout, 11088 .auto_enum_tag = args.auto_enum_tag, 11089 }), 11090 .operand = payload_index, 11091 } }, 11092 }); 11093 } 11094 11095 fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct { 11096 src_node: Ast.Node.Index, 11097 tag_type: Zir.Inst.Ref, 11098 body_len: u32, 11099 fields_len: u32, 11100 decls_len: u32, 11101 nonexhaustive: bool, 11102 }) !void { 11103 const astgen = gz.astgen; 11104 const gpa = astgen.gpa; 11105 11106 try astgen.extra.ensureUnusedCapacity(gpa, 5); 11107 const payload_index = @intCast(u32, astgen.extra.items.len); 11108 11109 if (args.src_node != 0) { 11110 const node_offset = gz.nodeIndexToRelative(args.src_node); 11111 astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset)); 11112 } 11113 if (args.tag_type != .none) { 11114 astgen.extra.appendAssumeCapacity(@enumToInt(args.tag_type)); 11115 } 11116 if (args.body_len != 0) { 11117 astgen.extra.appendAssumeCapacity(args.body_len); 11118 } 11119 if (args.fields_len != 0) { 11120 astgen.extra.appendAssumeCapacity(args.fields_len); 11121 } 11122 if (args.decls_len != 0) { 11123 astgen.extra.appendAssumeCapacity(args.decls_len); 11124 } 11125 astgen.instructions.set(inst, .{ 11126 .tag = .extended, 11127 .data = .{ .extended = .{ 11128 .opcode = .enum_decl, 11129 .small = @bitCast(u16, Zir.Inst.EnumDecl.Small{ 11130 .has_src_node = args.src_node != 0, 11131 .has_tag_type = args.tag_type != .none, 11132 .has_body_len = args.body_len != 0, 11133 .has_fields_len = args.fields_len != 0, 11134 .has_decls_len = args.decls_len != 0, 11135 .name_strategy = gz.anon_name_strategy, 11136 .nonexhaustive = args.nonexhaustive, 11137 }), 11138 .operand = payload_index, 11139 } }, 11140 }); 11141 } 11142 11143 fn setOpaque(gz: *GenZir, inst: Zir.Inst.Index, args: struct { 11144 src_node: Ast.Node.Index, 11145 decls_len: u32, 11146 }) !void { 11147 const astgen = gz.astgen; 11148 const gpa = astgen.gpa; 11149 11150 try astgen.extra.ensureUnusedCapacity(gpa, 2); 11151 const payload_index = @intCast(u32, astgen.extra.items.len); 11152 11153 if (args.src_node != 0) { 11154 const node_offset = gz.nodeIndexToRelative(args.src_node); 11155 astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset)); 11156 } 11157 if (args.decls_len != 0) { 11158 astgen.extra.appendAssumeCapacity(args.decls_len); 11159 } 11160 astgen.instructions.set(inst, .{ 11161 .tag = .extended, 11162 .data = .{ .extended = .{ 11163 .opcode = .opaque_decl, 11164 .small = @bitCast(u16, Zir.Inst.OpaqueDecl.Small{ 11165 .has_src_node = args.src_node != 0, 11166 .has_decls_len = args.decls_len != 0, 11167 .name_strategy = gz.anon_name_strategy, 11168 }), 11169 .operand = payload_index, 11170 } }, 11171 }); 11172 } 11173 11174 fn add(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Ref { 11175 return indexToRef(try gz.addAsIndex(inst)); 11176 } 11177 11178 fn addAsIndex(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Index { 11179 const gpa = gz.astgen.gpa; 11180 try gz.instructions.ensureUnusedCapacity(gpa, 1); 11181 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 11182 11183 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 11184 gz.astgen.instructions.appendAssumeCapacity(inst); 11185 gz.instructions.appendAssumeCapacity(new_index); 11186 return new_index; 11187 } 11188 11189 fn reserveInstructionIndex(gz: *GenZir) !Zir.Inst.Index { 11190 const gpa = gz.astgen.gpa; 11191 try gz.instructions.ensureUnusedCapacity(gpa, 1); 11192 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 11193 11194 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 11195 gz.astgen.instructions.len += 1; 11196 gz.instructions.appendAssumeCapacity(new_index); 11197 return new_index; 11198 } 11199 11200 fn addRet(gz: *GenZir, rl: ResultLoc, operand: Zir.Inst.Ref, node: Ast.Node.Index) !void { 11201 switch (rl) { 11202 .ptr => |ret_ptr| _ = try gz.addUnNode(.ret_load, ret_ptr, node), 11203 .ty => _ = try gz.addUnNode(.ret_node, operand, node), 11204 else => unreachable, 11205 } 11206 } 11207 11208 fn addNamespaceCaptures(gz: *GenZir, namespace: *Scope.Namespace) !void { 11209 if (namespace.captures.count() > 0) { 11210 try gz.instructions.ensureUnusedCapacity(gz.astgen.gpa, namespace.captures.count()); 11211 for (namespace.captures.values()) |capture| { 11212 gz.instructions.appendAssumeCapacity(capture); 11213 } 11214 } 11215 } 11216 11217 fn addDbgVar(gz: *GenZir, tag: Zir.Inst.Tag, name: u32, inst: Zir.Inst.Ref) !void { 11218 if (gz.force_comptime) return; 11219 11220 _ = try gz.add(.{ .tag = tag, .data = .{ 11221 .str_op = .{ 11222 .str = name, 11223 .operand = inst, 11224 }, 11225 } }); 11226 } 11227 11228 fn addDbgBlockBegin(gz: *GenZir) !void { 11229 if (gz.force_comptime) return; 11230 11231 _ = try gz.add(.{ .tag = .dbg_block_begin, .data = undefined }); 11232 } 11233 11234 fn addDbgBlockEnd(gz: *GenZir) !void { 11235 if (gz.force_comptime) return; 11236 const gpa = gz.astgen.gpa; 11237 11238 const tags = gz.astgen.instructions.items(.tag); 11239 const last_inst = gz.instructions.items[gz.instructions.items.len - 1]; 11240 // remove dbg_block_begin immediately followed by dbg_block_end 11241 if (tags[last_inst] == .dbg_block_begin) { 11242 _ = gz.instructions.pop(); 11243 return; 11244 } 11245 11246 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 11247 try gz.astgen.instructions.append(gpa, .{ .tag = .dbg_block_end, .data = undefined }); 11248 try gz.instructions.insert(gpa, gz.instructions.items.len - 1, new_index); 11249 } 11250 11251 /// Control flow does not fall through the "then" block of a loop; it continues 11252 /// back to the while condition. This prevents `rvalue` from 11253 /// adding an invalid store to the result location of `then_scope`. 11254 fn markAsLoopBody(gz: *GenZir, loop_scope: GenZir) void { 11255 gz.rvalue_noresult = switch (loop_scope.break_result_loc) { 11256 .ptr, .inferred_ptr => |ptr| ptr, 11257 .block_ptr => |block| block.rl_ptr, 11258 else => .none, 11259 }; 11260 } 11261 }; 11262 11263 /// This can only be for short-lived references; the memory becomes invalidated 11264 /// when another string is added. 11265 fn nullTerminatedString(astgen: AstGen, index: usize) [*:0]const u8 { 11266 return @ptrCast([*:0]const u8, astgen.string_bytes.items.ptr) + index; 11267 } 11268 11269 pub fn isPrimitive(name: []const u8) bool { 11270 if (primitives.get(name) != null) return true; 11271 if (name.len < 2) return false; 11272 const first_c = name[0]; 11273 if (first_c != 'i' and first_c != 'u') return false; 11274 if (parseBitCount(name[1..])) |_| { 11275 return true; 11276 } else |err| switch (err) { 11277 error.Overflow => return true, 11278 error.InvalidCharacter => return false, 11279 } 11280 } 11281 11282 /// Local variables shadowing detection, including function parameters. 11283 fn detectLocalShadowing( 11284 astgen: *AstGen, 11285 scope: *Scope, 11286 ident_name: u32, 11287 name_token: Ast.TokenIndex, 11288 token_bytes: []const u8, 11289 ) !void { 11290 const gpa = astgen.gpa; 11291 if (token_bytes[0] != '@' and isPrimitive(token_bytes)) { 11292 return astgen.failTokNotes(name_token, "name shadows primitive '{s}'", .{ 11293 token_bytes, 11294 }, &[_]u32{ 11295 try astgen.errNoteTok(name_token, "consider using @\"{s}\" to disambiguate", .{ 11296 token_bytes, 11297 }), 11298 }); 11299 } 11300 11301 var s = scope; 11302 while (true) switch (s.tag) { 11303 .local_val => { 11304 const local_val = s.cast(Scope.LocalVal).?; 11305 if (local_val.name == ident_name) { 11306 const name_slice = mem.span(astgen.nullTerminatedString(ident_name)); 11307 const name = try gpa.dupe(u8, name_slice); 11308 defer gpa.free(name); 11309 return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{ 11310 @tagName(local_val.id_cat), name, 11311 }, &[_]u32{ 11312 try astgen.errNoteTok( 11313 local_val.token_src, 11314 "previous declaration here", 11315 .{}, 11316 ), 11317 }); 11318 } 11319 s = local_val.parent; 11320 }, 11321 .local_ptr => { 11322 const local_ptr = s.cast(Scope.LocalPtr).?; 11323 if (local_ptr.name == ident_name) { 11324 const name_slice = mem.span(astgen.nullTerminatedString(ident_name)); 11325 const name = try gpa.dupe(u8, name_slice); 11326 defer gpa.free(name); 11327 return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{ 11328 @tagName(local_ptr.id_cat), name, 11329 }, &[_]u32{ 11330 try astgen.errNoteTok( 11331 local_ptr.token_src, 11332 "previous declaration here", 11333 .{}, 11334 ), 11335 }); 11336 } 11337 s = local_ptr.parent; 11338 }, 11339 .namespace => { 11340 const ns = s.cast(Scope.Namespace).?; 11341 const decl_node = ns.decls.get(ident_name) orelse { 11342 s = ns.parent; 11343 continue; 11344 }; 11345 const name_slice = mem.span(astgen.nullTerminatedString(ident_name)); 11346 const name = try gpa.dupe(u8, name_slice); 11347 defer gpa.free(name); 11348 return astgen.failTokNotes(name_token, "local shadows declaration of '{s}'", .{ 11349 name, 11350 }, &[_]u32{ 11351 try astgen.errNoteNode(decl_node, "declared here", .{}), 11352 }); 11353 }, 11354 .gen_zir => s = s.cast(GenZir).?.parent, 11355 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, 11356 .top => break, 11357 }; 11358 } 11359 11360 /// Advances the source cursor to the beginning of `node`. 11361 fn advanceSourceCursorToNode(astgen: *AstGen, node: Ast.Node.Index) void { 11362 const tree = astgen.tree; 11363 const token_starts = tree.tokens.items(.start); 11364 const node_start = token_starts[tree.firstToken(node)]; 11365 astgen.advanceSourceCursor(node_start); 11366 } 11367 11368 /// Advances the source cursor to an absolute byte offset `end` in the file. 11369 fn advanceSourceCursor(astgen: *AstGen, end: usize) void { 11370 const source = astgen.tree.source; 11371 var i = astgen.source_offset; 11372 var line = astgen.source_line; 11373 var column = astgen.source_column; 11374 assert(i <= end); 11375 while (i < end) : (i += 1) { 11376 if (source[i] == '\n') { 11377 line += 1; 11378 column = 0; 11379 } else { 11380 column += 1; 11381 } 11382 } 11383 astgen.source_offset = i; 11384 astgen.source_line = line; 11385 astgen.source_column = column; 11386 } 11387 11388 fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.Node.Index) !u32 { 11389 const gpa = astgen.gpa; 11390 const tree = astgen.tree; 11391 const node_tags = tree.nodes.items(.tag); 11392 const main_tokens = tree.nodes.items(.main_token); 11393 const token_tags = tree.tokens.items(.tag); 11394 var decl_count: u32 = 0; 11395 for (members) |member_node| { 11396 const name_token = switch (node_tags[member_node]) { 11397 .fn_proto_simple, 11398 .fn_proto_multi, 11399 .fn_proto_one, 11400 .fn_proto, 11401 .global_var_decl, 11402 .local_var_decl, 11403 .simple_var_decl, 11404 .aligned_var_decl, 11405 => blk: { 11406 decl_count += 1; 11407 break :blk main_tokens[member_node] + 1; 11408 }, 11409 11410 .fn_decl => blk: { 11411 decl_count += 1; 11412 const ident = main_tokens[member_node] + 1; 11413 if (token_tags[ident] != .identifier) { 11414 switch (astgen.failNode(member_node, "missing function name", .{})) { 11415 error.AnalysisFail => continue, 11416 error.OutOfMemory => return error.OutOfMemory, 11417 } 11418 } 11419 break :blk ident; 11420 }, 11421 11422 .@"comptime", .@"usingnamespace", .test_decl => { 11423 decl_count += 1; 11424 continue; 11425 }, 11426 11427 else => continue, 11428 }; 11429 11430 const token_bytes = astgen.tree.tokenSlice(name_token); 11431 if (token_bytes[0] != '@' and isPrimitive(token_bytes)) { 11432 switch (astgen.failTokNotes(name_token, "name shadows primitive '{s}'", .{ 11433 token_bytes, 11434 }, &[_]u32{ 11435 try astgen.errNoteTok(name_token, "consider using @\"{s}\" to disambiguate", .{ 11436 token_bytes, 11437 }), 11438 })) { 11439 error.AnalysisFail => continue, 11440 error.OutOfMemory => return error.OutOfMemory, 11441 } 11442 } 11443 11444 const name_str_index = try astgen.identAsString(name_token); 11445 const gop = try namespace.decls.getOrPut(gpa, name_str_index); 11446 if (gop.found_existing) { 11447 const name = try gpa.dupe(u8, mem.span(astgen.nullTerminatedString(name_str_index))); 11448 defer gpa.free(name); 11449 switch (astgen.failNodeNotes(member_node, "redeclaration of '{s}'", .{ 11450 name, 11451 }, &[_]u32{ 11452 try astgen.errNoteNode(gop.value_ptr.*, "other declaration here", .{}), 11453 })) { 11454 error.AnalysisFail => continue, 11455 error.OutOfMemory => return error.OutOfMemory, 11456 } 11457 } 11458 gop.value_ptr.* = member_node; 11459 } 11460 return decl_count; 11461 } 11462 11463 fn isInferred(astgen: *AstGen, ref: Zir.Inst.Ref) bool { 11464 const inst = refToIndex(ref) orelse return false; 11465 const zir_tags = astgen.instructions.items(.tag); 11466 return switch (zir_tags[inst]) { 11467 .alloc_inferred, 11468 .alloc_inferred_mut, 11469 .alloc_inferred_comptime, 11470 .alloc_inferred_comptime_mut, 11471 => true, 11472 11473 else => false, 11474 }; 11475 } 11476 11477 /// Assumes capacity for body has already been added. Needed capacity taking into 11478 /// account fixups can be found with `countBodyLenAfterFixups`. 11479 fn appendBodyWithFixups(astgen: *AstGen, body: []const Zir.Inst.Index) void { 11480 return appendBodyWithFixupsArrayList(astgen, &astgen.extra, body); 11481 } 11482 11483 fn appendBodyWithFixupsArrayList( 11484 astgen: *AstGen, 11485 list: *std.ArrayListUnmanaged(u32), 11486 body: []const Zir.Inst.Index, 11487 ) void { 11488 for (body) |body_inst| { 11489 appendPossiblyRefdBodyInst(astgen, list, body_inst); 11490 } 11491 } 11492 11493 fn appendPossiblyRefdBodyInst( 11494 astgen: *AstGen, 11495 list: *std.ArrayListUnmanaged(u32), 11496 body_inst: Zir.Inst.Index, 11497 ) void { 11498 list.appendAssumeCapacity(body_inst); 11499 const kv = astgen.ref_table.fetchRemove(body_inst) orelse return; 11500 const ref_inst = kv.value; 11501 return appendPossiblyRefdBodyInst(astgen, list, ref_inst); 11502 } 11503 11504 fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 { 11505 var count = body.len; 11506 for (body) |body_inst| { 11507 var check_inst = body_inst; 11508 while (astgen.ref_table.get(check_inst)) |ref_inst| { 11509 count += 1; 11510 check_inst = ref_inst; 11511 } 11512 } 11513 return @intCast(u32, count); 11514 }