blob a5e61fa4 (279887B) - Raw
1 //! Compilation of all Zig source code is represented by one `Module`. 2 //! Each `Compilation` has exactly one or zero `Module`, depending on whether 3 //! there is or is not any zig source code, respectively. 4 5 const std = @import("std"); 6 const builtin = @import("builtin"); 7 const mem = std.mem; 8 const Allocator = std.mem.Allocator; 9 const ArrayListUnmanaged = std.ArrayListUnmanaged; 10 const assert = std.debug.assert; 11 const log = std.log.scoped(.module); 12 const BigIntConst = std.math.big.int.Const; 13 const BigIntMutable = std.math.big.int.Mutable; 14 const Target = std.Target; 15 const Ast = std.zig.Ast; 16 17 const Module = @This(); 18 const Compilation = @import("Compilation.zig"); 19 const Cache = std.Build.Cache; 20 const Value = @import("value.zig").Value; 21 const Type = @import("type.zig").Type; 22 const TypedValue = @import("TypedValue.zig"); 23 const Package = @import("Package.zig"); 24 const link = @import("link.zig"); 25 const Air = @import("Air.zig"); 26 const Zir = @import("Zir.zig"); 27 const trace = @import("tracy.zig").trace; 28 const AstGen = @import("AstGen.zig"); 29 const Sema = @import("Sema.zig"); 30 const target_util = @import("target.zig"); 31 const build_options = @import("build_options"); 32 const Liveness = @import("Liveness.zig"); 33 const isUpDir = @import("introspect.zig").isUpDir; 34 const clang = @import("clang.zig"); 35 const InternPool = @import("InternPool.zig"); 36 37 comptime { 38 @setEvalBranchQuota(4000); 39 for ( 40 @typeInfo(Zir.Inst.Ref).Enum.fields, 41 @typeInfo(Air.Inst.Ref).Enum.fields, 42 @typeInfo(InternPool.Index).Enum.fields, 43 ) |zir_field, air_field, ip_field| { 44 assert(mem.eql(u8, zir_field.name, ip_field.name)); 45 assert(mem.eql(u8, air_field.name, ip_field.name)); 46 } 47 } 48 49 /// General-purpose allocator. Used for both temporary and long-term storage. 50 gpa: Allocator, 51 comp: *Compilation, 52 53 /// Where build artifacts and incremental compilation metadata serialization go. 54 zig_cache_artifact_directory: Compilation.Directory, 55 /// Pointer to externally managed resource. 56 root_pkg: *Package, 57 /// Normally, `main_pkg` and `root_pkg` are the same. The exception is `zig test`, in which 58 /// `root_pkg` is the test runner, and `main_pkg` is the user's source file which has the tests. 59 main_pkg: *Package, 60 sema_prog_node: std.Progress.Node = undefined, 61 62 /// Used by AstGen worker to load and store ZIR cache. 63 global_zir_cache: Compilation.Directory, 64 /// Used by AstGen worker to load and store ZIR cache. 65 local_zir_cache: Compilation.Directory, 66 /// It's rare for a decl to be exported, so we save memory by having a sparse 67 /// map of Decl indexes to details about them being exported. 68 /// The Export memory is owned by the `export_owners` table; the slice itself 69 /// is owned by this table. The slice is guaranteed to not be empty. 70 decl_exports: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(*Export)) = .{}, 71 /// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl 72 /// is modified. Note that the key of this table is not the Decl being exported, but the Decl that 73 /// is performing the export of another Decl. 74 /// This table owns the Export memory. 75 export_owners: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(*Export)) = .{}, 76 /// The set of all the Zig source files in the Module. We keep track of this in order 77 /// to iterate over it and check which source files have been modified on the file system when 78 /// an update is requested, as well as to cache `@import` results. 79 /// Keys are fully resolved file paths. This table owns the keys and values. 80 import_table: std.StringArrayHashMapUnmanaged(*File) = .{}, 81 /// The set of all the files which have been loaded with `@embedFile` in the Module. 82 /// We keep track of this in order to iterate over it and check which files have been 83 /// modified on the file system when an update is requested, as well as to cache 84 /// `@embedFile` results. 85 /// Keys are fully resolved file paths. This table owns the keys and values. 86 embed_table: std.StringHashMapUnmanaged(*EmbedFile) = .{}, 87 88 /// This is a temporary addition to stage2 in order to match legacy behavior, 89 /// however the end-game once the lang spec is settled will be to use a global 90 /// InternPool for comptime memoized objects, making this behavior consistent across all types, 91 /// not only string literals. Or, we might decide to not guarantee string literals 92 /// to have equal comptime pointers, in which case this field can be deleted (perhaps 93 /// the commit that introduced it can simply be reverted). 94 /// This table uses an optional index so that when a Decl is destroyed, the string literal 95 /// is still reclaimable by a future Decl. 96 string_literal_table: std.HashMapUnmanaged(StringLiteralContext.Key, Decl.OptionalIndex, StringLiteralContext, std.hash_map.default_max_load_percentage) = .{}, 97 string_literal_bytes: ArrayListUnmanaged(u8) = .{}, 98 99 /// Stores all Type and Value objects; periodically garbage collected. 100 intern_pool: InternPool = .{}, 101 /// Temporarily used for some unfortunate allocations made by backends that need to construct 102 /// pointer types that can't be represented by the InternPool. Once all types are migrated 103 /// to be stored in the InternPool, this can be removed. 104 tmp_hack_arena: std.heap.ArenaAllocator, 105 106 /// The set of all the generic function instantiations. This is used so that when a generic 107 /// function is called twice with the same comptime parameter arguments, both calls dispatch 108 /// to the same function. 109 monomorphed_funcs: MonomorphedFuncsSet = .{}, 110 /// The set of all comptime function calls that have been cached so that future calls 111 /// with the same parameters will get the same return value. 112 memoized_calls: MemoizedCallSet = .{}, 113 /// Contains the values from `@setAlignStack`. A sparse table is used here 114 /// instead of a field of `Fn` because usage of `@setAlignStack` is rare, while 115 /// functions are many. 116 align_stack_fns: std.AutoHashMapUnmanaged(*const Fn, SetAlignStack) = .{}, 117 118 /// We optimize memory usage for a compilation with no compile errors by storing the 119 /// error messages and mapping outside of `Decl`. 120 /// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator. 121 /// Note that a Decl can succeed but the Fn it represents can fail. In this case, 122 /// a Decl can have a failed_decls entry but have analysis status of success. 123 failed_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, *ErrorMsg) = .{}, 124 /// Keep track of one `@compileLog` callsite per owner Decl. 125 /// The value is the AST node index offset from the Decl. 126 compile_log_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, i32) = .{}, 127 /// Using a map here for consistency with the other fields here. 128 /// The ErrorMsg memory is owned by the `File`, using Module's general purpose allocator. 129 failed_files: std.AutoArrayHashMapUnmanaged(*File, ?*ErrorMsg) = .{}, 130 /// The ErrorMsg memory is owned by the `EmbedFile`, using Module's general purpose allocator. 131 failed_embed_files: std.AutoArrayHashMapUnmanaged(*EmbedFile, *ErrorMsg) = .{}, 132 /// Using a map here for consistency with the other fields here. 133 /// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator. 134 failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{}, 135 /// If a decl failed due to a cimport error, the corresponding Clang errors 136 /// are stored here. 137 cimport_errors: std.AutoArrayHashMapUnmanaged(Decl.Index, []CImportError) = .{}, 138 139 /// Candidates for deletion. After a semantic analysis update completes, this list 140 /// contains Decls that need to be deleted if they end up having no references to them. 141 deletion_set: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{}, 142 143 /// Error tags and their values, tag names are duped with mod.gpa. 144 /// Corresponds with `error_name_list`. 145 global_error_set: std.StringHashMapUnmanaged(ErrorInt) = .{}, 146 147 /// ErrorInt -> []const u8 for fast lookups for @intToError at comptime 148 /// Corresponds with `global_error_set`. 149 error_name_list: ArrayListUnmanaged([]const u8), 150 151 /// Incrementing integer used to compare against the corresponding Decl 152 /// field to determine whether a Decl's status applies to an ongoing update, or a 153 /// previous analysis. 154 generation: u32 = 0, 155 156 stage1_flags: packed struct { 157 have_winmain: bool = false, 158 have_wwinmain: bool = false, 159 have_winmain_crt_startup: bool = false, 160 have_wwinmain_crt_startup: bool = false, 161 have_dllmain_crt_startup: bool = false, 162 have_c_main: bool = false, 163 reserved: u2 = 0, 164 } = .{}, 165 166 job_queued_update_builtin_zig: bool = true, 167 168 compile_log_text: ArrayListUnmanaged(u8) = .{}, 169 170 emit_h: ?*GlobalEmitH, 171 172 test_functions: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{}, 173 174 /// Rather than allocating Decl objects with an Allocator, we instead allocate 175 /// them with this SegmentedList. This provides four advantages: 176 /// * Stable memory so that one thread can access a Decl object while another 177 /// thread allocates additional Decl objects from this list. 178 /// * It allows us to use u32 indexes to reference Decl objects rather than 179 /// pointers, saving memory in Type, Value, and dependency sets. 180 /// * Using integers to reference Decl objects rather than pointers makes 181 /// serialization trivial. 182 /// * It provides a unique integer to be used for anonymous symbol names, avoiding 183 /// multi-threaded contention on an atomic counter. 184 allocated_decls: std.SegmentedList(Decl, 0) = .{}, 185 /// When a Decl object is freed from `allocated_decls`, it is pushed into this stack. 186 decls_free_list: ArrayListUnmanaged(Decl.Index) = .{}, 187 188 global_assembly: std.AutoHashMapUnmanaged(Decl.Index, []u8) = .{}, 189 190 reference_table: std.AutoHashMapUnmanaged(Decl.Index, struct { 191 referencer: Decl.Index, 192 src: LazySrcLoc, 193 }) = .{}, 194 195 pub const CImportError = struct { 196 offset: u32, 197 line: u32, 198 column: u32, 199 path: ?[*:0]u8, 200 source_line: ?[*:0]u8, 201 msg: [*:0]u8, 202 203 pub fn deinit(err: CImportError, gpa: Allocator) void { 204 if (err.path) |some| gpa.free(std.mem.span(some)); 205 if (err.source_line) |some| gpa.free(std.mem.span(some)); 206 gpa.free(std.mem.span(err.msg)); 207 } 208 }; 209 210 pub const StringLiteralContext = struct { 211 bytes: *ArrayListUnmanaged(u8), 212 213 pub const Key = struct { 214 index: u32, 215 len: u32, 216 }; 217 218 pub fn eql(self: @This(), a: Key, b: Key) bool { 219 _ = self; 220 return a.index == b.index and a.len == b.len; 221 } 222 223 pub fn hash(self: @This(), x: Key) u64 { 224 const x_slice = self.bytes.items[x.index..][0..x.len]; 225 return std.hash_map.hashString(x_slice); 226 } 227 }; 228 229 pub const StringLiteralAdapter = struct { 230 bytes: *ArrayListUnmanaged(u8), 231 232 pub fn eql(self: @This(), a_slice: []const u8, b: StringLiteralContext.Key) bool { 233 const b_slice = self.bytes.items[b.index..][0..b.len]; 234 return mem.eql(u8, a_slice, b_slice); 235 } 236 237 pub fn hash(self: @This(), adapted_key: []const u8) u64 { 238 _ = self; 239 return std.hash_map.hashString(adapted_key); 240 } 241 }; 242 243 const MonomorphedFuncsSet = std.HashMapUnmanaged( 244 *Fn, 245 void, 246 MonomorphedFuncsContext, 247 std.hash_map.default_max_load_percentage, 248 ); 249 250 const MonomorphedFuncsContext = struct { 251 pub fn eql(ctx: @This(), a: *Fn, b: *Fn) bool { 252 _ = ctx; 253 return a == b; 254 } 255 256 /// Must match `Sema.GenericCallAdapter.hash`. 257 pub fn hash(ctx: @This(), key: *Fn) u64 { 258 _ = ctx; 259 return key.hash; 260 } 261 }; 262 263 pub const MemoizedCallSet = std.HashMapUnmanaged( 264 MemoizedCall.Key, 265 MemoizedCall.Result, 266 MemoizedCall, 267 std.hash_map.default_max_load_percentage, 268 ); 269 270 pub const MemoizedCall = struct { 271 module: *Module, 272 273 pub const Key = struct { 274 func: *Fn, 275 args: []TypedValue, 276 }; 277 278 pub const Result = struct { 279 val: Value, 280 arena: std.heap.ArenaAllocator.State, 281 }; 282 283 pub fn eql(ctx: @This(), a: Key, b: Key) bool { 284 if (a.func != b.func) return false; 285 286 assert(a.args.len == b.args.len); 287 for (a.args, 0..) |a_arg, arg_i| { 288 const b_arg = b.args[arg_i]; 289 if (!a_arg.eql(b_arg, ctx.module)) { 290 return false; 291 } 292 } 293 294 return true; 295 } 296 297 /// Must match `Sema.GenericCallAdapter.hash`. 298 pub fn hash(ctx: @This(), key: Key) u64 { 299 var hasher = std.hash.Wyhash.init(0); 300 301 // The generic function Decl is guaranteed to be the first dependency 302 // of each of its instantiations. 303 std.hash.autoHash(&hasher, key.func); 304 305 // This logic must be kept in sync with the logic in `analyzeCall` that 306 // computes the hash. 307 for (key.args) |arg| { 308 arg.hash(&hasher, ctx.module); 309 } 310 311 return hasher.final(); 312 } 313 }; 314 315 pub const SetAlignStack = struct { 316 alignment: u32, 317 /// TODO: This needs to store a non-lazy source location for the case of an inline function 318 /// which does `@setAlignStack` (applying it to the caller). 319 src: LazySrcLoc, 320 }; 321 322 /// A `Module` has zero or one of these depending on whether `-femit-h` is enabled. 323 pub const GlobalEmitH = struct { 324 /// Where to put the output. 325 loc: Compilation.EmitLoc, 326 /// When emit_h is non-null, each Decl gets one more compile error slot for 327 /// emit-h failing for that Decl. This table is also how we tell if a Decl has 328 /// failed emit-h or succeeded. 329 failed_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, *ErrorMsg) = .{}, 330 /// Tracks all decls in order to iterate over them and emit .h code for them. 331 decl_table: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{}, 332 /// Similar to the allocated_decls field of Module, this is where `EmitH` objects 333 /// are allocated. There will be exactly one EmitH object per Decl object, with 334 /// identical indexes. 335 allocated_emit_h: std.SegmentedList(EmitH, 0) = .{}, 336 337 pub fn declPtr(global_emit_h: *GlobalEmitH, decl_index: Decl.Index) *EmitH { 338 return global_emit_h.allocated_emit_h.at(@enumToInt(decl_index)); 339 } 340 }; 341 342 pub const ErrorInt = u32; 343 344 pub const Export = struct { 345 options: std.builtin.ExportOptions, 346 src: LazySrcLoc, 347 /// The Decl that performs the export. Note that this is *not* the Decl being exported. 348 owner_decl: Decl.Index, 349 /// The Decl containing the export statement. Inline function calls 350 /// may cause this to be different from the owner_decl. 351 src_decl: Decl.Index, 352 /// The Decl being exported. Note this is *not* the Decl performing the export. 353 exported_decl: Decl.Index, 354 status: enum { 355 in_progress, 356 failed, 357 /// Indicates that the failure was due to a temporary issue, such as an I/O error 358 /// when writing to the output file. Retrying the export may succeed. 359 failed_retryable, 360 complete, 361 }, 362 363 pub fn getSrcLoc(exp: Export, mod: *Module) SrcLoc { 364 const src_decl = mod.declPtr(exp.src_decl); 365 return .{ 366 .file_scope = src_decl.getFileScope(), 367 .parent_decl_node = src_decl.src_node, 368 .lazy = exp.src, 369 }; 370 } 371 }; 372 373 pub const CaptureScope = struct { 374 parent: ?*CaptureScope, 375 376 /// Values from this decl's evaluation that will be closed over in 377 /// child decls. Values stored in the value_arena of the linked decl. 378 /// During sema, this map is backed by the gpa. Once sema completes, 379 /// it is reallocated using the value_arena. 380 captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, TypedValue) = .{}, 381 382 pub fn failed(noalias self: *const @This()) bool { 383 return self.captures.available == 0 and self.captures.size == std.math.maxInt(u32); 384 } 385 386 pub fn fail(noalias self: *@This()) void { 387 self.captures.available = 0; 388 self.captures.size = std.math.maxInt(u32); 389 } 390 }; 391 392 pub const WipCaptureScope = struct { 393 scope: *CaptureScope, 394 finalized: bool, 395 gpa: Allocator, 396 perm_arena: Allocator, 397 398 pub fn init(gpa: Allocator, perm_arena: Allocator, parent: ?*CaptureScope) !@This() { 399 const scope = try perm_arena.create(CaptureScope); 400 scope.* = .{ .parent = parent }; 401 return @This(){ 402 .scope = scope, 403 .finalized = false, 404 .gpa = gpa, 405 .perm_arena = perm_arena, 406 }; 407 } 408 409 pub fn finalize(noalias self: *@This()) !void { 410 assert(!self.finalized); 411 // use a temp to avoid unintentional aliasing due to RLS 412 const tmp = try self.scope.captures.clone(self.perm_arena); 413 self.scope.captures.deinit(self.gpa); 414 self.scope.captures = tmp; 415 self.finalized = true; 416 } 417 418 pub fn reset(noalias self: *@This(), parent: ?*CaptureScope) !void { 419 if (!self.finalized) try self.finalize(); 420 self.scope = try self.perm_arena.create(CaptureScope); 421 self.scope.* = .{ .parent = parent }; 422 self.finalized = false; 423 } 424 425 pub fn deinit(noalias self: *@This()) void { 426 if (!self.finalized) { 427 self.scope.captures.deinit(self.gpa); 428 self.scope.fail(); 429 } 430 self.* = undefined; 431 } 432 }; 433 434 const ValueArena = struct { 435 state: std.heap.ArenaAllocator.State, 436 state_acquired: ?*std.heap.ArenaAllocator.State = null, 437 438 /// If this ValueArena replaced an existing one during re-analysis, this is the previous instance 439 prev: ?*ValueArena = null, 440 441 /// Returns an allocator backed by either promoting `state`, or by the existing ArenaAllocator 442 /// that has already promoted `state`. `out_arena_allocator` provides storage for the initial promotion, 443 /// and must live until the matching call to release(). 444 pub fn acquire(self: *ValueArena, child_allocator: Allocator, out_arena_allocator: *std.heap.ArenaAllocator) Allocator { 445 if (self.state_acquired) |state_acquired| { 446 return @fieldParentPtr(std.heap.ArenaAllocator, "state", state_acquired).allocator(); 447 } 448 449 out_arena_allocator.* = self.state.promote(child_allocator); 450 self.state_acquired = &out_arena_allocator.state; 451 return out_arena_allocator.allocator(); 452 } 453 454 /// Releases the allocator acquired by `acquire. `arena_allocator` must match the one passed to `acquire`. 455 pub fn release(self: *ValueArena, arena_allocator: *std.heap.ArenaAllocator) void { 456 if (@fieldParentPtr(std.heap.ArenaAllocator, "state", self.state_acquired.?) == arena_allocator) { 457 self.state = self.state_acquired.?.*; 458 self.state_acquired = null; 459 } 460 } 461 462 pub fn deinit(self: ValueArena, child_allocator: Allocator) void { 463 assert(self.state_acquired == null); 464 465 const prev = self.prev; 466 self.state.promote(child_allocator).deinit(); 467 468 if (prev) |p| { 469 p.deinit(child_allocator); 470 } 471 } 472 }; 473 474 pub const Decl = struct { 475 /// Allocated with Module's allocator; outlives the ZIR code. 476 name: [*:0]const u8, 477 /// The most recent Type of the Decl after a successful semantic analysis. 478 /// Populated when `has_tv`. 479 ty: Type, 480 /// The most recent Value of the Decl after a successful semantic analysis. 481 /// Populated when `has_tv`. 482 val: Value, 483 /// Populated when `has_tv`. 484 /// Points to memory inside value_arena. 485 @"linksection": ?[*:0]const u8, 486 /// Populated when `has_tv`. 487 @"align": u32, 488 /// Populated when `has_tv`. 489 @"addrspace": std.builtin.AddressSpace, 490 /// The memory for ty, val, align, linksection, and captures. 491 /// If this is `null` then there is no memory management needed. 492 value_arena: ?*ValueArena = null, 493 /// The direct parent namespace of the Decl. 494 /// Reference to externally owned memory. 495 /// In the case of the Decl corresponding to a file, this is 496 /// the namespace of the struct, since there is no parent. 497 src_namespace: *Namespace, 498 499 /// The scope which lexically contains this decl. A decl must depend 500 /// on its lexical parent, in order to ensure that this pointer is valid. 501 /// This scope is allocated out of the arena of the parent decl. 502 src_scope: ?*CaptureScope, 503 504 /// An integer that can be checked against the corresponding incrementing 505 /// generation field of Module. This is used to determine whether `complete` status 506 /// represents pre- or post- re-analysis. 507 generation: u32, 508 /// The AST node index of this declaration. 509 /// Must be recomputed when the corresponding source file is modified. 510 src_node: Ast.Node.Index, 511 /// Line number corresponding to `src_node`. Stored separately so that source files 512 /// do not need to be loaded into memory in order to compute debug line numbers. 513 /// This value is absolute. 514 src_line: u32, 515 /// Index to ZIR `extra` array to the entry in the parent's decl structure 516 /// (the part that says "for every decls_len"). The first item at this index is 517 /// the contents hash, followed by line, name, etc. 518 /// For anonymous decls and also the root Decl for a File, this is 0. 519 zir_decl_index: Zir.Inst.Index, 520 521 /// Represents the "shallow" analysis status. For example, for decls that are functions, 522 /// the function type is analyzed with this set to `in_progress`, however, the semantic 523 /// analysis of the function body is performed with this value set to `success`. Functions 524 /// have their own analysis status field. 525 analysis: enum { 526 /// This Decl corresponds to an AST Node that has not been referenced yet, and therefore 527 /// because of Zig's lazy declaration analysis, it will remain unanalyzed until referenced. 528 unreferenced, 529 /// Semantic analysis for this Decl is running right now. 530 /// This state detects dependency loops. 531 in_progress, 532 /// The file corresponding to this Decl had a parse error or ZIR error. 533 /// There will be a corresponding ErrorMsg in Module.failed_files. 534 file_failure, 535 /// This Decl might be OK but it depends on another one which did not successfully complete 536 /// semantic analysis. 537 dependency_failure, 538 /// Semantic analysis failure. 539 /// There will be a corresponding ErrorMsg in Module.failed_decls. 540 sema_failure, 541 /// There will be a corresponding ErrorMsg in Module.failed_decls. 542 /// This indicates the failure was something like running out of disk space, 543 /// and attempting semantic analysis again may succeed. 544 sema_failure_retryable, 545 /// There will be a corresponding ErrorMsg in Module.failed_decls. 546 liveness_failure, 547 /// There will be a corresponding ErrorMsg in Module.failed_decls. 548 codegen_failure, 549 /// There will be a corresponding ErrorMsg in Module.failed_decls. 550 /// This indicates the failure was something like running out of disk space, 551 /// and attempting codegen again may succeed. 552 codegen_failure_retryable, 553 /// Everything is done. During an update, this Decl may be out of date, depending 554 /// on its dependencies. The `generation` field can be used to determine if this 555 /// completion status occurred before or after a given update. 556 complete, 557 /// A Module update is in progress, and this Decl has been flagged as being known 558 /// to require re-analysis. 559 outdated, 560 }, 561 /// Whether `typed_value`, `align`, `linksection` and `addrspace` are populated. 562 has_tv: bool, 563 /// If `true` it means the `Decl` is the resource owner of the type/value associated 564 /// with it. That means when `Decl` is destroyed, the cleanup code should additionally 565 /// check if the value owns a `Namespace`, and destroy that too. 566 owns_tv: bool, 567 /// This flag is set when this Decl is added to `Module.deletion_set`, and cleared 568 /// when removed. 569 deletion_flag: bool, 570 /// Whether the corresponding AST decl has a `pub` keyword. 571 is_pub: bool, 572 /// Whether the corresponding AST decl has a `export` keyword. 573 is_exported: bool, 574 /// Whether the ZIR code provides an align instruction. 575 has_align: bool, 576 /// Whether the ZIR code provides a linksection and address space instruction. 577 has_linksection_or_addrspace: bool, 578 /// Flag used by garbage collection to mark and sweep. 579 /// Decls which correspond to an AST node always have this field set to `true`. 580 /// Anonymous Decls are initialized with this field set to `false` and then it 581 /// is the responsibility of machine code backends to mark it `true` whenever 582 /// a `decl_ref` Value is encountered that points to this Decl. 583 /// When the `codegen_decl` job is encountered in the main work queue, if the 584 /// Decl is marked alive, then it sends the Decl to the linker. Otherwise it 585 /// deletes the Decl on the spot. 586 alive: bool, 587 /// If true `name` is already fully qualified. 588 name_fully_qualified: bool = false, 589 /// What kind of a declaration is this. 590 kind: Kind, 591 592 /// The shallow set of other decls whose typed_value could possibly change if this Decl's 593 /// typed_value is modified. 594 dependants: DepsTable = .{}, 595 /// The shallow set of other decls whose typed_value changing indicates that this Decl's 596 /// typed_value may need to be regenerated. 597 dependencies: DepsTable = .{}, 598 599 pub const Kind = enum { 600 @"usingnamespace", 601 @"test", 602 @"comptime", 603 named, 604 anon, 605 }; 606 607 pub const Index = enum(u32) { 608 _, 609 610 pub fn toOptional(i: Index) OptionalIndex { 611 return @intToEnum(OptionalIndex, @enumToInt(i)); 612 } 613 }; 614 615 pub const OptionalIndex = enum(u32) { 616 none = std.math.maxInt(u32), 617 _, 618 619 pub fn init(oi: ?Index) OptionalIndex { 620 return @intToEnum(OptionalIndex, @enumToInt(oi orelse return .none)); 621 } 622 623 pub fn unwrap(oi: OptionalIndex) ?Index { 624 if (oi == .none) return null; 625 return @intToEnum(Index, @enumToInt(oi)); 626 } 627 }; 628 629 pub const DepsTable = std.AutoArrayHashMapUnmanaged(Decl.Index, DepType); 630 631 /// Later types take priority; e.g. if a dependent decl has both `normal` 632 /// and `function_body` dependencies on another decl, it will be marked as 633 /// having a `function_body` dependency. 634 pub const DepType = enum { 635 /// The dependent references or uses the dependency's value, so must be 636 /// updated whenever it is changed. However, if the dependency is a 637 /// function and its type is unchanged, the dependent does not need to 638 /// be updated. 639 normal, 640 /// The dependent performs an inline or comptime call to the dependency, 641 /// or is a generic instantiation of it. It must therefore be updated 642 /// whenever the dependency is updated, even if the function type 643 /// remained the same. 644 function_body, 645 }; 646 647 pub fn clearName(decl: *Decl, gpa: Allocator) void { 648 gpa.free(mem.sliceTo(decl.name, 0)); 649 decl.name = undefined; 650 } 651 652 pub fn clearValues(decl: *Decl, mod: *Module) void { 653 const gpa = mod.gpa; 654 if (decl.getExternFn()) |extern_fn| { 655 extern_fn.deinit(gpa); 656 gpa.destroy(extern_fn); 657 } 658 if (decl.getFunction()) |func| { 659 _ = mod.align_stack_fns.remove(func); 660 if (func.comptime_args != null) { 661 _ = mod.monomorphed_funcs.remove(func); 662 } 663 func.deinit(gpa); 664 gpa.destroy(func); 665 } 666 if (decl.getVariable()) |variable| { 667 variable.deinit(gpa); 668 gpa.destroy(variable); 669 } 670 if (decl.value_arena) |value_arena| { 671 if (decl.owns_tv) { 672 if (decl.val.castTag(.str_lit)) |str_lit| { 673 mod.string_literal_table.getPtrContext(str_lit.data, .{ 674 .bytes = &mod.string_literal_bytes, 675 }).?.* = .none; 676 } 677 } 678 value_arena.deinit(gpa); 679 decl.value_arena = null; 680 decl.has_tv = false; 681 decl.owns_tv = false; 682 } 683 } 684 685 pub fn finalizeNewArena(decl: *Decl, arena: *std.heap.ArenaAllocator) !void { 686 assert(decl.value_arena == null); 687 const value_arena = try arena.allocator().create(ValueArena); 688 value_arena.* = .{ .state = arena.state }; 689 decl.value_arena = value_arena; 690 } 691 692 /// This name is relative to the containing namespace of the decl. 693 /// The memory is owned by the containing File ZIR. 694 pub fn getName(decl: Decl) ?[:0]const u8 { 695 const zir = decl.getFileScope().zir; 696 return decl.getNameZir(zir); 697 } 698 699 pub fn getNameZir(decl: Decl, zir: Zir) ?[:0]const u8 { 700 assert(decl.zir_decl_index != 0); 701 const name_index = zir.extra[decl.zir_decl_index + 5]; 702 if (name_index <= 1) return null; 703 return zir.nullTerminatedString(name_index); 704 } 705 706 pub fn contentsHash(decl: Decl) std.zig.SrcHash { 707 const zir = decl.getFileScope().zir; 708 return decl.contentsHashZir(zir); 709 } 710 711 pub fn contentsHashZir(decl: Decl, zir: Zir) std.zig.SrcHash { 712 assert(decl.zir_decl_index != 0); 713 const hash_u32s = zir.extra[decl.zir_decl_index..][0..4]; 714 const contents_hash = @bitCast(std.zig.SrcHash, hash_u32s.*); 715 return contents_hash; 716 } 717 718 pub fn zirBlockIndex(decl: *const Decl) Zir.Inst.Index { 719 assert(decl.zir_decl_index != 0); 720 const zir = decl.getFileScope().zir; 721 return zir.extra[decl.zir_decl_index + 6]; 722 } 723 724 pub fn zirAlignRef(decl: Decl) Zir.Inst.Ref { 725 if (!decl.has_align) return .none; 726 assert(decl.zir_decl_index != 0); 727 const zir = decl.getFileScope().zir; 728 return @intToEnum(Zir.Inst.Ref, zir.extra[decl.zir_decl_index + 8]); 729 } 730 731 pub fn zirLinksectionRef(decl: Decl) Zir.Inst.Ref { 732 if (!decl.has_linksection_or_addrspace) return .none; 733 assert(decl.zir_decl_index != 0); 734 const zir = decl.getFileScope().zir; 735 const extra_index = decl.zir_decl_index + 8 + @boolToInt(decl.has_align); 736 return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); 737 } 738 739 pub fn zirAddrspaceRef(decl: Decl) Zir.Inst.Ref { 740 if (!decl.has_linksection_or_addrspace) return .none; 741 assert(decl.zir_decl_index != 0); 742 const zir = decl.getFileScope().zir; 743 const extra_index = decl.zir_decl_index + 8 + @boolToInt(decl.has_align) + 1; 744 return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); 745 } 746 747 pub fn relativeToLine(decl: Decl, offset: u32) u32 { 748 return decl.src_line + offset; 749 } 750 751 pub fn relativeToNodeIndex(decl: Decl, offset: i32) Ast.Node.Index { 752 return @bitCast(Ast.Node.Index, offset + @bitCast(i32, decl.src_node)); 753 } 754 755 pub fn nodeIndexToRelative(decl: Decl, node_index: Ast.Node.Index) i32 { 756 return @bitCast(i32, node_index) - @bitCast(i32, decl.src_node); 757 } 758 759 pub fn tokSrcLoc(decl: Decl, token_index: Ast.TokenIndex) LazySrcLoc { 760 return .{ .token_offset = token_index - decl.srcToken() }; 761 } 762 763 pub fn nodeSrcLoc(decl: Decl, node_index: Ast.Node.Index) LazySrcLoc { 764 return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(node_index)); 765 } 766 767 pub fn srcLoc(decl: Decl) SrcLoc { 768 return decl.nodeOffsetSrcLoc(0); 769 } 770 771 pub fn nodeOffsetSrcLoc(decl: Decl, node_offset: i32) SrcLoc { 772 return .{ 773 .file_scope = decl.getFileScope(), 774 .parent_decl_node = decl.src_node, 775 .lazy = LazySrcLoc.nodeOffset(node_offset), 776 }; 777 } 778 779 pub fn srcToken(decl: Decl) Ast.TokenIndex { 780 const tree = &decl.getFileScope().tree; 781 return tree.firstToken(decl.src_node); 782 } 783 784 pub fn srcByteOffset(decl: Decl) u32 { 785 const tree = &decl.getFileScope().tree; 786 return tree.tokens.items(.start)[decl.srcToken()]; 787 } 788 789 pub fn renderFullyQualifiedName(decl: Decl, mod: *Module, writer: anytype) !void { 790 const unqualified_name = mem.sliceTo(decl.name, 0); 791 if (decl.name_fully_qualified) { 792 return writer.writeAll(unqualified_name); 793 } 794 return decl.src_namespace.renderFullyQualifiedName(mod, unqualified_name, writer); 795 } 796 797 pub fn renderFullyQualifiedDebugName(decl: Decl, mod: *Module, writer: anytype) !void { 798 const unqualified_name = mem.sliceTo(decl.name, 0); 799 return decl.src_namespace.renderFullyQualifiedDebugName(mod, unqualified_name, writer); 800 } 801 802 pub fn getFullyQualifiedName(decl: Decl, mod: *Module) ![:0]u8 { 803 var buffer = std.ArrayList(u8).init(mod.gpa); 804 defer buffer.deinit(); 805 try decl.renderFullyQualifiedName(mod, buffer.writer()); 806 807 // Sanitize the name for nvptx which is more restrictive. 808 if (mod.comp.bin_file.options.target.cpu.arch.isNvptx()) { 809 for (buffer.items) |*byte| switch (byte.*) { 810 '{', '}', '*', '[', ']', '(', ')', ',', ' ', '\'' => byte.* = '_', 811 else => {}, 812 }; 813 } 814 815 return buffer.toOwnedSliceSentinel(0); 816 } 817 818 pub fn typedValue(decl: Decl) error{AnalysisFail}!TypedValue { 819 if (!decl.has_tv) return error.AnalysisFail; 820 return TypedValue{ 821 .ty = decl.ty, 822 .val = decl.val, 823 }; 824 } 825 826 pub fn value(decl: *Decl) error{AnalysisFail}!Value { 827 return (try decl.typedValue()).val; 828 } 829 830 pub fn isFunction(decl: Decl, mod: *const Module) !bool { 831 const tv = try decl.typedValue(); 832 return tv.ty.zigTypeTag(mod) == .Fn; 833 } 834 835 /// If the Decl has a value and it is a struct, return it, 836 /// otherwise null. 837 pub fn getStruct(decl: *Decl) ?*Struct { 838 if (!decl.owns_tv) return null; 839 const ty = (decl.val.castTag(.ty) orelse return null).data; 840 const struct_obj = (ty.castTag(.@"struct") orelse return null).data; 841 return struct_obj; 842 } 843 844 /// If the Decl has a value and it is a union, return it, 845 /// otherwise null. 846 pub fn getUnion(decl: *Decl) ?*Union { 847 if (!decl.owns_tv) return null; 848 const ty = (decl.val.castTag(.ty) orelse return null).data; 849 const union_obj = (ty.cast(Type.Payload.Union) orelse return null).data; 850 return union_obj; 851 } 852 853 /// If the Decl has a value and it is a function, return it, 854 /// otherwise null. 855 pub fn getFunction(decl: *const Decl) ?*Fn { 856 if (!decl.owns_tv) return null; 857 const func = (decl.val.castTag(.function) orelse return null).data; 858 return func; 859 } 860 861 /// If the Decl has a value and it is an extern function, returns it, 862 /// otherwise null. 863 pub fn getExternFn(decl: *const Decl) ?*ExternFn { 864 if (!decl.owns_tv) return null; 865 const extern_fn = (decl.val.castTag(.extern_fn) orelse return null).data; 866 return extern_fn; 867 } 868 869 /// If the Decl has a value and it is a variable, returns it, 870 /// otherwise null. 871 pub fn getVariable(decl: *const Decl) ?*Var { 872 if (!decl.owns_tv) return null; 873 const variable = (decl.val.castTag(.variable) orelse return null).data; 874 return variable; 875 } 876 877 /// Gets the namespace that this Decl creates by being a struct, union, 878 /// enum, or opaque. 879 /// Only returns it if the Decl is the owner. 880 pub fn getInnerNamespace(decl: *Decl) ?*Namespace { 881 if (!decl.owns_tv) return null; 882 const ty = (decl.val.castTag(.ty) orelse return null).data; 883 switch (ty.tag()) { 884 .@"struct" => { 885 const struct_obj = ty.castTag(.@"struct").?.data; 886 return &struct_obj.namespace; 887 }, 888 .enum_full, .enum_nonexhaustive => { 889 const enum_obj = ty.cast(Type.Payload.EnumFull).?.data; 890 return &enum_obj.namespace; 891 }, 892 .empty_struct => { 893 return ty.castTag(.empty_struct).?.data; 894 }, 895 .@"opaque" => { 896 const opaque_obj = ty.cast(Type.Payload.Opaque).?.data; 897 return &opaque_obj.namespace; 898 }, 899 .@"union", .union_safety_tagged, .union_tagged => { 900 const union_obj = ty.cast(Type.Payload.Union).?.data; 901 return &union_obj.namespace; 902 }, 903 904 else => return null, 905 } 906 } 907 908 pub fn dump(decl: *Decl) void { 909 const loc = std.zig.findLineColumn(decl.scope.source.bytes, decl.src); 910 std.debug.print("{s}:{d}:{d} name={s} status={s}", .{ 911 decl.scope.sub_file_path, 912 loc.line + 1, 913 loc.column + 1, 914 mem.sliceTo(decl.name, 0), 915 @tagName(decl.analysis), 916 }); 917 if (decl.has_tv) { 918 std.debug.print(" ty={} val={}", .{ decl.ty, decl.val }); 919 } 920 std.debug.print("\n", .{}); 921 } 922 923 pub fn getFileScope(decl: Decl) *File { 924 return decl.src_namespace.file_scope; 925 } 926 927 pub fn removeDependant(decl: *Decl, other: Decl.Index) void { 928 assert(decl.dependants.swapRemove(other)); 929 } 930 931 pub fn removeDependency(decl: *Decl, other: Decl.Index) void { 932 assert(decl.dependencies.swapRemove(other)); 933 } 934 935 pub fn isExtern(decl: Decl) bool { 936 assert(decl.has_tv); 937 return switch (decl.val.ip_index) { 938 .none => switch (decl.val.tag()) { 939 .extern_fn => true, 940 .variable => decl.val.castTag(.variable).?.data.init.ip_index == .unreachable_value, 941 else => false, 942 }, 943 else => false, 944 }; 945 } 946 947 pub fn getAlignment(decl: Decl, mod: *Module) u32 { 948 assert(decl.has_tv); 949 if (decl.@"align" != 0) { 950 // Explicit alignment. 951 return decl.@"align"; 952 } else { 953 // Natural alignment. 954 return decl.ty.abiAlignment(mod); 955 } 956 } 957 }; 958 959 /// This state is attached to every Decl when Module emit_h is non-null. 960 pub const EmitH = struct { 961 fwd_decl: ArrayListUnmanaged(u8) = .{}, 962 }; 963 964 /// Represents the data that an explicit error set syntax provides. 965 pub const ErrorSet = struct { 966 /// The Decl that corresponds to the error set itself. 967 owner_decl: Decl.Index, 968 /// The string bytes are stored in the owner Decl arena. 969 /// These must be in sorted order. See sortNames. 970 names: NameMap, 971 972 pub const NameMap = std.StringArrayHashMapUnmanaged(void); 973 974 pub fn srcLoc(self: ErrorSet, mod: *Module) SrcLoc { 975 const owner_decl = mod.declPtr(self.owner_decl); 976 return .{ 977 .file_scope = owner_decl.getFileScope(), 978 .parent_decl_node = owner_decl.src_node, 979 .lazy = LazySrcLoc.nodeOffset(0), 980 }; 981 } 982 983 /// sort the NameMap. This should be called whenever the map is modified. 984 /// alloc should be the allocator used for the NameMap data. 985 pub fn sortNames(names: *NameMap) void { 986 const Context = struct { 987 keys: [][]const u8, 988 pub fn lessThan(ctx: @This(), a_index: usize, b_index: usize) bool { 989 return std.mem.lessThan(u8, ctx.keys[a_index], ctx.keys[b_index]); 990 } 991 }; 992 names.sort(Context{ .keys = names.keys() }); 993 } 994 }; 995 996 pub const PropertyBoolean = enum { no, yes, unknown, wip }; 997 998 /// Represents the data that a struct declaration provides. 999 pub const Struct = struct { 1000 /// Set of field names in declaration order. 1001 fields: Fields, 1002 /// Represents the declarations inside this struct. 1003 namespace: Namespace, 1004 /// The Decl that corresponds to the struct itself. 1005 owner_decl: Decl.Index, 1006 /// Index of the struct_decl ZIR instruction. 1007 zir_index: Zir.Inst.Index, 1008 /// Indexes into `fields` sorted to be most memory efficient. 1009 optimized_order: ?[*]u32 = null, 1010 layout: std.builtin.Type.ContainerLayout, 1011 /// If the layout is not packed, this is the noreturn type. 1012 /// If the layout is packed, this is the backing integer type of the packed struct. 1013 /// Whether zig chooses this type or the user specifies it, it is stored here. 1014 /// This will be set to the noreturn type until status is `have_layout`. 1015 backing_int_ty: Type = Type.noreturn, 1016 status: enum { 1017 none, 1018 field_types_wip, 1019 have_field_types, 1020 layout_wip, 1021 have_layout, 1022 fully_resolved_wip, 1023 // The types and all its fields have had their layout resolved. Even through pointer, 1024 // which `have_layout` does not ensure. 1025 fully_resolved, 1026 }, 1027 /// If true, has more than one possible value. However it may still be non-runtime type 1028 /// if it is a comptime-only type. 1029 /// If false, resolving the fields is necessary to determine whether the type has only 1030 /// one possible value. 1031 known_non_opv: bool, 1032 requires_comptime: PropertyBoolean = .unknown, 1033 have_field_inits: bool = false, 1034 is_tuple: bool, 1035 assumed_runtime_bits: bool = false, 1036 1037 pub const Fields = std.StringArrayHashMapUnmanaged(Field); 1038 1039 /// The `Type` and `Value` memory is owned by the arena of the Struct's owner_decl. 1040 pub const Field = struct { 1041 /// Uses `noreturn` to indicate `anytype`. 1042 /// undefined until `status` is >= `have_field_types`. 1043 ty: Type, 1044 /// Uses `unreachable_value` to indicate no default. 1045 default_val: Value, 1046 /// Zero means to use the ABI alignment of the type. 1047 abi_align: u32, 1048 /// undefined until `status` is `have_layout`. 1049 offset: u32, 1050 /// If true then `default_val` is the comptime field value. 1051 is_comptime: bool, 1052 1053 /// Returns the field alignment. If the struct is packed, returns 0. 1054 pub fn alignment( 1055 field: Field, 1056 mod: *Module, 1057 layout: std.builtin.Type.ContainerLayout, 1058 ) u32 { 1059 if (field.abi_align != 0) { 1060 assert(layout != .Packed); 1061 return field.abi_align; 1062 } 1063 1064 const target = mod.getTarget(); 1065 1066 switch (layout) { 1067 .Packed => return 0, 1068 .Auto => { 1069 if (target.ofmt == .c) { 1070 return alignmentExtern(field, mod); 1071 } else { 1072 return field.ty.abiAlignment(mod); 1073 } 1074 }, 1075 .Extern => return alignmentExtern(field, mod), 1076 } 1077 } 1078 1079 pub fn alignmentExtern(field: Field, mod: *Module) u32 { 1080 // This logic is duplicated in Type.abiAlignmentAdvanced. 1081 const ty_abi_align = field.ty.abiAlignment(mod); 1082 1083 if (field.ty.isAbiInt(mod) and field.ty.intInfo(mod).bits >= 128) { 1084 // The C ABI requires 128 bit integer fields of structs 1085 // to be 16-bytes aligned. 1086 return @max(ty_abi_align, 16); 1087 } 1088 1089 return ty_abi_align; 1090 } 1091 }; 1092 1093 /// Used in `optimized_order` to indicate field that is not present in the 1094 /// runtime version of the struct. 1095 pub const omitted_field = std.math.maxInt(u32); 1096 1097 pub fn getFullyQualifiedName(s: *Struct, mod: *Module) ![:0]u8 { 1098 return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod); 1099 } 1100 1101 pub fn srcLoc(s: Struct, mod: *Module) SrcLoc { 1102 const owner_decl = mod.declPtr(s.owner_decl); 1103 return .{ 1104 .file_scope = owner_decl.getFileScope(), 1105 .parent_decl_node = owner_decl.src_node, 1106 .lazy = LazySrcLoc.nodeOffset(0), 1107 }; 1108 } 1109 1110 pub fn fieldSrcLoc(s: Struct, mod: *Module, query: FieldSrcQuery) SrcLoc { 1111 @setCold(true); 1112 const owner_decl = mod.declPtr(s.owner_decl); 1113 const file = owner_decl.getFileScope(); 1114 const tree = file.getTree(mod.gpa) catch |err| { 1115 // In this case we emit a warning + a less precise source location. 1116 log.warn("unable to load {s}: {s}", .{ 1117 file.sub_file_path, @errorName(err), 1118 }); 1119 return s.srcLoc(mod); 1120 }; 1121 const node = owner_decl.relativeToNodeIndex(0); 1122 1123 var buf: [2]Ast.Node.Index = undefined; 1124 if (tree.fullContainerDecl(&buf, node)) |container_decl| { 1125 return queryFieldSrc(tree.*, query, file, container_decl); 1126 } else { 1127 // This struct was generated using @Type 1128 return s.srcLoc(mod); 1129 } 1130 } 1131 1132 pub fn haveFieldTypes(s: Struct) bool { 1133 return switch (s.status) { 1134 .none, 1135 .field_types_wip, 1136 => false, 1137 .have_field_types, 1138 .layout_wip, 1139 .have_layout, 1140 .fully_resolved_wip, 1141 .fully_resolved, 1142 => true, 1143 }; 1144 } 1145 1146 pub fn haveLayout(s: Struct) bool { 1147 return switch (s.status) { 1148 .none, 1149 .field_types_wip, 1150 .have_field_types, 1151 .layout_wip, 1152 => false, 1153 .have_layout, 1154 .fully_resolved_wip, 1155 .fully_resolved, 1156 => true, 1157 }; 1158 } 1159 1160 pub fn packedFieldBitOffset(s: Struct, mod: *Module, index: usize) u16 { 1161 assert(s.layout == .Packed); 1162 assert(s.haveLayout()); 1163 var bit_sum: u64 = 0; 1164 for (s.fields.values(), 0..) |field, i| { 1165 if (i == index) { 1166 return @intCast(u16, bit_sum); 1167 } 1168 bit_sum += field.ty.bitSize(mod); 1169 } 1170 unreachable; // index out of bounds 1171 } 1172 1173 pub const RuntimeFieldIterator = struct { 1174 module: *Module, 1175 struct_obj: *const Struct, 1176 index: u32 = 0, 1177 1178 pub const FieldAndIndex = struct { 1179 field: Field, 1180 index: u32, 1181 }; 1182 1183 pub fn next(it: *RuntimeFieldIterator) ?FieldAndIndex { 1184 const mod = it.module; 1185 while (true) { 1186 var i = it.index; 1187 it.index += 1; 1188 if (it.struct_obj.fields.count() <= i) 1189 return null; 1190 1191 if (it.struct_obj.optimized_order) |some| { 1192 i = some[i]; 1193 if (i == Module.Struct.omitted_field) return null; 1194 } 1195 const field = it.struct_obj.fields.values()[i]; 1196 1197 if (!field.is_comptime and field.ty.hasRuntimeBits(mod)) { 1198 return FieldAndIndex{ .index = i, .field = field }; 1199 } 1200 } 1201 } 1202 }; 1203 1204 pub fn runtimeFieldIterator(s: *const Struct, module: *Module) RuntimeFieldIterator { 1205 return .{ 1206 .struct_obj = s, 1207 .module = module, 1208 }; 1209 } 1210 }; 1211 1212 /// Represents the data that an enum declaration provides, when the fields 1213 /// are auto-numbered, and there are no declarations. The integer tag type 1214 /// is inferred to be the smallest power of two unsigned int that fits 1215 /// the number of fields. 1216 pub const EnumSimple = struct { 1217 /// The Decl that corresponds to the enum itself. 1218 owner_decl: Decl.Index, 1219 /// Set of field names in declaration order. 1220 fields: NameMap, 1221 1222 pub const NameMap = EnumFull.NameMap; 1223 1224 pub fn srcLoc(self: EnumSimple, mod: *Module) SrcLoc { 1225 const owner_decl = mod.declPtr(self.owner_decl); 1226 return .{ 1227 .file_scope = owner_decl.getFileScope(), 1228 .parent_decl_node = owner_decl.src_node, 1229 .lazy = LazySrcLoc.nodeOffset(0), 1230 }; 1231 } 1232 }; 1233 1234 /// Represents the data that an enum declaration provides, when there are no 1235 /// declarations. However an integer tag type is provided, and the enum tag values 1236 /// are explicitly provided. 1237 pub const EnumNumbered = struct { 1238 /// The Decl that corresponds to the enum itself. 1239 owner_decl: Decl.Index, 1240 /// An integer type which is used for the numerical value of the enum. 1241 /// Whether zig chooses this type or the user specifies it, it is stored here. 1242 tag_ty: Type, 1243 /// Set of field names in declaration order. 1244 fields: NameMap, 1245 /// Maps integer tag value to field index. 1246 /// Entries are in declaration order, same as `fields`. 1247 /// If this hash map is empty, it means the enum tags are auto-numbered. 1248 values: ValueMap, 1249 1250 pub const NameMap = EnumFull.NameMap; 1251 pub const ValueMap = EnumFull.ValueMap; 1252 1253 pub fn srcLoc(self: EnumNumbered, mod: *Module) SrcLoc { 1254 const owner_decl = mod.declPtr(self.owner_decl); 1255 return .{ 1256 .file_scope = owner_decl.getFileScope(), 1257 .parent_decl_node = owner_decl.src_node, 1258 .lazy = LazySrcLoc.nodeOffset(0), 1259 }; 1260 } 1261 }; 1262 1263 /// Represents the data that an enum declaration provides, when there is 1264 /// at least one tag value explicitly specified, or at least one declaration. 1265 pub const EnumFull = struct { 1266 /// The Decl that corresponds to the enum itself. 1267 owner_decl: Decl.Index, 1268 /// An integer type which is used for the numerical value of the enum. 1269 /// Whether zig chooses this type or the user specifies it, it is stored here. 1270 tag_ty: Type, 1271 /// Set of field names in declaration order. 1272 fields: NameMap, 1273 /// Maps integer tag value to field index. 1274 /// Entries are in declaration order, same as `fields`. 1275 /// If this hash map is empty, it means the enum tags are auto-numbered. 1276 values: ValueMap, 1277 /// Represents the declarations inside this enum. 1278 namespace: Namespace, 1279 /// true if zig inferred this tag type, false if user specified it 1280 tag_ty_inferred: bool, 1281 1282 pub const NameMap = std.StringArrayHashMapUnmanaged(void); 1283 pub const ValueMap = std.ArrayHashMapUnmanaged(Value, void, Value.ArrayHashContext, false); 1284 1285 pub fn srcLoc(self: EnumFull, mod: *Module) SrcLoc { 1286 const owner_decl = mod.declPtr(self.owner_decl); 1287 return .{ 1288 .file_scope = owner_decl.getFileScope(), 1289 .parent_decl_node = owner_decl.src_node, 1290 .lazy = LazySrcLoc.nodeOffset(0), 1291 }; 1292 } 1293 1294 pub fn fieldSrcLoc(e: EnumFull, mod: *Module, query: FieldSrcQuery) SrcLoc { 1295 @setCold(true); 1296 const owner_decl = mod.declPtr(e.owner_decl); 1297 const file = owner_decl.getFileScope(); 1298 const tree = file.getTree(mod.gpa) catch |err| { 1299 // In this case we emit a warning + a less precise source location. 1300 log.warn("unable to load {s}: {s}", .{ 1301 file.sub_file_path, @errorName(err), 1302 }); 1303 return e.srcLoc(mod); 1304 }; 1305 const node = owner_decl.relativeToNodeIndex(0); 1306 var buf: [2]Ast.Node.Index = undefined; 1307 if (tree.fullContainerDecl(&buf, node)) |container_decl| { 1308 return queryFieldSrc(tree.*, query, file, container_decl); 1309 } else { 1310 // This enum was generated using @Type 1311 return e.srcLoc(mod); 1312 } 1313 } 1314 }; 1315 1316 pub const Union = struct { 1317 /// An enum type which is used for the tag of the union. 1318 /// This type is created even for untagged unions, even when the memory 1319 /// layout does not store the tag. 1320 /// Whether zig chooses this type or the user specifies it, it is stored here. 1321 /// This will be set to the null type until status is `have_field_types`. 1322 tag_ty: Type, 1323 /// Set of field names in declaration order. 1324 fields: Fields, 1325 /// Represents the declarations inside this union. 1326 namespace: Namespace, 1327 /// The Decl that corresponds to the union itself. 1328 owner_decl: Decl.Index, 1329 /// Index of the union_decl ZIR instruction. 1330 zir_index: Zir.Inst.Index, 1331 1332 layout: std.builtin.Type.ContainerLayout, 1333 status: enum { 1334 none, 1335 field_types_wip, 1336 have_field_types, 1337 layout_wip, 1338 have_layout, 1339 fully_resolved_wip, 1340 // The types and all its fields have had their layout resolved. Even through pointer, 1341 // which `have_layout` does not ensure. 1342 fully_resolved, 1343 }, 1344 requires_comptime: PropertyBoolean = .unknown, 1345 assumed_runtime_bits: bool = false, 1346 1347 pub const Field = struct { 1348 /// undefined until `status` is `have_field_types` or `have_layout`. 1349 ty: Type, 1350 /// 0 means the ABI alignment of the type. 1351 abi_align: u32, 1352 1353 /// Returns the field alignment, assuming the union is not packed. 1354 /// Keep implementation in sync with `Sema.unionFieldAlignment`. 1355 /// Prefer to call that function instead of this one during Sema. 1356 pub fn normalAlignment(field: Field, mod: *Module) u32 { 1357 if (field.abi_align == 0) { 1358 return field.ty.abiAlignment(mod); 1359 } else { 1360 return field.abi_align; 1361 } 1362 } 1363 }; 1364 1365 pub const Fields = std.StringArrayHashMapUnmanaged(Field); 1366 1367 pub fn getFullyQualifiedName(s: *Union, mod: *Module) ![:0]u8 { 1368 return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod); 1369 } 1370 1371 pub fn srcLoc(self: Union, mod: *Module) SrcLoc { 1372 const owner_decl = mod.declPtr(self.owner_decl); 1373 return .{ 1374 .file_scope = owner_decl.getFileScope(), 1375 .parent_decl_node = owner_decl.src_node, 1376 .lazy = LazySrcLoc.nodeOffset(0), 1377 }; 1378 } 1379 1380 pub fn fieldSrcLoc(u: Union, mod: *Module, query: FieldSrcQuery) SrcLoc { 1381 @setCold(true); 1382 const owner_decl = mod.declPtr(u.owner_decl); 1383 const file = owner_decl.getFileScope(); 1384 const tree = file.getTree(mod.gpa) catch |err| { 1385 // In this case we emit a warning + a less precise source location. 1386 log.warn("unable to load {s}: {s}", .{ 1387 file.sub_file_path, @errorName(err), 1388 }); 1389 return u.srcLoc(mod); 1390 }; 1391 const node = owner_decl.relativeToNodeIndex(0); 1392 1393 var buf: [2]Ast.Node.Index = undefined; 1394 if (tree.fullContainerDecl(&buf, node)) |container_decl| { 1395 return queryFieldSrc(tree.*, query, file, container_decl); 1396 } else { 1397 // This union was generated using @Type 1398 return u.srcLoc(mod); 1399 } 1400 } 1401 1402 pub fn haveFieldTypes(u: Union) bool { 1403 return switch (u.status) { 1404 .none, 1405 .field_types_wip, 1406 => false, 1407 .have_field_types, 1408 .layout_wip, 1409 .have_layout, 1410 .fully_resolved_wip, 1411 .fully_resolved, 1412 => true, 1413 }; 1414 } 1415 1416 pub fn hasAllZeroBitFieldTypes(u: Union, mod: *Module) bool { 1417 assert(u.haveFieldTypes()); 1418 for (u.fields.values()) |field| { 1419 if (field.ty.hasRuntimeBits(mod)) return false; 1420 } 1421 return true; 1422 } 1423 1424 pub fn mostAlignedField(u: Union, mod: *Module) u32 { 1425 assert(u.haveFieldTypes()); 1426 var most_alignment: u32 = 0; 1427 var most_index: usize = undefined; 1428 for (u.fields.values(), 0..) |field, i| { 1429 if (!field.ty.hasRuntimeBits(mod)) continue; 1430 1431 const field_align = field.normalAlignment(mod); 1432 if (field_align > most_alignment) { 1433 most_alignment = field_align; 1434 most_index = i; 1435 } 1436 } 1437 return @intCast(u32, most_index); 1438 } 1439 1440 /// Returns 0 if the union is represented with 0 bits at runtime. 1441 pub fn abiAlignment(u: Union, mod: *Module, have_tag: bool) u32 { 1442 var max_align: u32 = 0; 1443 if (have_tag) max_align = u.tag_ty.abiAlignment(mod); 1444 for (u.fields.values()) |field| { 1445 if (!field.ty.hasRuntimeBits(mod)) continue; 1446 1447 const field_align = field.normalAlignment(mod); 1448 max_align = @max(max_align, field_align); 1449 } 1450 return max_align; 1451 } 1452 1453 pub fn abiSize(u: Union, mod: *Module, have_tag: bool) u64 { 1454 return u.getLayout(mod, have_tag).abi_size; 1455 } 1456 1457 pub const Layout = struct { 1458 abi_size: u64, 1459 abi_align: u32, 1460 most_aligned_field: u32, 1461 most_aligned_field_size: u64, 1462 biggest_field: u32, 1463 payload_size: u64, 1464 payload_align: u32, 1465 tag_align: u32, 1466 tag_size: u64, 1467 padding: u32, 1468 }; 1469 1470 pub fn haveLayout(u: Union) bool { 1471 return switch (u.status) { 1472 .none, 1473 .field_types_wip, 1474 .have_field_types, 1475 .layout_wip, 1476 => false, 1477 .have_layout, 1478 .fully_resolved_wip, 1479 .fully_resolved, 1480 => true, 1481 }; 1482 } 1483 1484 pub fn getLayout(u: Union, mod: *Module, have_tag: bool) Layout { 1485 assert(u.haveLayout()); 1486 var most_aligned_field: u32 = undefined; 1487 var most_aligned_field_size: u64 = undefined; 1488 var biggest_field: u32 = undefined; 1489 var payload_size: u64 = 0; 1490 var payload_align: u32 = 0; 1491 const fields = u.fields.values(); 1492 for (fields, 0..) |field, i| { 1493 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; 1494 1495 const field_align = a: { 1496 if (field.abi_align == 0) { 1497 break :a field.ty.abiAlignment(mod); 1498 } else { 1499 break :a field.abi_align; 1500 } 1501 }; 1502 const field_size = field.ty.abiSize(mod); 1503 if (field_size > payload_size) { 1504 payload_size = field_size; 1505 biggest_field = @intCast(u32, i); 1506 } 1507 if (field_align > payload_align) { 1508 payload_align = field_align; 1509 most_aligned_field = @intCast(u32, i); 1510 most_aligned_field_size = field_size; 1511 } 1512 } 1513 payload_align = @max(payload_align, 1); 1514 if (!have_tag or !u.tag_ty.hasRuntimeBits(mod)) { 1515 return .{ 1516 .abi_size = std.mem.alignForwardGeneric(u64, payload_size, payload_align), 1517 .abi_align = payload_align, 1518 .most_aligned_field = most_aligned_field, 1519 .most_aligned_field_size = most_aligned_field_size, 1520 .biggest_field = biggest_field, 1521 .payload_size = payload_size, 1522 .payload_align = payload_align, 1523 .tag_align = 0, 1524 .tag_size = 0, 1525 .padding = 0, 1526 }; 1527 } 1528 // Put the tag before or after the payload depending on which one's 1529 // alignment is greater. 1530 const tag_size = u.tag_ty.abiSize(mod); 1531 const tag_align = @max(1, u.tag_ty.abiAlignment(mod)); 1532 var size: u64 = 0; 1533 var padding: u32 = undefined; 1534 if (tag_align >= payload_align) { 1535 // {Tag, Payload} 1536 size += tag_size; 1537 size = std.mem.alignForwardGeneric(u64, size, payload_align); 1538 size += payload_size; 1539 const prev_size = size; 1540 size = std.mem.alignForwardGeneric(u64, size, tag_align); 1541 padding = @intCast(u32, size - prev_size); 1542 } else { 1543 // {Payload, Tag} 1544 size += payload_size; 1545 size = std.mem.alignForwardGeneric(u64, size, tag_align); 1546 size += tag_size; 1547 const prev_size = size; 1548 size = std.mem.alignForwardGeneric(u64, size, payload_align); 1549 padding = @intCast(u32, size - prev_size); 1550 } 1551 return .{ 1552 .abi_size = size, 1553 .abi_align = @max(tag_align, payload_align), 1554 .most_aligned_field = most_aligned_field, 1555 .most_aligned_field_size = most_aligned_field_size, 1556 .biggest_field = biggest_field, 1557 .payload_size = payload_size, 1558 .payload_align = payload_align, 1559 .tag_align = tag_align, 1560 .tag_size = tag_size, 1561 .padding = padding, 1562 }; 1563 } 1564 }; 1565 1566 pub const Opaque = struct { 1567 /// The Decl that corresponds to the opaque itself. 1568 owner_decl: Decl.Index, 1569 /// Represents the declarations inside this opaque. 1570 namespace: Namespace, 1571 1572 pub fn srcLoc(self: Opaque, mod: *Module) SrcLoc { 1573 const owner_decl = mod.declPtr(self.owner_decl); 1574 return .{ 1575 .file_scope = owner_decl.getFileScope(), 1576 .parent_decl_node = owner_decl.src_node, 1577 .lazy = LazySrcLoc.nodeOffset(0), 1578 }; 1579 } 1580 1581 pub fn getFullyQualifiedName(s: *Opaque, mod: *Module) ![:0]u8 { 1582 return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod); 1583 } 1584 }; 1585 1586 /// Some extern function struct memory is owned by the Decl's TypedValue.Managed 1587 /// arena allocator. 1588 pub const ExternFn = struct { 1589 /// The Decl that corresponds to the function itself. 1590 owner_decl: Decl.Index, 1591 /// Library name if specified. 1592 /// For example `extern "c" fn write(...) usize` would have 'c' as library name. 1593 /// Allocated with Module's allocator; outlives the ZIR code. 1594 lib_name: ?[*:0]const u8, 1595 1596 pub fn deinit(extern_fn: *ExternFn, gpa: Allocator) void { 1597 if (extern_fn.lib_name) |lib_name| { 1598 gpa.free(mem.sliceTo(lib_name, 0)); 1599 } 1600 } 1601 }; 1602 1603 /// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator. 1604 /// Extern functions do not have this data structure; they are represented by `ExternFn` 1605 /// instead. 1606 pub const Fn = struct { 1607 /// The Decl that corresponds to the function itself. 1608 owner_decl: Decl.Index, 1609 /// The ZIR instruction that is a function instruction. Use this to find 1610 /// the body. We store this rather than the body directly so that when ZIR 1611 /// is regenerated on update(), we can map this to the new corresponding 1612 /// ZIR instruction. 1613 zir_body_inst: Zir.Inst.Index, 1614 /// If this is not null, this function is a generic function instantiation, and 1615 /// there is a `TypedValue` here for each parameter of the function. 1616 /// Non-comptime parameters are marked with a `generic_poison` for the value. 1617 /// Non-anytype parameters are marked with a `generic_poison` for the type. 1618 /// These never have .generic_poison for the Type 1619 /// because the Type is needed to pass to `Type.eql` and for inserting comptime arguments 1620 /// into the inst_map when analyzing the body of a generic function instantiation. 1621 /// Instead, the is_anytype knowledge is communicated via `isAnytypeParam`. 1622 comptime_args: ?[*]TypedValue, 1623 1624 /// Precomputed hash for monomorphed_funcs. 1625 /// This is important because it may be accessed when resizing monomorphed_funcs 1626 /// while this Fn has already been added to the set, but does not have the 1627 /// owner_decl, comptime_args, or other fields populated yet. 1628 /// This field is undefined if comptime_args == null. 1629 hash: u64, 1630 1631 /// Relative to owner Decl. 1632 lbrace_line: u32, 1633 /// Relative to owner Decl. 1634 rbrace_line: u32, 1635 lbrace_column: u16, 1636 rbrace_column: u16, 1637 1638 /// When a generic function is instantiated, this value is inherited from the 1639 /// active Sema context. Importantly, this value is also updated when an existing 1640 /// generic function instantiation is found and called. 1641 branch_quota: u32, 1642 1643 /// If this is not none, this function is a generic function instantiation, and 1644 /// this is the generic function decl from which the instance was derived. 1645 /// This information is redundant with a combination of checking if comptime_args is 1646 /// not null and looking at the first decl dependency of owner_decl. This redundant 1647 /// information is useful for three reasons: 1648 /// 1. Improved perf of monomorphed_funcs when checking the eql() function because it 1649 /// can do two fewer pointer chases by grabbing the info from this field directly 1650 /// instead of accessing the decl and then the dependencies set. 1651 /// 2. While a generic function instantiation is being initialized, we need hash() 1652 /// and eql() to work before the initialization is complete. Completing the 1653 /// insertion into the decl dependency set has more fallible operations than simply 1654 /// setting this field. 1655 /// 3. I forgot what the third thing was while typing up the other two. 1656 generic_owner_decl: Decl.OptionalIndex, 1657 1658 state: Analysis, 1659 is_cold: bool = false, 1660 is_noinline: bool, 1661 calls_or_awaits_errorable_fn: bool = false, 1662 1663 /// Any inferred error sets that this function owns, both its own inferred error set and 1664 /// inferred error sets of any inline/comptime functions called. Not to be confused 1665 /// with inferred error sets of generic instantiations of this function, which are 1666 /// *not* tracked here - they are tracked in the new `Fn` object created for the 1667 /// instantiations. 1668 inferred_error_sets: InferredErrorSetList = .{}, 1669 1670 pub const Analysis = enum { 1671 /// This function has not yet undergone analysis, because we have not 1672 /// seen a potential runtime call. It may be analyzed in future. 1673 none, 1674 /// Analysis for this function has been queued, but not yet completed. 1675 queued, 1676 /// This function intentionally only has ZIR generated because it is marked 1677 /// inline, which means no runtime version of the function will be generated. 1678 inline_only, 1679 in_progress, 1680 /// There will be a corresponding ErrorMsg in Module.failed_decls 1681 sema_failure, 1682 /// This Fn might be OK but it depends on another Decl which did not 1683 /// successfully complete semantic analysis. 1684 dependency_failure, 1685 success, 1686 }; 1687 1688 /// This struct is used to keep track of any dependencies related to functions instances 1689 /// that return inferred error sets. Note that a function may be associated to 1690 /// multiple different error sets, for example an inferred error set which 1691 /// this function returns, but also any inferred error sets of called inline 1692 /// or comptime functions. 1693 pub const InferredErrorSet = struct { 1694 /// The function from which this error set originates. 1695 func: *Fn, 1696 1697 /// All currently known errors that this error set contains. This includes 1698 /// direct additions via `return error.Foo;`, and possibly also errors that 1699 /// are returned from any dependent functions. When the inferred error set is 1700 /// fully resolved, this map contains all the errors that the function might return. 1701 errors: ErrorSet.NameMap = .{}, 1702 1703 /// Other inferred error sets which this inferred error set should include. 1704 inferred_error_sets: std.AutoArrayHashMapUnmanaged(*InferredErrorSet, void) = .{}, 1705 1706 /// Whether the function returned anyerror. This is true if either of 1707 /// the dependent functions returns anyerror. 1708 is_anyerror: bool = false, 1709 1710 /// Whether this error set is already fully resolved. If true, resolving 1711 /// can skip resolving any dependents of this inferred error set. 1712 is_resolved: bool = false, 1713 1714 pub fn addErrorSet(self: *InferredErrorSet, gpa: Allocator, err_set_ty: Type) !void { 1715 switch (err_set_ty.ip_index) { 1716 .anyerror_type => { 1717 self.is_anyerror = true; 1718 }, 1719 .none => switch (err_set_ty.tag()) { 1720 .error_set => { 1721 const names = err_set_ty.castTag(.error_set).?.data.names.keys(); 1722 for (names) |name| { 1723 try self.errors.put(gpa, name, {}); 1724 } 1725 }, 1726 .error_set_single => { 1727 const name = err_set_ty.castTag(.error_set_single).?.data; 1728 try self.errors.put(gpa, name, {}); 1729 }, 1730 .error_set_inferred => { 1731 const ies = err_set_ty.castTag(.error_set_inferred).?.data; 1732 try self.inferred_error_sets.put(gpa, ies, {}); 1733 }, 1734 .error_set_merged => { 1735 const names = err_set_ty.castTag(.error_set_merged).?.data.keys(); 1736 for (names) |name| { 1737 try self.errors.put(gpa, name, {}); 1738 } 1739 }, 1740 else => unreachable, 1741 }, 1742 else => @panic("TODO"), 1743 } 1744 } 1745 }; 1746 1747 pub const InferredErrorSetList = std.SinglyLinkedList(InferredErrorSet); 1748 pub const InferredErrorSetListNode = InferredErrorSetList.Node; 1749 1750 pub fn deinit(func: *Fn, gpa: Allocator) void { 1751 var it = func.inferred_error_sets.first; 1752 while (it) |node| { 1753 const next = node.next; 1754 node.data.errors.deinit(gpa); 1755 node.data.inferred_error_sets.deinit(gpa); 1756 gpa.destroy(node); 1757 it = next; 1758 } 1759 } 1760 1761 pub fn isAnytypeParam(func: Fn, mod: *Module, index: u32) bool { 1762 const file = mod.declPtr(func.owner_decl).getFileScope(); 1763 1764 const tags = file.zir.instructions.items(.tag); 1765 1766 const param_body = file.zir.getParamBody(func.zir_body_inst); 1767 const param = param_body[index]; 1768 1769 return switch (tags[param]) { 1770 .param, .param_comptime => false, 1771 .param_anytype, .param_anytype_comptime => true, 1772 else => unreachable, 1773 }; 1774 } 1775 1776 pub fn getParamName(func: Fn, mod: *Module, index: u32) [:0]const u8 { 1777 const file = mod.declPtr(func.owner_decl).getFileScope(); 1778 1779 const tags = file.zir.instructions.items(.tag); 1780 const data = file.zir.instructions.items(.data); 1781 1782 const param_body = file.zir.getParamBody(func.zir_body_inst); 1783 const param = param_body[index]; 1784 1785 return switch (tags[param]) { 1786 .param, .param_comptime => blk: { 1787 const extra = file.zir.extraData(Zir.Inst.Param, data[param].pl_tok.payload_index); 1788 break :blk file.zir.nullTerminatedString(extra.data.name); 1789 }, 1790 .param_anytype, .param_anytype_comptime => blk: { 1791 const param_data = data[param].str_tok; 1792 break :blk param_data.get(file.zir); 1793 }, 1794 else => unreachable, 1795 }; 1796 } 1797 1798 pub fn hasInferredErrorSet(func: Fn, mod: *Module) bool { 1799 const owner_decl = mod.declPtr(func.owner_decl); 1800 const zir = owner_decl.getFileScope().zir; 1801 const zir_tags = zir.instructions.items(.tag); 1802 switch (zir_tags[func.zir_body_inst]) { 1803 .func => return false, 1804 .func_inferred => return true, 1805 .func_fancy => { 1806 const inst_data = zir.instructions.items(.data)[func.zir_body_inst].pl_node; 1807 const extra = zir.extraData(Zir.Inst.FuncFancy, inst_data.payload_index); 1808 return extra.data.bits.is_inferred_error; 1809 }, 1810 else => unreachable, 1811 } 1812 } 1813 }; 1814 1815 pub const Var = struct { 1816 /// if is_extern == true this is undefined 1817 init: Value, 1818 owner_decl: Decl.Index, 1819 1820 /// Library name if specified. 1821 /// For example `extern "c" var stderrp = ...` would have 'c' as library name. 1822 /// Allocated with Module's allocator; outlives the ZIR code. 1823 lib_name: ?[*:0]const u8, 1824 1825 is_extern: bool, 1826 is_mutable: bool, 1827 is_threadlocal: bool, 1828 is_weak_linkage: bool, 1829 1830 pub fn deinit(variable: *Var, gpa: Allocator) void { 1831 if (variable.lib_name) |lib_name| { 1832 gpa.free(mem.sliceTo(lib_name, 0)); 1833 } 1834 } 1835 }; 1836 1837 pub const DeclAdapter = struct { 1838 mod: *Module, 1839 1840 pub fn hash(self: @This(), s: []const u8) u32 { 1841 _ = self; 1842 return @truncate(u32, std.hash.Wyhash.hash(0, s)); 1843 } 1844 1845 pub fn eql(self: @This(), a: []const u8, b_decl_index: Decl.Index, b_index: usize) bool { 1846 _ = b_index; 1847 const b_decl = self.mod.declPtr(b_decl_index); 1848 return mem.eql(u8, a, mem.sliceTo(b_decl.name, 0)); 1849 } 1850 }; 1851 1852 /// The container that structs, enums, unions, and opaques have. 1853 pub const Namespace = struct { 1854 parent: ?*Namespace, 1855 file_scope: *File, 1856 /// Will be a struct, enum, union, or opaque. 1857 ty: Type, 1858 /// Direct children of the namespace. Used during an update to detect 1859 /// which decls have been added/removed from source. 1860 /// Declaration order is preserved via entry order. 1861 /// Key memory is owned by `decl.name`. 1862 /// Anonymous decls are not stored here; they are kept in `anon_decls` instead. 1863 decls: std.ArrayHashMapUnmanaged(Decl.Index, void, DeclContext, true) = .{}, 1864 1865 anon_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{}, 1866 1867 /// Key is usingnamespace Decl itself. To find the namespace being included, 1868 /// the Decl Value has to be resolved as a Type which has a Namespace. 1869 /// Value is whether the usingnamespace decl is marked `pub`. 1870 usingnamespace_set: std.AutoHashMapUnmanaged(Decl.Index, bool) = .{}, 1871 1872 const DeclContext = struct { 1873 module: *Module, 1874 1875 pub fn hash(ctx: @This(), decl_index: Decl.Index) u32 { 1876 const decl = ctx.module.declPtr(decl_index); 1877 return @truncate(u32, std.hash.Wyhash.hash(0, mem.sliceTo(decl.name, 0))); 1878 } 1879 1880 pub fn eql(ctx: @This(), a_decl_index: Decl.Index, b_decl_index: Decl.Index, b_index: usize) bool { 1881 _ = b_index; 1882 const a_decl = ctx.module.declPtr(a_decl_index); 1883 const b_decl = ctx.module.declPtr(b_decl_index); 1884 const a_name = mem.sliceTo(a_decl.name, 0); 1885 const b_name = mem.sliceTo(b_decl.name, 0); 1886 return mem.eql(u8, a_name, b_name); 1887 } 1888 }; 1889 1890 pub fn deinit(ns: *Namespace, mod: *Module) void { 1891 ns.destroyDecls(mod); 1892 ns.* = undefined; 1893 } 1894 1895 pub fn destroyDecls(ns: *Namespace, mod: *Module) void { 1896 const gpa = mod.gpa; 1897 1898 log.debug("destroyDecls {*}", .{ns}); 1899 1900 var decls = ns.decls; 1901 ns.decls = .{}; 1902 1903 var anon_decls = ns.anon_decls; 1904 ns.anon_decls = .{}; 1905 1906 for (decls.keys()) |decl_index| { 1907 mod.destroyDecl(decl_index); 1908 } 1909 decls.deinit(gpa); 1910 1911 for (anon_decls.keys()) |key| { 1912 mod.destroyDecl(key); 1913 } 1914 anon_decls.deinit(gpa); 1915 ns.usingnamespace_set.deinit(gpa); 1916 } 1917 1918 pub fn deleteAllDecls( 1919 ns: *Namespace, 1920 mod: *Module, 1921 outdated_decls: ?*std.AutoArrayHashMap(Decl.Index, void), 1922 ) !void { 1923 const gpa = mod.gpa; 1924 1925 log.debug("deleteAllDecls {*}", .{ns}); 1926 1927 var decls = ns.decls; 1928 ns.decls = .{}; 1929 1930 var anon_decls = ns.anon_decls; 1931 ns.anon_decls = .{}; 1932 1933 // TODO rework this code to not panic on OOM. 1934 // (might want to coordinate with the clearDecl function) 1935 1936 for (decls.keys()) |child_decl| { 1937 mod.clearDecl(child_decl, outdated_decls) catch @panic("out of memory"); 1938 mod.destroyDecl(child_decl); 1939 } 1940 decls.deinit(gpa); 1941 1942 for (anon_decls.keys()) |child_decl| { 1943 mod.clearDecl(child_decl, outdated_decls) catch @panic("out of memory"); 1944 mod.destroyDecl(child_decl); 1945 } 1946 anon_decls.deinit(gpa); 1947 1948 ns.usingnamespace_set.deinit(gpa); 1949 } 1950 1951 // This renders e.g. "std.fs.Dir.OpenOptions" 1952 pub fn renderFullyQualifiedName( 1953 ns: Namespace, 1954 mod: *Module, 1955 name: []const u8, 1956 writer: anytype, 1957 ) @TypeOf(writer).Error!void { 1958 if (ns.parent) |parent| { 1959 const decl_index = ns.getDeclIndex(); 1960 const decl = mod.declPtr(decl_index); 1961 try parent.renderFullyQualifiedName(mod, mem.sliceTo(decl.name, 0), writer); 1962 } else { 1963 try ns.file_scope.renderFullyQualifiedName(writer); 1964 } 1965 if (name.len != 0) { 1966 try writer.writeAll("."); 1967 try writer.writeAll(name); 1968 } 1969 } 1970 1971 /// This renders e.g. "std/fs.zig:Dir.OpenOptions" 1972 pub fn renderFullyQualifiedDebugName( 1973 ns: Namespace, 1974 mod: *Module, 1975 name: []const u8, 1976 writer: anytype, 1977 ) @TypeOf(writer).Error!void { 1978 var separator_char: u8 = '.'; 1979 if (ns.parent) |parent| { 1980 const decl_index = ns.getDeclIndex(); 1981 const decl = mod.declPtr(decl_index); 1982 try parent.renderFullyQualifiedDebugName(mod, mem.sliceTo(decl.name, 0), writer); 1983 } else { 1984 try ns.file_scope.renderFullyQualifiedDebugName(writer); 1985 separator_char = ':'; 1986 } 1987 if (name.len != 0) { 1988 try writer.writeByte(separator_char); 1989 try writer.writeAll(name); 1990 } 1991 } 1992 1993 pub fn getDeclIndex(ns: Namespace) Decl.Index { 1994 return ns.ty.getOwnerDecl(); 1995 } 1996 }; 1997 1998 pub const File = struct { 1999 /// The Decl of the struct that represents this File. 2000 root_decl: Decl.OptionalIndex, 2001 status: enum { 2002 never_loaded, 2003 retryable_failure, 2004 parse_failure, 2005 astgen_failure, 2006 success_zir, 2007 }, 2008 source_loaded: bool, 2009 tree_loaded: bool, 2010 zir_loaded: bool, 2011 /// Relative to the owning package's root_src_dir. 2012 /// Memory is stored in gpa, owned by File. 2013 sub_file_path: []const u8, 2014 /// Whether this is populated depends on `source_loaded`. 2015 source: [:0]const u8, 2016 /// Whether this is populated depends on `status`. 2017 stat: Cache.File.Stat, 2018 /// Whether this is populated or not depends on `tree_loaded`. 2019 tree: Ast, 2020 /// Whether this is populated or not depends on `zir_loaded`. 2021 zir: Zir, 2022 /// Package that this file is a part of, managed externally. 2023 pkg: *Package, 2024 /// Whether this file is a part of multiple packages. This is an error condition which will be reported after AstGen. 2025 multi_pkg: bool = false, 2026 /// List of references to this file, used for multi-package errors. 2027 references: std.ArrayListUnmanaged(Reference) = .{}, 2028 2029 /// Used by change detection algorithm, after astgen, contains the 2030 /// set of decls that existed in the previous ZIR but not in the new one. 2031 deleted_decls: ArrayListUnmanaged(Decl.Index) = .{}, 2032 /// Used by change detection algorithm, after astgen, contains the 2033 /// set of decls that existed both in the previous ZIR and in the new one, 2034 /// but their source code has been modified. 2035 outdated_decls: ArrayListUnmanaged(Decl.Index) = .{}, 2036 2037 /// The most recent successful ZIR for this file, with no errors. 2038 /// This is only populated when a previously successful ZIR 2039 /// newly introduces compile errors during an update. When ZIR is 2040 /// successful, this field is unloaded. 2041 prev_zir: ?*Zir = null, 2042 2043 /// A single reference to a file. 2044 pub const Reference = union(enum) { 2045 /// The file is imported directly (i.e. not as a package) with @import. 2046 import: SrcLoc, 2047 /// The file is the root of a package. 2048 root: *Package, 2049 }; 2050 2051 pub fn unload(file: *File, gpa: Allocator) void { 2052 file.unloadTree(gpa); 2053 file.unloadSource(gpa); 2054 file.unloadZir(gpa); 2055 } 2056 2057 pub fn unloadTree(file: *File, gpa: Allocator) void { 2058 if (file.tree_loaded) { 2059 file.tree_loaded = false; 2060 file.tree.deinit(gpa); 2061 } 2062 } 2063 2064 pub fn unloadSource(file: *File, gpa: Allocator) void { 2065 if (file.source_loaded) { 2066 file.source_loaded = false; 2067 gpa.free(file.source); 2068 } 2069 } 2070 2071 pub fn unloadZir(file: *File, gpa: Allocator) void { 2072 if (file.zir_loaded) { 2073 file.zir_loaded = false; 2074 file.zir.deinit(gpa); 2075 } 2076 } 2077 2078 pub fn deinit(file: *File, mod: *Module) void { 2079 const gpa = mod.gpa; 2080 log.debug("deinit File {s}", .{file.sub_file_path}); 2081 file.deleted_decls.deinit(gpa); 2082 file.outdated_decls.deinit(gpa); 2083 file.references.deinit(gpa); 2084 if (file.root_decl.unwrap()) |root_decl| { 2085 mod.destroyDecl(root_decl); 2086 } 2087 gpa.free(file.sub_file_path); 2088 file.unload(gpa); 2089 if (file.prev_zir) |prev_zir| { 2090 prev_zir.deinit(gpa); 2091 gpa.destroy(prev_zir); 2092 } 2093 file.* = undefined; 2094 } 2095 2096 pub const Source = struct { 2097 bytes: [:0]const u8, 2098 stat: Cache.File.Stat, 2099 }; 2100 2101 pub fn getSource(file: *File, gpa: Allocator) !Source { 2102 if (file.source_loaded) return Source{ 2103 .bytes = file.source, 2104 .stat = file.stat, 2105 }; 2106 2107 const root_dir_path = file.pkg.root_src_directory.path orelse "."; 2108 log.debug("File.getSource, not cached. pkgdir={s} sub_file_path={s}", .{ 2109 root_dir_path, file.sub_file_path, 2110 }); 2111 2112 // Keep track of inode, file size, mtime, hash so we can detect which files 2113 // have been modified when an incremental update is requested. 2114 var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{}); 2115 defer f.close(); 2116 2117 const stat = try f.stat(); 2118 2119 if (stat.size > std.math.maxInt(u32)) 2120 return error.FileTooBig; 2121 2122 const source = try gpa.allocSentinel(u8, @intCast(usize, stat.size), 0); 2123 defer if (!file.source_loaded) gpa.free(source); 2124 const amt = try f.readAll(source); 2125 if (amt != stat.size) 2126 return error.UnexpectedEndOfFile; 2127 2128 // Here we do not modify stat fields because this function is the one 2129 // used for error reporting. We need to keep the stat fields stale so that 2130 // astGenFile can know to regenerate ZIR. 2131 2132 file.source = source; 2133 file.source_loaded = true; 2134 return Source{ 2135 .bytes = source, 2136 .stat = .{ 2137 .size = stat.size, 2138 .inode = stat.inode, 2139 .mtime = stat.mtime, 2140 }, 2141 }; 2142 } 2143 2144 pub fn getTree(file: *File, gpa: Allocator) !*const Ast { 2145 if (file.tree_loaded) return &file.tree; 2146 2147 const source = try file.getSource(gpa); 2148 file.tree = try Ast.parse(gpa, source.bytes, .zig); 2149 file.tree_loaded = true; 2150 return &file.tree; 2151 } 2152 2153 pub fn destroy(file: *File, mod: *Module) void { 2154 const gpa = mod.gpa; 2155 file.deinit(mod); 2156 gpa.destroy(file); 2157 } 2158 2159 pub fn renderFullyQualifiedName(file: File, writer: anytype) !void { 2160 // Convert all the slashes into dots and truncate the extension. 2161 const ext = std.fs.path.extension(file.sub_file_path); 2162 const noext = file.sub_file_path[0 .. file.sub_file_path.len - ext.len]; 2163 for (noext) |byte| switch (byte) { 2164 '/', '\\' => try writer.writeByte('.'), 2165 else => try writer.writeByte(byte), 2166 }; 2167 } 2168 2169 pub fn renderFullyQualifiedDebugName(file: File, writer: anytype) !void { 2170 for (file.sub_file_path) |byte| switch (byte) { 2171 '/', '\\' => try writer.writeByte('/'), 2172 else => try writer.writeByte(byte), 2173 }; 2174 } 2175 2176 pub fn fullyQualifiedNameZ(file: File, gpa: Allocator) ![:0]u8 { 2177 var buf = std.ArrayList(u8).init(gpa); 2178 defer buf.deinit(); 2179 try file.renderFullyQualifiedName(buf.writer()); 2180 return buf.toOwnedSliceSentinel(0); 2181 } 2182 2183 /// Returns the full path to this file relative to its package. 2184 pub fn fullPath(file: File, ally: Allocator) ![]u8 { 2185 return file.pkg.root_src_directory.join(ally, &[_][]const u8{file.sub_file_path}); 2186 } 2187 2188 /// Returns the full path to this file relative to its package. 2189 pub fn fullPathZ(file: File, ally: Allocator) ![:0]u8 { 2190 return file.pkg.root_src_directory.joinZ(ally, &[_][]const u8{file.sub_file_path}); 2191 } 2192 2193 pub fn dumpSrc(file: *File, src: LazySrcLoc) void { 2194 const loc = std.zig.findLineColumn(file.source.bytes, src); 2195 std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 }); 2196 } 2197 2198 pub fn okToReportErrors(file: File) bool { 2199 return switch (file.status) { 2200 .parse_failure, .astgen_failure => false, 2201 else => true, 2202 }; 2203 } 2204 2205 /// Add a reference to this file during AstGen. 2206 pub fn addReference(file: *File, mod: Module, ref: Reference) !void { 2207 // Don't add the same module root twice. Note that since we always add module roots at the 2208 // front of the references array (see below), this loop is actually O(1) on valid code. 2209 if (ref == .root) { 2210 for (file.references.items) |other| { 2211 switch (other) { 2212 .root => |r| if (ref.root == r) return, 2213 else => break, // reached the end of the "is-root" references 2214 } 2215 } 2216 } 2217 2218 switch (ref) { 2219 // We put root references at the front of the list both to make the above loop fast and 2220 // to make multi-module errors more helpful (since "root-of" notes are generally more 2221 // informative than "imported-from" notes). This path is hit very rarely, so the speed 2222 // of the insert operation doesn't matter too much. 2223 .root => try file.references.insert(mod.gpa, 0, ref), 2224 2225 // Other references we'll just put at the end. 2226 else => try file.references.append(mod.gpa, ref), 2227 } 2228 2229 const pkg = switch (ref) { 2230 .import => |loc| loc.file_scope.pkg, 2231 .root => |pkg| pkg, 2232 }; 2233 if (pkg != file.pkg) file.multi_pkg = true; 2234 } 2235 2236 /// Mark this file and every file referenced by it as multi_pkg and report an 2237 /// astgen_failure error for them. AstGen must have completed in its entirety. 2238 pub fn recursiveMarkMultiPkg(file: *File, mod: *Module) void { 2239 file.multi_pkg = true; 2240 file.status = .astgen_failure; 2241 2242 // We can only mark children as failed if the ZIR is loaded, which may not 2243 // be the case if there were other astgen failures in this file 2244 if (!file.zir_loaded) return; 2245 2246 const imports_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.imports)]; 2247 if (imports_index == 0) return; 2248 const extra = file.zir.extraData(Zir.Inst.Imports, imports_index); 2249 2250 var import_i: u32 = 0; 2251 var extra_index = extra.end; 2252 while (import_i < extra.data.imports_len) : (import_i += 1) { 2253 const item = file.zir.extraData(Zir.Inst.Imports.Item, extra_index); 2254 extra_index = item.end; 2255 2256 const import_path = file.zir.nullTerminatedString(item.data.name); 2257 if (mem.eql(u8, import_path, "builtin")) continue; 2258 2259 const res = mod.importFile(file, import_path) catch continue; 2260 if (!res.is_pkg and !res.file.multi_pkg) { 2261 res.file.recursiveMarkMultiPkg(mod); 2262 } 2263 } 2264 } 2265 }; 2266 2267 /// Represents the contents of a file loaded with `@embedFile`. 2268 pub const EmbedFile = struct { 2269 /// Relative to the owning package's root_src_dir. 2270 /// Memory is stored in gpa, owned by EmbedFile. 2271 sub_file_path: []const u8, 2272 bytes: [:0]const u8, 2273 stat: Cache.File.Stat, 2274 /// Package that this file is a part of, managed externally. 2275 pkg: *Package, 2276 /// The Decl that was created from the `@embedFile` to own this resource. 2277 /// This is how zig knows what other Decl objects to invalidate if the file 2278 /// changes on disk. 2279 owner_decl: Decl.Index, 2280 2281 fn destroy(embed_file: *EmbedFile, mod: *Module) void { 2282 const gpa = mod.gpa; 2283 gpa.free(embed_file.sub_file_path); 2284 gpa.free(embed_file.bytes); 2285 gpa.destroy(embed_file); 2286 } 2287 }; 2288 2289 /// This struct holds data necessary to construct API-facing `AllErrors.Message`. 2290 /// Its memory is managed with the general purpose allocator so that they 2291 /// can be created and destroyed in response to incremental updates. 2292 /// In some cases, the File could have been inferred from where the ErrorMsg 2293 /// is stored. For example, if it is stored in Module.failed_decls, then the File 2294 /// would be determined by the Decl Scope. However, the data structure contains the field 2295 /// anyway so that `ErrorMsg` can be reused for error notes, which may be in a different 2296 /// file than the parent error message. It also simplifies processing of error messages. 2297 pub const ErrorMsg = struct { 2298 src_loc: SrcLoc, 2299 msg: []const u8, 2300 notes: []ErrorMsg = &.{}, 2301 reference_trace: []Trace = &.{}, 2302 2303 pub const Trace = struct { 2304 decl: ?[*:0]const u8, 2305 src_loc: SrcLoc, 2306 hidden: u32 = 0, 2307 }; 2308 2309 pub fn create( 2310 gpa: Allocator, 2311 src_loc: SrcLoc, 2312 comptime format: []const u8, 2313 args: anytype, 2314 ) !*ErrorMsg { 2315 const err_msg = try gpa.create(ErrorMsg); 2316 errdefer gpa.destroy(err_msg); 2317 err_msg.* = try ErrorMsg.init(gpa, src_loc, format, args); 2318 return err_msg; 2319 } 2320 2321 /// Assumes the ErrorMsg struct and msg were both allocated with `gpa`, 2322 /// as well as all notes. 2323 pub fn destroy(err_msg: *ErrorMsg, gpa: Allocator) void { 2324 err_msg.deinit(gpa); 2325 gpa.destroy(err_msg); 2326 } 2327 2328 pub fn init( 2329 gpa: Allocator, 2330 src_loc: SrcLoc, 2331 comptime format: []const u8, 2332 args: anytype, 2333 ) !ErrorMsg { 2334 return ErrorMsg{ 2335 .src_loc = src_loc, 2336 .msg = try std.fmt.allocPrint(gpa, format, args), 2337 }; 2338 } 2339 2340 pub fn deinit(err_msg: *ErrorMsg, gpa: Allocator) void { 2341 for (err_msg.notes) |*note| { 2342 note.deinit(gpa); 2343 } 2344 gpa.free(err_msg.notes); 2345 gpa.free(err_msg.msg); 2346 gpa.free(err_msg.reference_trace); 2347 err_msg.* = undefined; 2348 } 2349 2350 pub fn clearTrace(err_msg: *ErrorMsg, gpa: Allocator) void { 2351 if (err_msg.reference_trace.len == 0) return; 2352 gpa.free(err_msg.reference_trace); 2353 err_msg.reference_trace = &.{}; 2354 } 2355 }; 2356 2357 /// Canonical reference to a position within a source file. 2358 pub const SrcLoc = struct { 2359 file_scope: *File, 2360 /// Might be 0 depending on tag of `lazy`. 2361 parent_decl_node: Ast.Node.Index, 2362 /// Relative to `parent_decl_node`. 2363 lazy: LazySrcLoc, 2364 2365 pub fn declSrcToken(src_loc: SrcLoc) Ast.TokenIndex { 2366 const tree = src_loc.file_scope.tree; 2367 return tree.firstToken(src_loc.parent_decl_node); 2368 } 2369 2370 pub fn declRelativeToNodeIndex(src_loc: SrcLoc, offset: i32) Ast.TokenIndex { 2371 return @bitCast(Ast.Node.Index, offset + @bitCast(i32, src_loc.parent_decl_node)); 2372 } 2373 2374 pub const Span = struct { 2375 start: u32, 2376 end: u32, 2377 main: u32, 2378 }; 2379 2380 pub fn span(src_loc: SrcLoc, gpa: Allocator) !Span { 2381 switch (src_loc.lazy) { 2382 .unneeded => unreachable, 2383 .entire_file => return Span{ .start = 0, .end = 1, .main = 0 }, 2384 2385 .byte_abs => |byte_index| return Span{ .start = byte_index, .end = byte_index + 1, .main = byte_index }, 2386 2387 .token_abs => |tok_index| { 2388 const tree = try src_loc.file_scope.getTree(gpa); 2389 const start = tree.tokens.items(.start)[tok_index]; 2390 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len); 2391 return Span{ .start = start, .end = end, .main = start }; 2392 }, 2393 .node_abs => |node| { 2394 const tree = try src_loc.file_scope.getTree(gpa); 2395 return nodeToSpan(tree, node); 2396 }, 2397 .byte_offset => |byte_off| { 2398 const tree = try src_loc.file_scope.getTree(gpa); 2399 const tok_index = src_loc.declSrcToken(); 2400 const start = tree.tokens.items(.start)[tok_index] + byte_off; 2401 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len); 2402 return Span{ .start = start, .end = end, .main = start }; 2403 }, 2404 .token_offset => |tok_off| { 2405 const tree = try src_loc.file_scope.getTree(gpa); 2406 const tok_index = src_loc.declSrcToken() + tok_off; 2407 const start = tree.tokens.items(.start)[tok_index]; 2408 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len); 2409 return Span{ .start = start, .end = end, .main = start }; 2410 }, 2411 .node_offset => |traced_off| { 2412 const node_off = traced_off.x; 2413 const tree = try src_loc.file_scope.getTree(gpa); 2414 const node = src_loc.declRelativeToNodeIndex(node_off); 2415 assert(src_loc.file_scope.tree_loaded); 2416 return nodeToSpan(tree, node); 2417 }, 2418 .node_offset_main_token => |node_off| { 2419 const tree = try src_loc.file_scope.getTree(gpa); 2420 const node = src_loc.declRelativeToNodeIndex(node_off); 2421 const main_token = tree.nodes.items(.main_token)[node]; 2422 return tokensToSpan(tree, main_token, main_token, main_token); 2423 }, 2424 .node_offset_bin_op => |node_off| { 2425 const tree = try src_loc.file_scope.getTree(gpa); 2426 const node = src_loc.declRelativeToNodeIndex(node_off); 2427 assert(src_loc.file_scope.tree_loaded); 2428 return nodeToSpan(tree, node); 2429 }, 2430 .node_offset_initializer => |node_off| { 2431 const tree = try src_loc.file_scope.getTree(gpa); 2432 const node = src_loc.declRelativeToNodeIndex(node_off); 2433 return tokensToSpan( 2434 tree, 2435 tree.firstToken(node) - 3, 2436 tree.lastToken(node), 2437 tree.nodes.items(.main_token)[node] - 2, 2438 ); 2439 }, 2440 .node_offset_var_decl_ty => |node_off| { 2441 const tree = try src_loc.file_scope.getTree(gpa); 2442 const node = src_loc.declRelativeToNodeIndex(node_off); 2443 const node_tags = tree.nodes.items(.tag); 2444 const full = switch (node_tags[node]) { 2445 .global_var_decl, 2446 .local_var_decl, 2447 .simple_var_decl, 2448 .aligned_var_decl, 2449 => tree.fullVarDecl(node).?, 2450 .@"usingnamespace" => { 2451 const node_data = tree.nodes.items(.data); 2452 return nodeToSpan(tree, node_data[node].lhs); 2453 }, 2454 else => unreachable, 2455 }; 2456 if (full.ast.type_node != 0) { 2457 return nodeToSpan(tree, full.ast.type_node); 2458 } 2459 const tok_index = full.ast.mut_token + 1; // the name token 2460 const start = tree.tokens.items(.start)[tok_index]; 2461 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len); 2462 return Span{ .start = start, .end = end, .main = start }; 2463 }, 2464 .node_offset_var_decl_align => |node_off| { 2465 const tree = try src_loc.file_scope.getTree(gpa); 2466 const node = src_loc.declRelativeToNodeIndex(node_off); 2467 const full = tree.fullVarDecl(node).?; 2468 return nodeToSpan(tree, full.ast.align_node); 2469 }, 2470 .node_offset_var_decl_section => |node_off| { 2471 const tree = try src_loc.file_scope.getTree(gpa); 2472 const node = src_loc.declRelativeToNodeIndex(node_off); 2473 const full = tree.fullVarDecl(node).?; 2474 return nodeToSpan(tree, full.ast.section_node); 2475 }, 2476 .node_offset_var_decl_addrspace => |node_off| { 2477 const tree = try src_loc.file_scope.getTree(gpa); 2478 const node = src_loc.declRelativeToNodeIndex(node_off); 2479 const full = tree.fullVarDecl(node).?; 2480 return nodeToSpan(tree, full.ast.addrspace_node); 2481 }, 2482 .node_offset_var_decl_init => |node_off| { 2483 const tree = try src_loc.file_scope.getTree(gpa); 2484 const node = src_loc.declRelativeToNodeIndex(node_off); 2485 const full = tree.fullVarDecl(node).?; 2486 return nodeToSpan(tree, full.ast.init_node); 2487 }, 2488 .node_offset_builtin_call_arg0 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 0), 2489 .node_offset_builtin_call_arg1 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 1), 2490 .node_offset_builtin_call_arg2 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 2), 2491 .node_offset_builtin_call_arg3 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 3), 2492 .node_offset_builtin_call_arg4 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 4), 2493 .node_offset_builtin_call_arg5 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 5), 2494 .node_offset_array_access_index => |node_off| { 2495 const tree = try src_loc.file_scope.getTree(gpa); 2496 const node_datas = tree.nodes.items(.data); 2497 const node = src_loc.declRelativeToNodeIndex(node_off); 2498 return nodeToSpan(tree, node_datas[node].rhs); 2499 }, 2500 .node_offset_slice_ptr, 2501 .node_offset_slice_start, 2502 .node_offset_slice_end, 2503 .node_offset_slice_sentinel, 2504 => |node_off| { 2505 const tree = try src_loc.file_scope.getTree(gpa); 2506 const node = src_loc.declRelativeToNodeIndex(node_off); 2507 const full = tree.fullSlice(node).?; 2508 const part_node = switch (src_loc.lazy) { 2509 .node_offset_slice_ptr => full.ast.sliced, 2510 .node_offset_slice_start => full.ast.start, 2511 .node_offset_slice_end => full.ast.end, 2512 .node_offset_slice_sentinel => full.ast.sentinel, 2513 else => unreachable, 2514 }; 2515 return nodeToSpan(tree, part_node); 2516 }, 2517 .node_offset_call_func => |node_off| { 2518 const tree = try src_loc.file_scope.getTree(gpa); 2519 const node = src_loc.declRelativeToNodeIndex(node_off); 2520 var buf: [1]Ast.Node.Index = undefined; 2521 const full = tree.fullCall(&buf, node).?; 2522 return nodeToSpan(tree, full.ast.fn_expr); 2523 }, 2524 .node_offset_field_name => |node_off| { 2525 const tree = try src_loc.file_scope.getTree(gpa); 2526 const node_datas = tree.nodes.items(.data); 2527 const node_tags = tree.nodes.items(.tag); 2528 const node = src_loc.declRelativeToNodeIndex(node_off); 2529 var buf: [1]Ast.Node.Index = undefined; 2530 const tok_index = switch (node_tags[node]) { 2531 .field_access => node_datas[node].rhs, 2532 .call_one, 2533 .call_one_comma, 2534 .async_call_one, 2535 .async_call_one_comma, 2536 .call, 2537 .call_comma, 2538 .async_call, 2539 .async_call_comma, 2540 => blk: { 2541 const full = tree.fullCall(&buf, node).?; 2542 break :blk tree.lastToken(full.ast.fn_expr); 2543 }, 2544 else => tree.firstToken(node) - 2, 2545 }; 2546 const start = tree.tokens.items(.start)[tok_index]; 2547 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len); 2548 return Span{ .start = start, .end = end, .main = start }; 2549 }, 2550 .node_offset_deref_ptr => |node_off| { 2551 const tree = try src_loc.file_scope.getTree(gpa); 2552 const node = src_loc.declRelativeToNodeIndex(node_off); 2553 return nodeToSpan(tree, node); 2554 }, 2555 .node_offset_asm_source => |node_off| { 2556 const tree = try src_loc.file_scope.getTree(gpa); 2557 const node = src_loc.declRelativeToNodeIndex(node_off); 2558 const full = tree.fullAsm(node).?; 2559 return nodeToSpan(tree, full.ast.template); 2560 }, 2561 .node_offset_asm_ret_ty => |node_off| { 2562 const tree = try src_loc.file_scope.getTree(gpa); 2563 const node = src_loc.declRelativeToNodeIndex(node_off); 2564 const full = tree.fullAsm(node).?; 2565 const asm_output = full.outputs[0]; 2566 const node_datas = tree.nodes.items(.data); 2567 return nodeToSpan(tree, node_datas[asm_output].lhs); 2568 }, 2569 2570 .node_offset_if_cond => |node_off| { 2571 const tree = try src_loc.file_scope.getTree(gpa); 2572 const node = src_loc.declRelativeToNodeIndex(node_off); 2573 const node_tags = tree.nodes.items(.tag); 2574 const src_node = switch (node_tags[node]) { 2575 .if_simple, 2576 .@"if", 2577 => tree.fullIf(node).?.ast.cond_expr, 2578 2579 .while_simple, 2580 .while_cont, 2581 .@"while", 2582 => tree.fullWhile(node).?.ast.cond_expr, 2583 2584 .for_simple, 2585 .@"for", 2586 => { 2587 const inputs = tree.fullFor(node).?.ast.inputs; 2588 const start = tree.firstToken(inputs[0]); 2589 const end = tree.lastToken(inputs[inputs.len - 1]); 2590 return tokensToSpan(tree, start, end, start); 2591 }, 2592 2593 .@"orelse" => node, 2594 .@"catch" => node, 2595 else => unreachable, 2596 }; 2597 return nodeToSpan(tree, src_node); 2598 }, 2599 .for_input => |for_input| { 2600 const tree = try src_loc.file_scope.getTree(gpa); 2601 const node = src_loc.declRelativeToNodeIndex(for_input.for_node_offset); 2602 const for_full = tree.fullFor(node).?; 2603 const src_node = for_full.ast.inputs[for_input.input_index]; 2604 return nodeToSpan(tree, src_node); 2605 }, 2606 .for_capture_from_input => |node_off| { 2607 const tree = try src_loc.file_scope.getTree(gpa); 2608 const token_tags = tree.tokens.items(.tag); 2609 const input_node = src_loc.declRelativeToNodeIndex(node_off); 2610 // We have to actually linear scan the whole AST to find the for loop 2611 // that contains this input. 2612 const node_tags = tree.nodes.items(.tag); 2613 for (node_tags, 0..) |node_tag, node_usize| { 2614 const node = @intCast(Ast.Node.Index, node_usize); 2615 switch (node_tag) { 2616 .for_simple, .@"for" => { 2617 const for_full = tree.fullFor(node).?; 2618 for (for_full.ast.inputs, 0..) |input, input_index| { 2619 if (input_node == input) { 2620 var count = input_index; 2621 var tok = for_full.payload_token; 2622 while (true) { 2623 switch (token_tags[tok]) { 2624 .comma => { 2625 count -= 1; 2626 tok += 1; 2627 }, 2628 .identifier => { 2629 if (count == 0) 2630 return tokensToSpan(tree, tok, tok + 1, tok); 2631 tok += 1; 2632 }, 2633 .asterisk => { 2634 if (count == 0) 2635 return tokensToSpan(tree, tok, tok + 2, tok); 2636 tok += 1; 2637 }, 2638 else => unreachable, 2639 } 2640 } 2641 } 2642 } 2643 }, 2644 else => continue, 2645 } 2646 } else unreachable; 2647 }, 2648 .node_offset_bin_lhs => |node_off| { 2649 const tree = try src_loc.file_scope.getTree(gpa); 2650 const node = src_loc.declRelativeToNodeIndex(node_off); 2651 const node_datas = tree.nodes.items(.data); 2652 return nodeToSpan(tree, node_datas[node].lhs); 2653 }, 2654 .node_offset_bin_rhs => |node_off| { 2655 const tree = try src_loc.file_scope.getTree(gpa); 2656 const node = src_loc.declRelativeToNodeIndex(node_off); 2657 const node_datas = tree.nodes.items(.data); 2658 return nodeToSpan(tree, node_datas[node].rhs); 2659 }, 2660 2661 .node_offset_switch_operand => |node_off| { 2662 const tree = try src_loc.file_scope.getTree(gpa); 2663 const node = src_loc.declRelativeToNodeIndex(node_off); 2664 const node_datas = tree.nodes.items(.data); 2665 return nodeToSpan(tree, node_datas[node].lhs); 2666 }, 2667 2668 .node_offset_switch_special_prong => |node_off| { 2669 const tree = try src_loc.file_scope.getTree(gpa); 2670 const switch_node = src_loc.declRelativeToNodeIndex(node_off); 2671 const node_datas = tree.nodes.items(.data); 2672 const node_tags = tree.nodes.items(.tag); 2673 const main_tokens = tree.nodes.items(.main_token); 2674 const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange); 2675 const case_nodes = tree.extra_data[extra.start..extra.end]; 2676 for (case_nodes) |case_node| { 2677 const case = tree.fullSwitchCase(case_node).?; 2678 const is_special = (case.ast.values.len == 0) or 2679 (case.ast.values.len == 1 and 2680 node_tags[case.ast.values[0]] == .identifier and 2681 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_")); 2682 if (!is_special) continue; 2683 2684 return nodeToSpan(tree, case_node); 2685 } else unreachable; 2686 }, 2687 2688 .node_offset_switch_range => |node_off| { 2689 const tree = try src_loc.file_scope.getTree(gpa); 2690 const switch_node = src_loc.declRelativeToNodeIndex(node_off); 2691 const node_datas = tree.nodes.items(.data); 2692 const node_tags = tree.nodes.items(.tag); 2693 const main_tokens = tree.nodes.items(.main_token); 2694 const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange); 2695 const case_nodes = tree.extra_data[extra.start..extra.end]; 2696 for (case_nodes) |case_node| { 2697 const case = tree.fullSwitchCase(case_node).?; 2698 const is_special = (case.ast.values.len == 0) or 2699 (case.ast.values.len == 1 and 2700 node_tags[case.ast.values[0]] == .identifier and 2701 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_")); 2702 if (is_special) continue; 2703 2704 for (case.ast.values) |item_node| { 2705 if (node_tags[item_node] == .switch_range) { 2706 return nodeToSpan(tree, item_node); 2707 } 2708 } 2709 } else unreachable; 2710 }, 2711 .node_offset_switch_prong_capture => |node_off| { 2712 const tree = try src_loc.file_scope.getTree(gpa); 2713 const case_node = src_loc.declRelativeToNodeIndex(node_off); 2714 const case = tree.fullSwitchCase(case_node).?; 2715 const start_tok = case.payload_token.?; 2716 const token_tags = tree.tokens.items(.tag); 2717 const end_tok = switch (token_tags[start_tok]) { 2718 .asterisk => start_tok + 1, 2719 else => start_tok, 2720 }; 2721 const start = tree.tokens.items(.start)[start_tok]; 2722 const end_start = tree.tokens.items(.start)[end_tok]; 2723 const end = end_start + @intCast(u32, tree.tokenSlice(end_tok).len); 2724 return Span{ .start = start, .end = end, .main = start }; 2725 }, 2726 .node_offset_fn_type_align => |node_off| { 2727 const tree = try src_loc.file_scope.getTree(gpa); 2728 const node = src_loc.declRelativeToNodeIndex(node_off); 2729 var buf: [1]Ast.Node.Index = undefined; 2730 const full = tree.fullFnProto(&buf, node).?; 2731 return nodeToSpan(tree, full.ast.align_expr); 2732 }, 2733 .node_offset_fn_type_addrspace => |node_off| { 2734 const tree = try src_loc.file_scope.getTree(gpa); 2735 const node = src_loc.declRelativeToNodeIndex(node_off); 2736 var buf: [1]Ast.Node.Index = undefined; 2737 const full = tree.fullFnProto(&buf, node).?; 2738 return nodeToSpan(tree, full.ast.addrspace_expr); 2739 }, 2740 .node_offset_fn_type_section => |node_off| { 2741 const tree = try src_loc.file_scope.getTree(gpa); 2742 const node = src_loc.declRelativeToNodeIndex(node_off); 2743 var buf: [1]Ast.Node.Index = undefined; 2744 const full = tree.fullFnProto(&buf, node).?; 2745 return nodeToSpan(tree, full.ast.section_expr); 2746 }, 2747 .node_offset_fn_type_cc => |node_off| { 2748 const tree = try src_loc.file_scope.getTree(gpa); 2749 const node = src_loc.declRelativeToNodeIndex(node_off); 2750 var buf: [1]Ast.Node.Index = undefined; 2751 const full = tree.fullFnProto(&buf, node).?; 2752 return nodeToSpan(tree, full.ast.callconv_expr); 2753 }, 2754 2755 .node_offset_fn_type_ret_ty => |node_off| { 2756 const tree = try src_loc.file_scope.getTree(gpa); 2757 const node = src_loc.declRelativeToNodeIndex(node_off); 2758 var buf: [1]Ast.Node.Index = undefined; 2759 const full = tree.fullFnProto(&buf, node).?; 2760 return nodeToSpan(tree, full.ast.return_type); 2761 }, 2762 .node_offset_param => |node_off| { 2763 const tree = try src_loc.file_scope.getTree(gpa); 2764 const token_tags = tree.tokens.items(.tag); 2765 const node = src_loc.declRelativeToNodeIndex(node_off); 2766 2767 var first_tok = tree.firstToken(node); 2768 while (true) switch (token_tags[first_tok - 1]) { 2769 .colon, .identifier, .keyword_comptime, .keyword_noalias => first_tok -= 1, 2770 else => break, 2771 }; 2772 return tokensToSpan( 2773 tree, 2774 first_tok, 2775 tree.lastToken(node), 2776 first_tok, 2777 ); 2778 }, 2779 .token_offset_param => |token_off| { 2780 const tree = try src_loc.file_scope.getTree(gpa); 2781 const token_tags = tree.tokens.items(.tag); 2782 const main_token = tree.nodes.items(.main_token)[src_loc.parent_decl_node]; 2783 const tok_index = @bitCast(Ast.TokenIndex, token_off + @bitCast(i32, main_token)); 2784 2785 var first_tok = tok_index; 2786 while (true) switch (token_tags[first_tok - 1]) { 2787 .colon, .identifier, .keyword_comptime, .keyword_noalias => first_tok -= 1, 2788 else => break, 2789 }; 2790 return tokensToSpan( 2791 tree, 2792 first_tok, 2793 tok_index, 2794 first_tok, 2795 ); 2796 }, 2797 2798 .node_offset_anyframe_type => |node_off| { 2799 const tree = try src_loc.file_scope.getTree(gpa); 2800 const node_datas = tree.nodes.items(.data); 2801 const parent_node = src_loc.declRelativeToNodeIndex(node_off); 2802 return nodeToSpan(tree, node_datas[parent_node].rhs); 2803 }, 2804 2805 .node_offset_lib_name => |node_off| { 2806 const tree = try src_loc.file_scope.getTree(gpa); 2807 const parent_node = src_loc.declRelativeToNodeIndex(node_off); 2808 var buf: [1]Ast.Node.Index = undefined; 2809 const full = tree.fullFnProto(&buf, parent_node).?; 2810 const tok_index = full.lib_name.?; 2811 const start = tree.tokens.items(.start)[tok_index]; 2812 const end = start + @intCast(u32, tree.tokenSlice(tok_index).len); 2813 return Span{ .start = start, .end = end, .main = start }; 2814 }, 2815 2816 .node_offset_array_type_len => |node_off| { 2817 const tree = try src_loc.file_scope.getTree(gpa); 2818 const parent_node = src_loc.declRelativeToNodeIndex(node_off); 2819 2820 const full = tree.fullArrayType(parent_node).?; 2821 return nodeToSpan(tree, full.ast.elem_count); 2822 }, 2823 .node_offset_array_type_sentinel => |node_off| { 2824 const tree = try src_loc.file_scope.getTree(gpa); 2825 const parent_node = src_loc.declRelativeToNodeIndex(node_off); 2826 2827 const full = tree.fullArrayType(parent_node).?; 2828 return nodeToSpan(tree, full.ast.sentinel); 2829 }, 2830 .node_offset_array_type_elem => |node_off| { 2831 const tree = try src_loc.file_scope.getTree(gpa); 2832 const parent_node = src_loc.declRelativeToNodeIndex(node_off); 2833 2834 const full = tree.fullArrayType(parent_node).?; 2835 return nodeToSpan(tree, full.ast.elem_type); 2836 }, 2837 .node_offset_un_op => |node_off| { 2838 const tree = try src_loc.file_scope.getTree(gpa); 2839 const node_datas = tree.nodes.items(.data); 2840 const node = src_loc.declRelativeToNodeIndex(node_off); 2841 2842 return nodeToSpan(tree, node_datas[node].lhs); 2843 }, 2844 .node_offset_ptr_elem => |node_off| { 2845 const tree = try src_loc.file_scope.getTree(gpa); 2846 const parent_node = src_loc.declRelativeToNodeIndex(node_off); 2847 2848 const full = tree.fullPtrType(parent_node).?; 2849 return nodeToSpan(tree, full.ast.child_type); 2850 }, 2851 .node_offset_ptr_sentinel => |node_off| { 2852 const tree = try src_loc.file_scope.getTree(gpa); 2853 const parent_node = src_loc.declRelativeToNodeIndex(node_off); 2854 2855 const full = tree.fullPtrType(parent_node).?; 2856 return nodeToSpan(tree, full.ast.sentinel); 2857 }, 2858 .node_offset_ptr_align => |node_off| { 2859 const tree = try src_loc.file_scope.getTree(gpa); 2860 const parent_node = src_loc.declRelativeToNodeIndex(node_off); 2861 2862 const full = tree.fullPtrType(parent_node).?; 2863 return nodeToSpan(tree, full.ast.align_node); 2864 }, 2865 .node_offset_ptr_addrspace => |node_off| { 2866 const tree = try src_loc.file_scope.getTree(gpa); 2867 const parent_node = src_loc.declRelativeToNodeIndex(node_off); 2868 2869 const full = tree.fullPtrType(parent_node).?; 2870 return nodeToSpan(tree, full.ast.addrspace_node); 2871 }, 2872 .node_offset_ptr_bitoffset => |node_off| { 2873 const tree = try src_loc.file_scope.getTree(gpa); 2874 const parent_node = src_loc.declRelativeToNodeIndex(node_off); 2875 2876 const full = tree.fullPtrType(parent_node).?; 2877 return nodeToSpan(tree, full.ast.bit_range_start); 2878 }, 2879 .node_offset_ptr_hostsize => |node_off| { 2880 const tree = try src_loc.file_scope.getTree(gpa); 2881 const parent_node = src_loc.declRelativeToNodeIndex(node_off); 2882 2883 const full = tree.fullPtrType(parent_node).?; 2884 return nodeToSpan(tree, full.ast.bit_range_end); 2885 }, 2886 .node_offset_container_tag => |node_off| { 2887 const tree = try src_loc.file_scope.getTree(gpa); 2888 const node_tags = tree.nodes.items(.tag); 2889 const parent_node = src_loc.declRelativeToNodeIndex(node_off); 2890 2891 switch (node_tags[parent_node]) { 2892 .container_decl_arg, .container_decl_arg_trailing => { 2893 const full = tree.containerDeclArg(parent_node); 2894 return nodeToSpan(tree, full.ast.arg); 2895 }, 2896 .tagged_union_enum_tag, .tagged_union_enum_tag_trailing => { 2897 const full = tree.taggedUnionEnumTag(parent_node); 2898 2899 return tokensToSpan( 2900 tree, 2901 tree.firstToken(full.ast.arg) - 2, 2902 tree.lastToken(full.ast.arg) + 1, 2903 tree.nodes.items(.main_token)[full.ast.arg], 2904 ); 2905 }, 2906 else => unreachable, 2907 } 2908 }, 2909 .node_offset_field_default => |node_off| { 2910 const tree = try src_loc.file_scope.getTree(gpa); 2911 const node_tags = tree.nodes.items(.tag); 2912 const parent_node = src_loc.declRelativeToNodeIndex(node_off); 2913 2914 const full: Ast.full.ContainerField = switch (node_tags[parent_node]) { 2915 .container_field => tree.containerField(parent_node), 2916 .container_field_init => tree.containerFieldInit(parent_node), 2917 else => unreachable, 2918 }; 2919 return nodeToSpan(tree, full.ast.value_expr); 2920 }, 2921 .node_offset_init_ty => |node_off| { 2922 const tree = try src_loc.file_scope.getTree(gpa); 2923 const parent_node = src_loc.declRelativeToNodeIndex(node_off); 2924 2925 var buf: [2]Ast.Node.Index = undefined; 2926 const full = tree.fullArrayInit(&buf, parent_node).?; 2927 return nodeToSpan(tree, full.ast.type_expr); 2928 }, 2929 .node_offset_store_ptr => |node_off| { 2930 const tree = try src_loc.file_scope.getTree(gpa); 2931 const node_tags = tree.nodes.items(.tag); 2932 const node_datas = tree.nodes.items(.data); 2933 const node = src_loc.declRelativeToNodeIndex(node_off); 2934 2935 switch (node_tags[node]) { 2936 .assign => { 2937 return nodeToSpan(tree, node_datas[node].lhs); 2938 }, 2939 else => return nodeToSpan(tree, node), 2940 } 2941 }, 2942 .node_offset_store_operand => |node_off| { 2943 const tree = try src_loc.file_scope.getTree(gpa); 2944 const node_tags = tree.nodes.items(.tag); 2945 const node_datas = tree.nodes.items(.data); 2946 const node = src_loc.declRelativeToNodeIndex(node_off); 2947 2948 switch (node_tags[node]) { 2949 .assign => { 2950 return nodeToSpan(tree, node_datas[node].rhs); 2951 }, 2952 else => return nodeToSpan(tree, node), 2953 } 2954 }, 2955 } 2956 } 2957 2958 pub fn byteOffsetBuiltinCallArg( 2959 src_loc: SrcLoc, 2960 gpa: Allocator, 2961 node_off: i32, 2962 arg_index: u32, 2963 ) !Span { 2964 const tree = try src_loc.file_scope.getTree(gpa); 2965 const node_datas = tree.nodes.items(.data); 2966 const node_tags = tree.nodes.items(.tag); 2967 const node = src_loc.declRelativeToNodeIndex(node_off); 2968 const param = switch (node_tags[node]) { 2969 .builtin_call_two, .builtin_call_two_comma => switch (arg_index) { 2970 0 => node_datas[node].lhs, 2971 1 => node_datas[node].rhs, 2972 else => unreachable, 2973 }, 2974 .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + arg_index], 2975 else => unreachable, 2976 }; 2977 return nodeToSpan(tree, param); 2978 } 2979 2980 pub fn nodeToSpan(tree: *const Ast, node: u32) Span { 2981 return tokensToSpan( 2982 tree, 2983 tree.firstToken(node), 2984 tree.lastToken(node), 2985 tree.nodes.items(.main_token)[node], 2986 ); 2987 } 2988 2989 fn tokensToSpan(tree: *const Ast, start: Ast.TokenIndex, end: Ast.TokenIndex, main: Ast.TokenIndex) Span { 2990 const token_starts = tree.tokens.items(.start); 2991 var start_tok = start; 2992 var end_tok = end; 2993 2994 if (tree.tokensOnSameLine(start, end)) { 2995 // do nothing 2996 } else if (tree.tokensOnSameLine(start, main)) { 2997 end_tok = main; 2998 } else if (tree.tokensOnSameLine(main, end)) { 2999 start_tok = main; 3000 } else { 3001 start_tok = main; 3002 end_tok = main; 3003 } 3004 const start_off = token_starts[start_tok]; 3005 const end_off = token_starts[end_tok] + @intCast(u32, tree.tokenSlice(end_tok).len); 3006 return Span{ .start = start_off, .end = end_off, .main = token_starts[main] }; 3007 } 3008 }; 3009 3010 /// This wraps a simple integer in debug builds so that later on we can find out 3011 /// where in semantic analysis the value got set. 3012 const TracedOffset = struct { 3013 x: i32, 3014 trace: std.debug.Trace = .{}, 3015 3016 const want_tracing = build_options.value_tracing; 3017 }; 3018 3019 /// Resolving a source location into a byte offset may require doing work 3020 /// that we would rather not do unless the error actually occurs. 3021 /// Therefore we need a data structure that contains the information necessary 3022 /// to lazily produce a `SrcLoc` as required. 3023 /// Most of the offsets in this data structure are relative to the containing Decl. 3024 /// This makes the source location resolve properly even when a Decl gets 3025 /// shifted up or down in the file, as long as the Decl's contents itself 3026 /// do not change. 3027 pub const LazySrcLoc = union(enum) { 3028 /// When this tag is set, the code that constructed this `LazySrcLoc` is asserting 3029 /// that all code paths which would need to resolve the source location are 3030 /// unreachable. If you are debugging this tag incorrectly being this value, 3031 /// look into using reverse-continue with a memory watchpoint to see where the 3032 /// value is being set to this tag. 3033 unneeded, 3034 /// Means the source location points to an entire file; not any particular 3035 /// location within the file. `file_scope` union field will be active. 3036 entire_file, 3037 /// The source location points to a byte offset within a source file, 3038 /// offset from 0. The source file is determined contextually. 3039 /// Inside a `SrcLoc`, the `file_scope` union field will be active. 3040 byte_abs: u32, 3041 /// The source location points to a token within a source file, 3042 /// offset from 0. The source file is determined contextually. 3043 /// Inside a `SrcLoc`, the `file_scope` union field will be active. 3044 token_abs: u32, 3045 /// The source location points to an AST node within a source file, 3046 /// offset from 0. The source file is determined contextually. 3047 /// Inside a `SrcLoc`, the `file_scope` union field will be active. 3048 node_abs: u32, 3049 /// The source location points to a byte offset within a source file, 3050 /// offset from the byte offset of the Decl within the file. 3051 /// The Decl is determined contextually. 3052 byte_offset: u32, 3053 /// This data is the offset into the token list from the Decl token. 3054 /// The Decl is determined contextually. 3055 token_offset: u32, 3056 /// The source location points to an AST node, which is this value offset 3057 /// from its containing Decl node AST index. 3058 /// The Decl is determined contextually. 3059 node_offset: TracedOffset, 3060 /// The source location points to the main token of an AST node, found 3061 /// by taking this AST node index offset from the containing Decl AST node. 3062 /// The Decl is determined contextually. 3063 node_offset_main_token: i32, 3064 /// The source location points to the beginning of a struct initializer. 3065 /// The Decl is determined contextually. 3066 node_offset_initializer: i32, 3067 /// The source location points to a variable declaration type expression, 3068 /// found by taking this AST node index offset from the containing 3069 /// Decl AST node, which points to a variable declaration AST node. Next, navigate 3070 /// to the type expression. 3071 /// The Decl is determined contextually. 3072 node_offset_var_decl_ty: i32, 3073 /// The source location points to the alignment expression of a var decl. 3074 /// The Decl is determined contextually. 3075 node_offset_var_decl_align: i32, 3076 /// The source location points to the linksection expression of a var decl. 3077 /// The Decl is determined contextually. 3078 node_offset_var_decl_section: i32, 3079 /// The source location points to the addrspace expression of a var decl. 3080 /// The Decl is determined contextually. 3081 node_offset_var_decl_addrspace: i32, 3082 /// The source location points to the initializer of a var decl. 3083 /// The Decl is determined contextually. 3084 node_offset_var_decl_init: i32, 3085 /// The source location points to the first parameter of a builtin 3086 /// function call, found by taking this AST node index offset from the containing 3087 /// Decl AST node, which points to a builtin call AST node. Next, navigate 3088 /// to the first parameter. 3089 /// The Decl is determined contextually. 3090 node_offset_builtin_call_arg0: i32, 3091 /// Same as `node_offset_builtin_call_arg0` except arg index 1. 3092 node_offset_builtin_call_arg1: i32, 3093 node_offset_builtin_call_arg2: i32, 3094 node_offset_builtin_call_arg3: i32, 3095 node_offset_builtin_call_arg4: i32, 3096 node_offset_builtin_call_arg5: i32, 3097 /// The source location points to the index expression of an array access 3098 /// expression, found by taking this AST node index offset from the containing 3099 /// Decl AST node, which points to an array access AST node. Next, navigate 3100 /// to the index expression. 3101 /// The Decl is determined contextually. 3102 node_offset_array_access_index: i32, 3103 /// The source location points to the LHS of a slice expression 3104 /// expression, found by taking this AST node index offset from the containing 3105 /// Decl AST node, which points to a slice AST node. Next, navigate 3106 /// to the sentinel expression. 3107 /// The Decl is determined contextually. 3108 node_offset_slice_ptr: i32, 3109 /// The source location points to start expression of a slice expression 3110 /// expression, found by taking this AST node index offset from the containing 3111 /// Decl AST node, which points to a slice AST node. Next, navigate 3112 /// to the sentinel expression. 3113 /// The Decl is determined contextually. 3114 node_offset_slice_start: i32, 3115 /// The source location points to the end expression of a slice 3116 /// expression, found by taking this AST node index offset from the containing 3117 /// Decl AST node, which points to a slice AST node. Next, navigate 3118 /// to the sentinel expression. 3119 /// The Decl is determined contextually. 3120 node_offset_slice_end: i32, 3121 /// The source location points to the sentinel expression of a slice 3122 /// expression, found by taking this AST node index offset from the containing 3123 /// Decl AST node, which points to a slice AST node. Next, navigate 3124 /// to the sentinel expression. 3125 /// The Decl is determined contextually. 3126 node_offset_slice_sentinel: i32, 3127 /// The source location points to the callee expression of a function 3128 /// call expression, found by taking this AST node index offset from the containing 3129 /// Decl AST node, which points to a function call AST node. Next, navigate 3130 /// to the callee expression. 3131 /// The Decl is determined contextually. 3132 node_offset_call_func: i32, 3133 /// The payload is offset from the containing Decl AST node. 3134 /// The source location points to the field name of: 3135 /// * a field access expression (`a.b`), or 3136 /// * the callee of a method call (`a.b()`), or 3137 /// * the operand ("b" node) of a field initialization expression (`.a = b`), or 3138 /// The Decl is determined contextually. 3139 node_offset_field_name: i32, 3140 /// The source location points to the pointer of a pointer deref expression, 3141 /// found by taking this AST node index offset from the containing 3142 /// Decl AST node, which points to a pointer deref AST node. Next, navigate 3143 /// to the pointer expression. 3144 /// The Decl is determined contextually. 3145 node_offset_deref_ptr: i32, 3146 /// The source location points to the assembly source code of an inline assembly 3147 /// expression, found by taking this AST node index offset from the containing 3148 /// Decl AST node, which points to inline assembly AST node. Next, navigate 3149 /// to the asm template source code. 3150 /// The Decl is determined contextually. 3151 node_offset_asm_source: i32, 3152 /// The source location points to the return type of an inline assembly 3153 /// expression, found by taking this AST node index offset from the containing 3154 /// Decl AST node, which points to inline assembly AST node. Next, navigate 3155 /// to the return type expression. 3156 /// The Decl is determined contextually. 3157 node_offset_asm_ret_ty: i32, 3158 /// The source location points to the condition expression of an if 3159 /// expression, found by taking this AST node index offset from the containing 3160 /// Decl AST node, which points to an if expression AST node. Next, navigate 3161 /// to the condition expression. 3162 /// The Decl is determined contextually. 3163 node_offset_if_cond: i32, 3164 /// The source location points to a binary expression, such as `a + b`, found 3165 /// by taking this AST node index offset from the containing Decl AST node. 3166 /// The Decl is determined contextually. 3167 node_offset_bin_op: i32, 3168 /// The source location points to the LHS of a binary expression, found 3169 /// by taking this AST node index offset from the containing Decl AST node, 3170 /// which points to a binary expression AST node. Next, navigate to the LHS. 3171 /// The Decl is determined contextually. 3172 node_offset_bin_lhs: i32, 3173 /// The source location points to the RHS of a binary expression, found 3174 /// by taking this AST node index offset from the containing Decl AST node, 3175 /// which points to a binary expression AST node. Next, navigate to the RHS. 3176 /// The Decl is determined contextually. 3177 node_offset_bin_rhs: i32, 3178 /// The source location points to the operand of a switch expression, found 3179 /// by taking this AST node index offset from the containing Decl AST node, 3180 /// which points to a switch expression AST node. Next, navigate to the operand. 3181 /// The Decl is determined contextually. 3182 node_offset_switch_operand: i32, 3183 /// The source location points to the else/`_` prong of a switch expression, found 3184 /// by taking this AST node index offset from the containing Decl AST node, 3185 /// which points to a switch expression AST node. Next, navigate to the else/`_` prong. 3186 /// The Decl is determined contextually. 3187 node_offset_switch_special_prong: i32, 3188 /// The source location points to all the ranges of a switch expression, found 3189 /// by taking this AST node index offset from the containing Decl AST node, 3190 /// which points to a switch expression AST node. Next, navigate to any of the 3191 /// range nodes. The error applies to all of them. 3192 /// The Decl is determined contextually. 3193 node_offset_switch_range: i32, 3194 /// The source location points to the capture of a switch_prong. 3195 /// The Decl is determined contextually. 3196 node_offset_switch_prong_capture: i32, 3197 /// The source location points to the align expr of a function type 3198 /// expression, found by taking this AST node index offset from the containing 3199 /// Decl AST node, which points to a function type AST node. Next, navigate to 3200 /// the calling convention node. 3201 /// The Decl is determined contextually. 3202 node_offset_fn_type_align: i32, 3203 /// The source location points to the addrspace expr of a function type 3204 /// expression, found by taking this AST node index offset from the containing 3205 /// Decl AST node, which points to a function type AST node. Next, navigate to 3206 /// the calling convention node. 3207 /// The Decl is determined contextually. 3208 node_offset_fn_type_addrspace: i32, 3209 /// The source location points to the linksection expr of a function type 3210 /// expression, found by taking this AST node index offset from the containing 3211 /// Decl AST node, which points to a function type AST node. Next, navigate to 3212 /// the calling convention node. 3213 /// The Decl is determined contextually. 3214 node_offset_fn_type_section: i32, 3215 /// The source location points to the calling convention of a function type 3216 /// expression, found by taking this AST node index offset from the containing 3217 /// Decl AST node, which points to a function type AST node. Next, navigate to 3218 /// the calling convention node. 3219 /// The Decl is determined contextually. 3220 node_offset_fn_type_cc: i32, 3221 /// The source location points to the return type of a function type 3222 /// expression, found by taking this AST node index offset from the containing 3223 /// Decl AST node, which points to a function type AST node. Next, navigate to 3224 /// the return type node. 3225 /// The Decl is determined contextually. 3226 node_offset_fn_type_ret_ty: i32, 3227 node_offset_param: i32, 3228 token_offset_param: i32, 3229 /// The source location points to the type expression of an `anyframe->T` 3230 /// expression, found by taking this AST node index offset from the containing 3231 /// Decl AST node, which points to a `anyframe->T` expression AST node. Next, navigate 3232 /// to the type expression. 3233 /// The Decl is determined contextually. 3234 node_offset_anyframe_type: i32, 3235 /// The source location points to the string literal of `extern "foo"`, found 3236 /// by taking this AST node index offset from the containing 3237 /// Decl AST node, which points to a function prototype or variable declaration 3238 /// expression AST node. Next, navigate to the string literal of the `extern "foo"`. 3239 /// The Decl is determined contextually. 3240 node_offset_lib_name: i32, 3241 /// The source location points to the len expression of an `[N:S]T` 3242 /// expression, found by taking this AST node index offset from the containing 3243 /// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate 3244 /// to the len expression. 3245 /// The Decl is determined contextually. 3246 node_offset_array_type_len: i32, 3247 /// The source location points to the sentinel expression of an `[N:S]T` 3248 /// expression, found by taking this AST node index offset from the containing 3249 /// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate 3250 /// to the sentinel expression. 3251 /// The Decl is determined contextually. 3252 node_offset_array_type_sentinel: i32, 3253 /// The source location points to the elem expression of an `[N:S]T` 3254 /// expression, found by taking this AST node index offset from the containing 3255 /// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate 3256 /// to the elem expression. 3257 /// The Decl is determined contextually. 3258 node_offset_array_type_elem: i32, 3259 /// The source location points to the operand of an unary expression. 3260 /// The Decl is determined contextually. 3261 node_offset_un_op: i32, 3262 /// The source location points to the elem type of a pointer. 3263 /// The Decl is determined contextually. 3264 node_offset_ptr_elem: i32, 3265 /// The source location points to the sentinel of a pointer. 3266 /// The Decl is determined contextually. 3267 node_offset_ptr_sentinel: i32, 3268 /// The source location points to the align expr of a pointer. 3269 /// The Decl is determined contextually. 3270 node_offset_ptr_align: i32, 3271 /// The source location points to the addrspace expr of a pointer. 3272 /// The Decl is determined contextually. 3273 node_offset_ptr_addrspace: i32, 3274 /// The source location points to the bit-offset of a pointer. 3275 /// The Decl is determined contextually. 3276 node_offset_ptr_bitoffset: i32, 3277 /// The source location points to the host size of a pointer. 3278 /// The Decl is determined contextually. 3279 node_offset_ptr_hostsize: i32, 3280 /// The source location points to the tag type of an union or an enum. 3281 /// The Decl is determined contextually. 3282 node_offset_container_tag: i32, 3283 /// The source location points to the default value of a field. 3284 /// The Decl is determined contextually. 3285 node_offset_field_default: i32, 3286 /// The source location points to the type of an array or struct initializer. 3287 /// The Decl is determined contextually. 3288 node_offset_init_ty: i32, 3289 /// The source location points to the LHS of an assignment. 3290 /// The Decl is determined contextually. 3291 node_offset_store_ptr: i32, 3292 /// The source location points to the RHS of an assignment. 3293 /// The Decl is determined contextually. 3294 node_offset_store_operand: i32, 3295 /// The source location points to a for loop input. 3296 /// The Decl is determined contextually. 3297 for_input: struct { 3298 /// Points to the for loop AST node. 3299 for_node_offset: i32, 3300 /// Picks one of the inputs from the condition. 3301 input_index: u32, 3302 }, 3303 /// The source location points to one of the captures of a for loop, found 3304 /// by taking this AST node index offset from the containing 3305 /// Decl AST node, which points to one of the input nodes of a for loop. 3306 /// Next, navigate to the corresponding capture. 3307 /// The Decl is determined contextually. 3308 for_capture_from_input: i32, 3309 3310 pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease; 3311 3312 noinline fn nodeOffsetDebug(node_offset: i32) LazySrcLoc { 3313 var result: LazySrcLoc = .{ .node_offset = .{ .x = node_offset } }; 3314 result.node_offset.trace.addAddr(@returnAddress(), "init"); 3315 return result; 3316 } 3317 3318 fn nodeOffsetRelease(node_offset: i32) LazySrcLoc { 3319 return .{ .node_offset = .{ .x = node_offset } }; 3320 } 3321 3322 /// Upgrade to a `SrcLoc` based on the `Decl` provided. 3323 pub fn toSrcLoc(lazy: LazySrcLoc, decl: *Decl) SrcLoc { 3324 return switch (lazy) { 3325 .unneeded, 3326 .entire_file, 3327 .byte_abs, 3328 .token_abs, 3329 .node_abs, 3330 => .{ 3331 .file_scope = decl.getFileScope(), 3332 .parent_decl_node = 0, 3333 .lazy = lazy, 3334 }, 3335 3336 .byte_offset, 3337 .token_offset, 3338 .node_offset, 3339 .node_offset_main_token, 3340 .node_offset_initializer, 3341 .node_offset_var_decl_ty, 3342 .node_offset_var_decl_align, 3343 .node_offset_var_decl_section, 3344 .node_offset_var_decl_addrspace, 3345 .node_offset_var_decl_init, 3346 .node_offset_builtin_call_arg0, 3347 .node_offset_builtin_call_arg1, 3348 .node_offset_builtin_call_arg2, 3349 .node_offset_builtin_call_arg3, 3350 .node_offset_builtin_call_arg4, 3351 .node_offset_builtin_call_arg5, 3352 .node_offset_array_access_index, 3353 .node_offset_slice_ptr, 3354 .node_offset_slice_start, 3355 .node_offset_slice_end, 3356 .node_offset_slice_sentinel, 3357 .node_offset_call_func, 3358 .node_offset_field_name, 3359 .node_offset_deref_ptr, 3360 .node_offset_asm_source, 3361 .node_offset_asm_ret_ty, 3362 .node_offset_if_cond, 3363 .node_offset_bin_op, 3364 .node_offset_bin_lhs, 3365 .node_offset_bin_rhs, 3366 .node_offset_switch_operand, 3367 .node_offset_switch_special_prong, 3368 .node_offset_switch_range, 3369 .node_offset_switch_prong_capture, 3370 .node_offset_fn_type_align, 3371 .node_offset_fn_type_addrspace, 3372 .node_offset_fn_type_section, 3373 .node_offset_fn_type_cc, 3374 .node_offset_fn_type_ret_ty, 3375 .node_offset_param, 3376 .token_offset_param, 3377 .node_offset_anyframe_type, 3378 .node_offset_lib_name, 3379 .node_offset_array_type_len, 3380 .node_offset_array_type_sentinel, 3381 .node_offset_array_type_elem, 3382 .node_offset_un_op, 3383 .node_offset_ptr_elem, 3384 .node_offset_ptr_sentinel, 3385 .node_offset_ptr_align, 3386 .node_offset_ptr_addrspace, 3387 .node_offset_ptr_bitoffset, 3388 .node_offset_ptr_hostsize, 3389 .node_offset_container_tag, 3390 .node_offset_field_default, 3391 .node_offset_init_ty, 3392 .node_offset_store_ptr, 3393 .node_offset_store_operand, 3394 .for_input, 3395 .for_capture_from_input, 3396 => .{ 3397 .file_scope = decl.getFileScope(), 3398 .parent_decl_node = decl.src_node, 3399 .lazy = lazy, 3400 }, 3401 }; 3402 } 3403 }; 3404 3405 pub const SemaError = error{ OutOfMemory, AnalysisFail }; 3406 pub const CompileError = error{ 3407 OutOfMemory, 3408 /// When this is returned, the compile error for the failure has already been recorded. 3409 AnalysisFail, 3410 /// Returned when a compile error needed to be reported but a provided LazySrcLoc was set 3411 /// to the `unneeded` tag. The source location was, in fact, needed. It is expected that 3412 /// somewhere up the call stack, the operation will be retried after doing expensive work 3413 /// to compute a source location. 3414 NeededSourceLocation, 3415 /// A Type or Value was needed to be used during semantic analysis, but it was not available 3416 /// because the function is generic. This is only seen when analyzing the body of a param 3417 /// instruction. 3418 GenericPoison, 3419 /// In a comptime scope, a return instruction was encountered. This error is only seen when 3420 /// doing a comptime function call. 3421 ComptimeReturn, 3422 /// In a comptime scope, a break instruction was encountered. This error is only seen when 3423 /// evaluating a comptime block. 3424 ComptimeBreak, 3425 }; 3426 3427 pub fn init(mod: *Module) !void { 3428 const gpa = mod.gpa; 3429 try mod.error_name_list.append(gpa, "(no error)"); 3430 try mod.intern_pool.init(gpa); 3431 } 3432 3433 pub fn deinit(mod: *Module) void { 3434 const gpa = mod.gpa; 3435 3436 for (mod.import_table.keys()) |key| { 3437 gpa.free(key); 3438 } 3439 var failed_decls = mod.failed_decls; 3440 mod.failed_decls = .{}; 3441 for (mod.import_table.values()) |value| { 3442 value.destroy(mod); 3443 } 3444 mod.import_table.deinit(gpa); 3445 3446 { 3447 var it = mod.embed_table.iterator(); 3448 while (it.next()) |entry| { 3449 gpa.free(entry.key_ptr.*); 3450 entry.value_ptr.*.destroy(mod); 3451 } 3452 mod.embed_table.deinit(gpa); 3453 } 3454 3455 mod.deletion_set.deinit(gpa); 3456 3457 // The callsite of `Compilation.create` owns the `main_pkg`, however 3458 // Module owns the builtin and std packages that it adds. 3459 if (mod.main_pkg.table.fetchRemove("builtin")) |kv| { 3460 gpa.free(kv.key); 3461 kv.value.destroy(gpa); 3462 } 3463 if (mod.main_pkg.table.fetchRemove("std")) |kv| { 3464 gpa.free(kv.key); 3465 // It's possible for main_pkg to be std when running 'zig test'! In this case, we must not 3466 // destroy it, since it would lead to a double-free. 3467 if (kv.value != mod.main_pkg) { 3468 kv.value.destroy(gpa); 3469 } 3470 } 3471 if (mod.main_pkg.table.fetchRemove("root")) |kv| { 3472 gpa.free(kv.key); 3473 } 3474 if (mod.root_pkg != mod.main_pkg) { 3475 mod.root_pkg.destroy(gpa); 3476 } 3477 3478 mod.compile_log_text.deinit(gpa); 3479 3480 mod.zig_cache_artifact_directory.handle.close(); 3481 mod.local_zir_cache.handle.close(); 3482 mod.global_zir_cache.handle.close(); 3483 3484 for (failed_decls.values()) |value| { 3485 value.destroy(gpa); 3486 } 3487 failed_decls.deinit(gpa); 3488 3489 if (mod.emit_h) |emit_h| { 3490 for (emit_h.failed_decls.values()) |value| { 3491 value.destroy(gpa); 3492 } 3493 emit_h.failed_decls.deinit(gpa); 3494 emit_h.decl_table.deinit(gpa); 3495 emit_h.allocated_emit_h.deinit(gpa); 3496 gpa.destroy(emit_h); 3497 } 3498 3499 for (mod.failed_files.values()) |value| { 3500 if (value) |msg| msg.destroy(gpa); 3501 } 3502 mod.failed_files.deinit(gpa); 3503 3504 for (mod.failed_embed_files.values()) |msg| { 3505 msg.destroy(gpa); 3506 } 3507 mod.failed_embed_files.deinit(gpa); 3508 3509 for (mod.failed_exports.values()) |value| { 3510 value.destroy(gpa); 3511 } 3512 mod.failed_exports.deinit(gpa); 3513 3514 for (mod.cimport_errors.values()) |errs| { 3515 for (errs) |err| err.deinit(gpa); 3516 } 3517 mod.cimport_errors.deinit(gpa); 3518 3519 mod.compile_log_decls.deinit(gpa); 3520 3521 for (mod.decl_exports.values()) |*export_list| { 3522 export_list.deinit(gpa); 3523 } 3524 mod.decl_exports.deinit(gpa); 3525 3526 for (mod.export_owners.values()) |*value| { 3527 freeExportList(gpa, value); 3528 } 3529 mod.export_owners.deinit(gpa); 3530 3531 { 3532 var it = mod.global_error_set.keyIterator(); 3533 while (it.next()) |key| { 3534 gpa.free(key.*); 3535 } 3536 mod.global_error_set.deinit(gpa); 3537 } 3538 3539 mod.error_name_list.deinit(gpa); 3540 mod.test_functions.deinit(gpa); 3541 mod.align_stack_fns.deinit(gpa); 3542 mod.monomorphed_funcs.deinit(gpa); 3543 3544 { 3545 var it = mod.memoized_calls.iterator(); 3546 while (it.next()) |entry| { 3547 gpa.free(entry.key_ptr.args); 3548 entry.value_ptr.arena.promote(gpa).deinit(); 3549 } 3550 mod.memoized_calls.deinit(gpa); 3551 } 3552 3553 mod.decls_free_list.deinit(gpa); 3554 mod.allocated_decls.deinit(gpa); 3555 mod.global_assembly.deinit(gpa); 3556 mod.reference_table.deinit(gpa); 3557 3558 mod.string_literal_table.deinit(gpa); 3559 mod.string_literal_bytes.deinit(gpa); 3560 3561 mod.intern_pool.deinit(gpa); 3562 mod.tmp_hack_arena.deinit(); 3563 } 3564 3565 pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void { 3566 const gpa = mod.gpa; 3567 { 3568 const decl = mod.declPtr(decl_index); 3569 log.debug("destroy {*} ({s})", .{ decl, decl.name }); 3570 _ = mod.test_functions.swapRemove(decl_index); 3571 if (decl.deletion_flag) { 3572 assert(mod.deletion_set.swapRemove(decl_index)); 3573 } 3574 if (mod.global_assembly.fetchRemove(decl_index)) |kv| { 3575 gpa.free(kv.value); 3576 } 3577 if (decl.has_tv) { 3578 if (decl.getInnerNamespace()) |namespace| { 3579 namespace.destroyDecls(mod); 3580 } 3581 } 3582 decl.clearValues(mod); 3583 decl.dependants.deinit(gpa); 3584 decl.dependencies.deinit(gpa); 3585 decl.clearName(gpa); 3586 decl.* = undefined; 3587 } 3588 mod.decls_free_list.append(gpa, decl_index) catch { 3589 // In order to keep `destroyDecl` a non-fallible function, we ignore memory 3590 // allocation failures here, instead leaking the Decl until garbage collection. 3591 }; 3592 if (mod.emit_h) |mod_emit_h| { 3593 const decl_emit_h = mod_emit_h.declPtr(decl_index); 3594 decl_emit_h.fwd_decl.deinit(gpa); 3595 decl_emit_h.* = undefined; 3596 } 3597 } 3598 3599 pub fn declPtr(mod: *Module, decl_index: Decl.Index) *Decl { 3600 return mod.allocated_decls.at(@enumToInt(decl_index)); 3601 } 3602 3603 /// Returns true if and only if the Decl is the top level struct associated with a File. 3604 pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool { 3605 const decl = mod.declPtr(decl_index); 3606 if (decl.src_namespace.parent != null) 3607 return false; 3608 return decl_index == decl.src_namespace.getDeclIndex(); 3609 } 3610 3611 fn freeExportList(gpa: Allocator, export_list: *ArrayListUnmanaged(*Export)) void { 3612 for (export_list.items) |exp| { 3613 gpa.free(exp.options.name); 3614 if (exp.options.section) |s| gpa.free(s); 3615 gpa.destroy(exp); 3616 } 3617 export_list.deinit(gpa); 3618 } 3619 3620 // TODO https://github.com/ziglang/zig/issues/8643 3621 const data_has_safety_tag = @sizeOf(Zir.Inst.Data) != 8; 3622 const HackDataLayout = extern struct { 3623 data: [8]u8 align(@alignOf(Zir.Inst.Data)), 3624 safety_tag: u8, 3625 }; 3626 comptime { 3627 if (data_has_safety_tag) { 3628 assert(@sizeOf(HackDataLayout) == @sizeOf(Zir.Inst.Data)); 3629 } 3630 } 3631 3632 pub fn astGenFile(mod: *Module, file: *File) !void { 3633 const tracy = trace(@src()); 3634 defer tracy.end(); 3635 3636 const comp = mod.comp; 3637 const gpa = mod.gpa; 3638 3639 // In any case we need to examine the stat of the file to determine the course of action. 3640 var source_file = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{}); 3641 defer source_file.close(); 3642 3643 const stat = try source_file.stat(); 3644 3645 const want_local_cache = file.pkg == mod.main_pkg; 3646 const digest = hash: { 3647 var path_hash: Cache.HashHelper = .{}; 3648 path_hash.addBytes(build_options.version); 3649 path_hash.add(builtin.zig_backend); 3650 if (!want_local_cache) { 3651 path_hash.addOptionalBytes(file.pkg.root_src_directory.path); 3652 } 3653 path_hash.addBytes(file.sub_file_path); 3654 break :hash path_hash.final(); 3655 }; 3656 const cache_directory = if (want_local_cache) mod.local_zir_cache else mod.global_zir_cache; 3657 const zir_dir = cache_directory.handle; 3658 3659 // Determine whether we need to reload the file from disk and redo parsing and AstGen. 3660 var lock: std.fs.File.Lock = switch (file.status) { 3661 .never_loaded, .retryable_failure => lock: { 3662 // First, load the cached ZIR code, if any. 3663 log.debug("AstGen checking cache: {s} (local={}, digest={s})", .{ 3664 file.sub_file_path, want_local_cache, &digest, 3665 }); 3666 3667 break :lock .shared; 3668 }, 3669 .parse_failure, .astgen_failure, .success_zir => lock: { 3670 const unchanged_metadata = 3671 stat.size == file.stat.size and 3672 stat.mtime == file.stat.mtime and 3673 stat.inode == file.stat.inode; 3674 3675 if (unchanged_metadata) { 3676 log.debug("unmodified metadata of file: {s}", .{file.sub_file_path}); 3677 return; 3678 } 3679 3680 log.debug("metadata changed: {s}", .{file.sub_file_path}); 3681 3682 break :lock .exclusive; 3683 }, 3684 }; 3685 3686 // We ask for a lock in order to coordinate with other zig processes. 3687 // If another process is already working on this file, we will get the cached 3688 // version. Likewise if we're working on AstGen and another process asks for 3689 // the cached file, they'll get it. 3690 const cache_file = while (true) { 3691 break zir_dir.createFile(&digest, .{ 3692 .read = true, 3693 .truncate = false, 3694 .lock = lock, 3695 }) catch |err| switch (err) { 3696 error.NotDir => unreachable, // no dir components 3697 error.InvalidUtf8 => unreachable, // it's a hex encoded name 3698 error.BadPathName => unreachable, // it's a hex encoded name 3699 error.NameTooLong => unreachable, // it's a fixed size name 3700 error.PipeBusy => unreachable, // it's not a pipe 3701 error.WouldBlock => unreachable, // not asking for non-blocking I/O 3702 // There are no dir components, so you would think that this was 3703 // unreachable, however we have observed on macOS two processes racing 3704 // to do openat() with O_CREAT manifest in ENOENT. 3705 error.FileNotFound => continue, 3706 3707 else => |e| return e, // Retryable errors are handled at callsite. 3708 }; 3709 }; 3710 defer cache_file.close(); 3711 3712 while (true) { 3713 update: { 3714 // First we read the header to determine the lengths of arrays. 3715 const header = cache_file.reader().readStruct(Zir.Header) catch |err| switch (err) { 3716 // This can happen if Zig bails out of this function between creating 3717 // the cached file and writing it. 3718 error.EndOfStream => break :update, 3719 else => |e| return e, 3720 }; 3721 const unchanged_metadata = 3722 stat.size == header.stat_size and 3723 stat.mtime == header.stat_mtime and 3724 stat.inode == header.stat_inode; 3725 3726 if (!unchanged_metadata) { 3727 log.debug("AstGen cache stale: {s}", .{file.sub_file_path}); 3728 break :update; 3729 } 3730 log.debug("AstGen cache hit: {s} instructions_len={d}", .{ 3731 file.sub_file_path, header.instructions_len, 3732 }); 3733 3734 file.zir = loadZirCacheBody(gpa, header, cache_file) catch |err| switch (err) { 3735 error.UnexpectedFileSize => { 3736 log.warn("unexpected EOF reading cached ZIR for {s}", .{file.sub_file_path}); 3737 break :update; 3738 }, 3739 else => |e| return e, 3740 }; 3741 file.zir_loaded = true; 3742 file.stat = .{ 3743 .size = header.stat_size, 3744 .inode = header.stat_inode, 3745 .mtime = header.stat_mtime, 3746 }; 3747 file.status = .success_zir; 3748 log.debug("AstGen cached success: {s}", .{file.sub_file_path}); 3749 3750 // TODO don't report compile errors until Sema @importFile 3751 if (file.zir.hasCompileErrors()) { 3752 { 3753 comp.mutex.lock(); 3754 defer comp.mutex.unlock(); 3755 try mod.failed_files.putNoClobber(gpa, file, null); 3756 } 3757 file.status = .astgen_failure; 3758 return error.AnalysisFail; 3759 } 3760 return; 3761 } 3762 3763 // If we already have the exclusive lock then it is our job to update. 3764 if (builtin.os.tag == .wasi or lock == .exclusive) break; 3765 // Otherwise, unlock to give someone a chance to get the exclusive lock 3766 // and then upgrade to an exclusive lock. 3767 cache_file.unlock(); 3768 lock = .exclusive; 3769 try cache_file.lock(lock); 3770 } 3771 3772 // The cache is definitely stale so delete the contents to avoid an underwrite later. 3773 cache_file.setEndPos(0) catch |err| switch (err) { 3774 error.FileTooBig => unreachable, // 0 is not too big 3775 3776 else => |e| return e, 3777 }; 3778 3779 mod.lockAndClearFileCompileError(file); 3780 3781 // If the previous ZIR does not have compile errors, keep it around 3782 // in case parsing or new ZIR fails. In case of successful ZIR update 3783 // at the end of this function we will free it. 3784 // We keep the previous ZIR loaded so that we can use it 3785 // for the update next time it does not have any compile errors. This avoids 3786 // needlessly tossing out semantic analysis work when an error is 3787 // temporarily introduced. 3788 if (file.zir_loaded and !file.zir.hasCompileErrors()) { 3789 assert(file.prev_zir == null); 3790 const prev_zir_ptr = try gpa.create(Zir); 3791 file.prev_zir = prev_zir_ptr; 3792 prev_zir_ptr.* = file.zir; 3793 file.zir = undefined; 3794 file.zir_loaded = false; 3795 } 3796 file.unload(gpa); 3797 3798 if (stat.size > std.math.maxInt(u32)) 3799 return error.FileTooBig; 3800 3801 const source = try gpa.allocSentinel(u8, @intCast(usize, stat.size), 0); 3802 defer if (!file.source_loaded) gpa.free(source); 3803 const amt = try source_file.readAll(source); 3804 if (amt != stat.size) 3805 return error.UnexpectedEndOfFile; 3806 3807 file.stat = .{ 3808 .size = stat.size, 3809 .inode = stat.inode, 3810 .mtime = stat.mtime, 3811 }; 3812 file.source = source; 3813 file.source_loaded = true; 3814 3815 file.tree = try Ast.parse(gpa, source, .zig); 3816 file.tree_loaded = true; 3817 3818 // Any potential AST errors are converted to ZIR errors here. 3819 file.zir = try AstGen.generate(gpa, file.tree); 3820 file.zir_loaded = true; 3821 file.status = .success_zir; 3822 log.debug("AstGen fresh success: {s}", .{file.sub_file_path}); 3823 3824 const safety_buffer = if (data_has_safety_tag) 3825 try gpa.alloc([8]u8, file.zir.instructions.len) 3826 else 3827 undefined; 3828 defer if (data_has_safety_tag) gpa.free(safety_buffer); 3829 const data_ptr = if (data_has_safety_tag) 3830 if (file.zir.instructions.len == 0) 3831 @as([*]const u8, undefined) 3832 else 3833 @ptrCast([*]const u8, safety_buffer.ptr) 3834 else 3835 @ptrCast([*]const u8, file.zir.instructions.items(.data).ptr); 3836 if (data_has_safety_tag) { 3837 // The `Data` union has a safety tag but in the file format we store it without. 3838 for (file.zir.instructions.items(.data), 0..) |*data, i| { 3839 const as_struct = @ptrCast(*const HackDataLayout, data); 3840 safety_buffer[i] = as_struct.data; 3841 } 3842 } 3843 3844 const header: Zir.Header = .{ 3845 .instructions_len = @intCast(u32, file.zir.instructions.len), 3846 .string_bytes_len = @intCast(u32, file.zir.string_bytes.len), 3847 .extra_len = @intCast(u32, file.zir.extra.len), 3848 3849 .stat_size = stat.size, 3850 .stat_inode = stat.inode, 3851 .stat_mtime = stat.mtime, 3852 }; 3853 var iovecs = [_]std.os.iovec_const{ 3854 .{ 3855 .iov_base = @ptrCast([*]const u8, &header), 3856 .iov_len = @sizeOf(Zir.Header), 3857 }, 3858 .{ 3859 .iov_base = @ptrCast([*]const u8, file.zir.instructions.items(.tag).ptr), 3860 .iov_len = file.zir.instructions.len, 3861 }, 3862 .{ 3863 .iov_base = data_ptr, 3864 .iov_len = file.zir.instructions.len * 8, 3865 }, 3866 .{ 3867 .iov_base = file.zir.string_bytes.ptr, 3868 .iov_len = file.zir.string_bytes.len, 3869 }, 3870 .{ 3871 .iov_base = @ptrCast([*]const u8, file.zir.extra.ptr), 3872 .iov_len = file.zir.extra.len * 4, 3873 }, 3874 }; 3875 cache_file.writevAll(&iovecs) catch |err| { 3876 const pkg_path = file.pkg.root_src_directory.path orelse "."; 3877 const cache_path = cache_directory.path orelse "."; 3878 log.warn("unable to write cached ZIR code for {s}/{s} to {s}/{s}: {s}", .{ 3879 pkg_path, file.sub_file_path, cache_path, &digest, @errorName(err), 3880 }); 3881 }; 3882 3883 if (file.zir.hasCompileErrors()) { 3884 { 3885 comp.mutex.lock(); 3886 defer comp.mutex.unlock(); 3887 try mod.failed_files.putNoClobber(gpa, file, null); 3888 } 3889 file.status = .astgen_failure; 3890 return error.AnalysisFail; 3891 } 3892 3893 if (file.prev_zir) |prev_zir| { 3894 // Iterate over all Namespace objects contained within this File, looking at the 3895 // previous and new ZIR together and update the references to point 3896 // to the new one. For example, Decl name, Decl zir_decl_index, and Namespace 3897 // decl_table keys need to get updated to point to the new memory, even if the 3898 // underlying source code is unchanged. 3899 // We do not need to hold any locks at this time because all the Decl and Namespace 3900 // objects being touched are specific to this File, and the only other concurrent 3901 // tasks are touching other File objects. 3902 try updateZirRefs(mod, file, prev_zir.*); 3903 // At this point, `file.outdated_decls` and `file.deleted_decls` are populated, 3904 // and semantic analysis will deal with them properly. 3905 // No need to keep previous ZIR. 3906 prev_zir.deinit(gpa); 3907 gpa.destroy(prev_zir); 3908 file.prev_zir = null; 3909 } else if (file.root_decl.unwrap()) |root_decl| { 3910 // This is an update, but it is the first time the File has succeeded 3911 // ZIR. We must mark it outdated since we have already tried to 3912 // semantically analyze it. 3913 try file.outdated_decls.resize(gpa, 1); 3914 file.outdated_decls.items[0] = root_decl; 3915 } 3916 } 3917 3918 pub fn loadZirCache(gpa: Allocator, cache_file: std.fs.File) !Zir { 3919 return loadZirCacheBody(gpa, try cache_file.reader().readStruct(Zir.Header), cache_file); 3920 } 3921 3922 fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.File) !Zir { 3923 var instructions: std.MultiArrayList(Zir.Inst) = .{}; 3924 errdefer instructions.deinit(gpa); 3925 3926 try instructions.setCapacity(gpa, header.instructions_len); 3927 instructions.len = header.instructions_len; 3928 3929 var zir: Zir = .{ 3930 .instructions = instructions.toOwnedSlice(), 3931 .string_bytes = &.{}, 3932 .extra = &.{}, 3933 }; 3934 errdefer zir.deinit(gpa); 3935 3936 zir.string_bytes = try gpa.alloc(u8, header.string_bytes_len); 3937 zir.extra = try gpa.alloc(u32, header.extra_len); 3938 3939 const safety_buffer = if (data_has_safety_tag) 3940 try gpa.alloc([8]u8, header.instructions_len) 3941 else 3942 undefined; 3943 defer if (data_has_safety_tag) gpa.free(safety_buffer); 3944 3945 const data_ptr = if (data_has_safety_tag) 3946 @ptrCast([*]u8, safety_buffer.ptr) 3947 else 3948 @ptrCast([*]u8, zir.instructions.items(.data).ptr); 3949 3950 var iovecs = [_]std.os.iovec{ 3951 .{ 3952 .iov_base = @ptrCast([*]u8, zir.instructions.items(.tag).ptr), 3953 .iov_len = header.instructions_len, 3954 }, 3955 .{ 3956 .iov_base = data_ptr, 3957 .iov_len = header.instructions_len * 8, 3958 }, 3959 .{ 3960 .iov_base = zir.string_bytes.ptr, 3961 .iov_len = header.string_bytes_len, 3962 }, 3963 .{ 3964 .iov_base = @ptrCast([*]u8, zir.extra.ptr), 3965 .iov_len = header.extra_len * 4, 3966 }, 3967 }; 3968 const amt_read = try cache_file.readvAll(&iovecs); 3969 const amt_expected = zir.instructions.len * 9 + 3970 zir.string_bytes.len + 3971 zir.extra.len * 4; 3972 if (amt_read != amt_expected) return error.UnexpectedFileSize; 3973 if (data_has_safety_tag) { 3974 const tags = zir.instructions.items(.tag); 3975 for (zir.instructions.items(.data), 0..) |*data, i| { 3976 const union_tag = Zir.Inst.Tag.data_tags[@enumToInt(tags[i])]; 3977 const as_struct = @ptrCast(*HackDataLayout, data); 3978 as_struct.* = .{ 3979 .safety_tag = @enumToInt(union_tag), 3980 .data = safety_buffer[i], 3981 }; 3982 } 3983 } 3984 3985 return zir; 3986 } 3987 3988 /// Patch ups: 3989 /// * Struct.zir_index 3990 /// * Decl.zir_index 3991 /// * Fn.zir_body_inst 3992 /// * Decl.zir_decl_index 3993 fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void { 3994 const gpa = mod.gpa; 3995 const new_zir = file.zir; 3996 3997 // The root decl will be null if the previous ZIR had AST errors. 3998 const root_decl = file.root_decl.unwrap() orelse return; 3999 4000 // Maps from old ZIR to new ZIR, struct_decl, enum_decl, etc. Any instruction which 4001 // creates a namespace, gets mapped from old to new here. 4002 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}; 4003 defer inst_map.deinit(gpa); 4004 // Maps from old ZIR to new ZIR, the extra data index for the sub-decl item. 4005 // e.g. the thing that Decl.zir_decl_index points to. 4006 var extra_map: std.AutoHashMapUnmanaged(u32, u32) = .{}; 4007 defer extra_map.deinit(gpa); 4008 4009 try mapOldZirToNew(gpa, old_zir, new_zir, &inst_map, &extra_map); 4010 4011 // Walk the Decl graph, updating ZIR indexes, strings, and populating 4012 // the deleted and outdated lists. 4013 4014 var decl_stack: ArrayListUnmanaged(Decl.Index) = .{}; 4015 defer decl_stack.deinit(gpa); 4016 4017 try decl_stack.append(gpa, root_decl); 4018 4019 file.deleted_decls.clearRetainingCapacity(); 4020 file.outdated_decls.clearRetainingCapacity(); 4021 4022 // The root decl is always outdated; otherwise we would not have had 4023 // to re-generate ZIR for the File. 4024 try file.outdated_decls.append(gpa, root_decl); 4025 4026 while (decl_stack.popOrNull()) |decl_index| { 4027 const decl = mod.declPtr(decl_index); 4028 // Anonymous decls and the root decl have this set to 0. We still need 4029 // to walk them but we do not need to modify this value. 4030 // Anonymous decls should not be marked outdated. They will be re-generated 4031 // if their owner decl is marked outdated. 4032 if (decl.zir_decl_index != 0) { 4033 const old_zir_decl_index = decl.zir_decl_index; 4034 const new_zir_decl_index = extra_map.get(old_zir_decl_index) orelse { 4035 log.debug("updateZirRefs {s}: delete {*} ({s})", .{ 4036 file.sub_file_path, decl, decl.name, 4037 }); 4038 try file.deleted_decls.append(gpa, decl_index); 4039 continue; 4040 }; 4041 const old_hash = decl.contentsHashZir(old_zir); 4042 decl.zir_decl_index = new_zir_decl_index; 4043 const new_hash = decl.contentsHashZir(new_zir); 4044 if (!std.zig.srcHashEql(old_hash, new_hash)) { 4045 log.debug("updateZirRefs {s}: outdated {*} ({s}) {d} => {d}", .{ 4046 file.sub_file_path, decl, decl.name, old_zir_decl_index, new_zir_decl_index, 4047 }); 4048 try file.outdated_decls.append(gpa, decl_index); 4049 } else { 4050 log.debug("updateZirRefs {s}: unchanged {*} ({s}) {d} => {d}", .{ 4051 file.sub_file_path, decl, decl.name, old_zir_decl_index, new_zir_decl_index, 4052 }); 4053 } 4054 } 4055 4056 if (!decl.owns_tv) continue; 4057 4058 if (decl.getStruct()) |struct_obj| { 4059 struct_obj.zir_index = inst_map.get(struct_obj.zir_index) orelse { 4060 try file.deleted_decls.append(gpa, decl_index); 4061 continue; 4062 }; 4063 } 4064 4065 if (decl.getUnion()) |union_obj| { 4066 union_obj.zir_index = inst_map.get(union_obj.zir_index) orelse { 4067 try file.deleted_decls.append(gpa, decl_index); 4068 continue; 4069 }; 4070 } 4071 4072 if (decl.getFunction()) |func| { 4073 func.zir_body_inst = inst_map.get(func.zir_body_inst) orelse { 4074 try file.deleted_decls.append(gpa, decl_index); 4075 continue; 4076 }; 4077 } 4078 4079 if (decl.getInnerNamespace()) |namespace| { 4080 for (namespace.decls.keys()) |sub_decl| { 4081 try decl_stack.append(gpa, sub_decl); 4082 } 4083 for (namespace.anon_decls.keys()) |sub_decl| { 4084 try decl_stack.append(gpa, sub_decl); 4085 } 4086 } 4087 } 4088 } 4089 4090 pub fn populateBuiltinFile(mod: *Module) !void { 4091 const tracy = trace(@src()); 4092 defer tracy.end(); 4093 4094 const comp = mod.comp; 4095 const pkg_and_file = blk: { 4096 comp.mutex.lock(); 4097 defer comp.mutex.unlock(); 4098 4099 const builtin_pkg = mod.main_pkg.table.get("builtin").?; 4100 const result = try mod.importPkg(builtin_pkg); 4101 break :blk .{ 4102 .file = result.file, 4103 .pkg = builtin_pkg, 4104 }; 4105 }; 4106 const file = pkg_and_file.file; 4107 const builtin_pkg = pkg_and_file.pkg; 4108 const gpa = mod.gpa; 4109 file.source = try comp.generateBuiltinZigSource(gpa); 4110 file.source_loaded = true; 4111 4112 if (builtin_pkg.root_src_directory.handle.statFile(builtin_pkg.root_src_path)) |stat| { 4113 if (stat.size != file.source.len) { 4114 const full_path = try builtin_pkg.root_src_directory.join(gpa, &.{ 4115 builtin_pkg.root_src_path, 4116 }); 4117 defer gpa.free(full_path); 4118 4119 log.warn( 4120 "the cached file '{s}' had the wrong size. Expected {d}, found {d}. " ++ 4121 "Overwriting with correct file contents now", 4122 .{ full_path, file.source.len, stat.size }, 4123 ); 4124 4125 try writeBuiltinFile(file, builtin_pkg); 4126 } else { 4127 file.stat = .{ 4128 .size = stat.size, 4129 .inode = stat.inode, 4130 .mtime = stat.mtime, 4131 }; 4132 } 4133 } else |err| switch (err) { 4134 error.BadPathName => unreachable, // it's always "builtin.zig" 4135 error.NameTooLong => unreachable, // it's always "builtin.zig" 4136 error.PipeBusy => unreachable, // it's not a pipe 4137 error.WouldBlock => unreachable, // not asking for non-blocking I/O 4138 4139 error.FileNotFound => try writeBuiltinFile(file, builtin_pkg), 4140 4141 else => |e| return e, 4142 } 4143 4144 file.tree = try Ast.parse(gpa, file.source, .zig); 4145 file.tree_loaded = true; 4146 assert(file.tree.errors.len == 0); // builtin.zig must parse 4147 4148 file.zir = try AstGen.generate(gpa, file.tree); 4149 file.zir_loaded = true; 4150 file.status = .success_zir; 4151 } 4152 4153 fn writeBuiltinFile(file: *File, builtin_pkg: *Package) !void { 4154 var af = try builtin_pkg.root_src_directory.handle.atomicFile(builtin_pkg.root_src_path, .{}); 4155 defer af.deinit(); 4156 try af.file.writeAll(file.source); 4157 try af.finish(); 4158 4159 file.stat = .{ 4160 .size = file.source.len, 4161 .inode = 0, // dummy value 4162 .mtime = 0, // dummy value 4163 }; 4164 } 4165 4166 pub fn mapOldZirToNew( 4167 gpa: Allocator, 4168 old_zir: Zir, 4169 new_zir: Zir, 4170 inst_map: *std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index), 4171 extra_map: *std.AutoHashMapUnmanaged(u32, u32), 4172 ) Allocator.Error!void { 4173 // Contain ZIR indexes of declaration instructions. 4174 const MatchedZirDecl = struct { 4175 old_inst: Zir.Inst.Index, 4176 new_inst: Zir.Inst.Index, 4177 }; 4178 var match_stack: ArrayListUnmanaged(MatchedZirDecl) = .{}; 4179 defer match_stack.deinit(gpa); 4180 4181 // Main struct inst is always the same 4182 try match_stack.append(gpa, .{ 4183 .old_inst = Zir.main_struct_inst, 4184 .new_inst = Zir.main_struct_inst, 4185 }); 4186 4187 var old_decls = std.ArrayList(Zir.Inst.Index).init(gpa); 4188 defer old_decls.deinit(); 4189 var new_decls = std.ArrayList(Zir.Inst.Index).init(gpa); 4190 defer new_decls.deinit(); 4191 4192 while (match_stack.popOrNull()) |match_item| { 4193 try inst_map.put(gpa, match_item.old_inst, match_item.new_inst); 4194 4195 // Maps name to extra index of decl sub item. 4196 var decl_map: std.StringHashMapUnmanaged(u32) = .{}; 4197 defer decl_map.deinit(gpa); 4198 4199 { 4200 var old_decl_it = old_zir.declIterator(match_item.old_inst); 4201 while (old_decl_it.next()) |old_decl| { 4202 try decl_map.put(gpa, old_decl.name, old_decl.sub_index); 4203 } 4204 } 4205 4206 var new_decl_it = new_zir.declIterator(match_item.new_inst); 4207 while (new_decl_it.next()) |new_decl| { 4208 const old_extra_index = decl_map.get(new_decl.name) orelse continue; 4209 const new_extra_index = new_decl.sub_index; 4210 try extra_map.put(gpa, old_extra_index, new_extra_index); 4211 4212 try old_zir.findDecls(&old_decls, old_extra_index); 4213 try new_zir.findDecls(&new_decls, new_extra_index); 4214 var i: usize = 0; 4215 while (true) : (i += 1) { 4216 if (i >= old_decls.items.len) break; 4217 if (i >= new_decls.items.len) break; 4218 try match_stack.append(gpa, .{ 4219 .old_inst = old_decls.items[i], 4220 .new_inst = new_decls.items[i], 4221 }); 4222 } 4223 } 4224 } 4225 } 4226 4227 /// This ensures that the Decl will have a Type and Value populated. 4228 /// However the resolution status of the Type may not be fully resolved. 4229 /// For example an inferred error set is not resolved until after `analyzeFnBody`. 4230 /// is called. 4231 pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { 4232 const tracy = trace(@src()); 4233 defer tracy.end(); 4234 4235 const decl = mod.declPtr(decl_index); 4236 4237 const subsequent_analysis = switch (decl.analysis) { 4238 .in_progress => unreachable, 4239 4240 .file_failure, 4241 .sema_failure, 4242 .sema_failure_retryable, 4243 .liveness_failure, 4244 .codegen_failure, 4245 .dependency_failure, 4246 .codegen_failure_retryable, 4247 => return error.AnalysisFail, 4248 4249 .complete => return, 4250 4251 .outdated => blk: { 4252 log.debug("re-analyzing {*} ({s})", .{ decl, decl.name }); 4253 4254 // The exports this Decl performs will be re-discovered, so we remove them here 4255 // prior to re-analysis. 4256 try mod.deleteDeclExports(decl_index); 4257 4258 // Similarly, `@setAlignStack` invocations will be re-discovered. 4259 if (decl.getFunction()) |func| { 4260 _ = mod.align_stack_fns.remove(func); 4261 } 4262 4263 // Dependencies will be re-discovered, so we remove them here prior to re-analysis. 4264 for (decl.dependencies.keys()) |dep_index| { 4265 const dep = mod.declPtr(dep_index); 4266 dep.removeDependant(decl_index); 4267 if (dep.dependants.count() == 0 and !dep.deletion_flag) { 4268 log.debug("insert {*} ({s}) dependant {*} ({s}) into deletion set", .{ 4269 decl, decl.name, dep, dep.name, 4270 }); 4271 try mod.markDeclForDeletion(dep_index); 4272 } 4273 } 4274 decl.dependencies.clearRetainingCapacity(); 4275 4276 break :blk true; 4277 }, 4278 4279 .unreferenced => false, 4280 }; 4281 4282 var decl_prog_node = mod.sema_prog_node.start(mem.sliceTo(decl.name, 0), 0); 4283 decl_prog_node.activate(); 4284 defer decl_prog_node.end(); 4285 4286 const type_changed = blk: { 4287 if (decl.zir_decl_index == 0 and !mod.declIsRoot(decl_index)) { 4288 // Anonymous decl. We don't semantically analyze these. 4289 break :blk false; // tv unchanged 4290 } 4291 4292 break :blk mod.semaDecl(decl_index) catch |err| switch (err) { 4293 error.AnalysisFail => { 4294 if (decl.analysis == .in_progress) { 4295 // If this decl caused the compile error, the analysis field would 4296 // be changed to indicate it was this Decl's fault. Because this 4297 // did not happen, we infer here that it was a dependency failure. 4298 decl.analysis = .dependency_failure; 4299 } 4300 return error.AnalysisFail; 4301 }, 4302 error.NeededSourceLocation => unreachable, 4303 error.GenericPoison => unreachable, 4304 else => |e| { 4305 decl.analysis = .sema_failure_retryable; 4306 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1); 4307 mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( 4308 mod.gpa, 4309 decl.srcLoc(), 4310 "unable to analyze: {s}", 4311 .{@errorName(e)}, 4312 )); 4313 return error.AnalysisFail; 4314 }, 4315 }; 4316 }; 4317 4318 if (subsequent_analysis) { 4319 // Update all dependents which have at least this level of dependency. 4320 // If our type remained the same and we're a function, only update 4321 // decls which depend on our body; otherwise, update all dependents. 4322 const update_level: Decl.DepType = if (!type_changed and decl.ty.zigTypeTag(mod) == .Fn) .function_body else .normal; 4323 4324 for (decl.dependants.keys(), decl.dependants.values()) |dep_index, dep_type| { 4325 if (@enumToInt(dep_type) < @enumToInt(update_level)) continue; 4326 4327 const dep = mod.declPtr(dep_index); 4328 switch (dep.analysis) { 4329 .unreferenced => unreachable, 4330 .in_progress => continue, // already doing analysis, ok 4331 .outdated => continue, // already queued for update 4332 4333 .file_failure, 4334 .dependency_failure, 4335 .sema_failure, 4336 .sema_failure_retryable, 4337 .liveness_failure, 4338 .codegen_failure, 4339 .codegen_failure_retryable, 4340 .complete, 4341 => if (dep.generation != mod.generation) { 4342 try mod.markOutdatedDecl(dep_index); 4343 }, 4344 } 4345 } 4346 } 4347 } 4348 4349 pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { 4350 const tracy = trace(@src()); 4351 defer tracy.end(); 4352 4353 const decl_index = func.owner_decl; 4354 const decl = mod.declPtr(decl_index); 4355 4356 switch (decl.analysis) { 4357 .unreferenced => unreachable, 4358 .in_progress => unreachable, 4359 .outdated => unreachable, 4360 4361 .file_failure, 4362 .sema_failure, 4363 .liveness_failure, 4364 .codegen_failure, 4365 .dependency_failure, 4366 .sema_failure_retryable, 4367 => return error.AnalysisFail, 4368 4369 .complete, .codegen_failure_retryable => { 4370 switch (func.state) { 4371 .sema_failure, .dependency_failure => return error.AnalysisFail, 4372 .none, .queued => {}, 4373 .in_progress => unreachable, 4374 .inline_only => unreachable, // don't queue work for this 4375 .success => return, 4376 } 4377 4378 const gpa = mod.gpa; 4379 4380 var tmp_arena = std.heap.ArenaAllocator.init(gpa); 4381 defer tmp_arena.deinit(); 4382 const sema_arena = tmp_arena.allocator(); 4383 4384 var air = mod.analyzeFnBody(func, sema_arena) catch |err| switch (err) { 4385 error.AnalysisFail => { 4386 if (func.state == .in_progress) { 4387 // If this decl caused the compile error, the analysis field would 4388 // be changed to indicate it was this Decl's fault. Because this 4389 // did not happen, we infer here that it was a dependency failure. 4390 func.state = .dependency_failure; 4391 } 4392 return error.AnalysisFail; 4393 }, 4394 error.OutOfMemory => return error.OutOfMemory, 4395 }; 4396 defer air.deinit(gpa); 4397 4398 const comp = mod.comp; 4399 4400 const no_bin_file = (comp.bin_file.options.emit == null and 4401 comp.emit_asm == null and 4402 comp.emit_llvm_ir == null and 4403 comp.emit_llvm_bc == null); 4404 4405 const dump_air = builtin.mode == .Debug and comp.verbose_air; 4406 const dump_llvm_ir = builtin.mode == .Debug and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null); 4407 4408 if (no_bin_file and !dump_air and !dump_llvm_ir) return; 4409 4410 log.debug("analyze liveness of {s}", .{decl.name}); 4411 var liveness = try Liveness.analyze(gpa, air, &mod.intern_pool); 4412 defer liveness.deinit(gpa); 4413 4414 if (dump_air) { 4415 const fqn = try decl.getFullyQualifiedName(mod); 4416 defer mod.gpa.free(fqn); 4417 4418 std.debug.print("# Begin Function AIR: {s}:\n", .{fqn}); 4419 @import("print_air.zig").dump(mod, air, liveness); 4420 std.debug.print("# End Function AIR: {s}\n\n", .{fqn}); 4421 } 4422 4423 if (std.debug.runtime_safety) { 4424 var verify = Liveness.Verify{ 4425 .gpa = gpa, 4426 .air = air, 4427 .liveness = liveness, 4428 .intern_pool = &mod.intern_pool, 4429 }; 4430 defer verify.deinit(); 4431 4432 verify.verify() catch |err| switch (err) { 4433 error.OutOfMemory => return error.OutOfMemory, 4434 else => { 4435 try mod.failed_decls.ensureUnusedCapacity(gpa, 1); 4436 mod.failed_decls.putAssumeCapacityNoClobber( 4437 decl_index, 4438 try Module.ErrorMsg.create( 4439 gpa, 4440 decl.srcLoc(), 4441 "invalid liveness: {s}", 4442 .{@errorName(err)}, 4443 ), 4444 ); 4445 decl.analysis = .liveness_failure; 4446 return error.AnalysisFail; 4447 }, 4448 }; 4449 } 4450 4451 if (no_bin_file and !dump_llvm_ir) return; 4452 4453 comp.bin_file.updateFunc(mod, func, air, liveness) catch |err| switch (err) { 4454 error.OutOfMemory => return error.OutOfMemory, 4455 error.AnalysisFail => { 4456 decl.analysis = .codegen_failure; 4457 return; 4458 }, 4459 else => { 4460 try mod.failed_decls.ensureUnusedCapacity(gpa, 1); 4461 mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create( 4462 gpa, 4463 decl.srcLoc(), 4464 "unable to codegen: {s}", 4465 .{@errorName(err)}, 4466 )); 4467 decl.analysis = .codegen_failure_retryable; 4468 return; 4469 }, 4470 }; 4471 return; 4472 }, 4473 } 4474 } 4475 4476 /// Ensure this function's body is or will be analyzed and emitted. This should 4477 /// be called whenever a potential runtime call of a function is seen. 4478 /// 4479 /// The caller is responsible for ensuring the function decl itself is already 4480 /// analyzed, and for ensuring it can exist at runtime (see 4481 /// `sema.fnHasRuntimeBits`). This function does *not* guarantee that the body 4482 /// will be analyzed when it returns: for that, see `ensureFuncBodyAnalyzed`. 4483 pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func: *Fn) !void { 4484 const decl_index = func.owner_decl; 4485 const decl = mod.declPtr(decl_index); 4486 4487 switch (decl.analysis) { 4488 .unreferenced => unreachable, 4489 .in_progress => unreachable, 4490 .outdated => unreachable, 4491 4492 .file_failure, 4493 .sema_failure, 4494 .liveness_failure, 4495 .codegen_failure, 4496 .dependency_failure, 4497 .sema_failure_retryable, 4498 .codegen_failure_retryable, 4499 // The function analysis failed, but we've already emitted an error for 4500 // that. The callee doesn't need the function to be analyzed right now, 4501 // so its analysis can safely continue. 4502 => return, 4503 4504 .complete => {}, 4505 } 4506 4507 assert(decl.has_tv); 4508 4509 switch (func.state) { 4510 .none => {}, 4511 .queued => return, 4512 // As above, we don't need to forward errors here. 4513 .sema_failure, .dependency_failure => return, 4514 .in_progress => return, 4515 .inline_only => unreachable, // don't queue work for this 4516 .success => return, 4517 } 4518 4519 // Decl itself is safely analyzed, and body analysis is not yet queued 4520 4521 try mod.comp.work_queue.writeItem(.{ .codegen_func = func }); 4522 if (mod.emit_h != null) { 4523 // TODO: we ideally only want to do this if the function's type changed 4524 // since the last update 4525 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl_index }); 4526 } 4527 func.state = .queued; 4528 } 4529 4530 pub fn updateEmbedFile(mod: *Module, embed_file: *EmbedFile) SemaError!void { 4531 const tracy = trace(@src()); 4532 defer tracy.end(); 4533 4534 // TODO we can potentially relax this if we store some more information along 4535 // with decl dependency edges 4536 const owner_decl = mod.declPtr(embed_file.owner_decl); 4537 for (owner_decl.dependants.keys()) |dep_index| { 4538 const dep = mod.declPtr(dep_index); 4539 switch (dep.analysis) { 4540 .unreferenced => unreachable, 4541 .in_progress => continue, // already doing analysis, ok 4542 .outdated => continue, // already queued for update 4543 4544 .file_failure, 4545 .dependency_failure, 4546 .sema_failure, 4547 .sema_failure_retryable, 4548 .liveness_failure, 4549 .codegen_failure, 4550 .codegen_failure_retryable, 4551 .complete, 4552 => if (dep.generation != mod.generation) { 4553 try mod.markOutdatedDecl(dep_index); 4554 }, 4555 } 4556 } 4557 } 4558 4559 pub fn semaPkg(mod: *Module, pkg: *Package) !void { 4560 const file = (try mod.importPkg(pkg)).file; 4561 return mod.semaFile(file); 4562 } 4563 4564 /// Regardless of the file status, will create a `Decl` so that we 4565 /// can track dependencies and re-analyze when the file becomes outdated. 4566 pub fn semaFile(mod: *Module, file: *File) SemaError!void { 4567 const tracy = trace(@src()); 4568 defer tracy.end(); 4569 4570 if (file.root_decl != .none) return; 4571 4572 const gpa = mod.gpa; 4573 var new_decl_arena = std.heap.ArenaAllocator.init(gpa); 4574 errdefer new_decl_arena.deinit(); 4575 const new_decl_arena_allocator = new_decl_arena.allocator(); 4576 4577 const struct_obj = try new_decl_arena_allocator.create(Module.Struct); 4578 const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj); 4579 const struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty); 4580 const ty_ty = comptime Type.type; 4581 struct_obj.* = .{ 4582 .owner_decl = undefined, // set below 4583 .fields = .{}, 4584 .zir_index = undefined, // set below 4585 .layout = .Auto, 4586 .status = .none, 4587 .known_non_opv = undefined, 4588 .is_tuple = undefined, // set below 4589 .namespace = .{ 4590 .parent = null, 4591 .ty = struct_ty, 4592 .file_scope = file, 4593 }, 4594 }; 4595 const new_decl_index = try mod.allocateNewDecl(&struct_obj.namespace, 0, null); 4596 const new_decl = mod.declPtr(new_decl_index); 4597 file.root_decl = new_decl_index.toOptional(); 4598 struct_obj.owner_decl = new_decl_index; 4599 new_decl.name = try file.fullyQualifiedNameZ(gpa); 4600 new_decl.src_line = 0; 4601 new_decl.is_pub = true; 4602 new_decl.is_exported = false; 4603 new_decl.has_align = false; 4604 new_decl.has_linksection_or_addrspace = false; 4605 new_decl.ty = ty_ty; 4606 new_decl.val = struct_val; 4607 new_decl.@"align" = 0; 4608 new_decl.@"linksection" = null; 4609 new_decl.has_tv = true; 4610 new_decl.owns_tv = true; 4611 new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive. 4612 new_decl.analysis = .in_progress; 4613 new_decl.generation = mod.generation; 4614 new_decl.name_fully_qualified = true; 4615 4616 if (file.status == .success_zir) { 4617 assert(file.zir_loaded); 4618 const main_struct_inst = Zir.main_struct_inst; 4619 struct_obj.zir_index = main_struct_inst; 4620 const extended = file.zir.instructions.items(.data)[main_struct_inst].extended; 4621 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); 4622 struct_obj.is_tuple = small.is_tuple; 4623 4624 var sema_arena = std.heap.ArenaAllocator.init(gpa); 4625 defer sema_arena.deinit(); 4626 const sema_arena_allocator = sema_arena.allocator(); 4627 4628 var sema: Sema = .{ 4629 .mod = mod, 4630 .gpa = gpa, 4631 .arena = sema_arena_allocator, 4632 .perm_arena = new_decl_arena_allocator, 4633 .code = file.zir, 4634 .owner_decl = new_decl, 4635 .owner_decl_index = new_decl_index, 4636 .func = null, 4637 .fn_ret_ty = Type.void, 4638 .owner_func = null, 4639 }; 4640 defer sema.deinit(); 4641 4642 var wip_captures = try WipCaptureScope.init(gpa, new_decl_arena_allocator, null); 4643 defer wip_captures.deinit(); 4644 4645 if (sema.analyzeStructDecl(new_decl, main_struct_inst, struct_obj)) |_| { 4646 try wip_captures.finalize(); 4647 new_decl.analysis = .complete; 4648 } else |err| switch (err) { 4649 error.OutOfMemory => return error.OutOfMemory, 4650 error.AnalysisFail => {}, 4651 } 4652 4653 if (mod.comp.whole_cache_manifest) |whole_cache_manifest| { 4654 const source = file.getSource(gpa) catch |err| { 4655 try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)}); 4656 return error.AnalysisFail; 4657 }; 4658 4659 const resolved_path = std.fs.path.resolve( 4660 gpa, 4661 if (file.pkg.root_src_directory.path) |pkg_path| 4662 &[_][]const u8{ pkg_path, file.sub_file_path } 4663 else 4664 &[_][]const u8{file.sub_file_path}, 4665 ) catch |err| { 4666 try reportRetryableFileError(mod, file, "unable to resolve path: {s}", .{@errorName(err)}); 4667 return error.AnalysisFail; 4668 }; 4669 errdefer gpa.free(resolved_path); 4670 4671 mod.comp.whole_cache_manifest_mutex.lock(); 4672 defer mod.comp.whole_cache_manifest_mutex.unlock(); 4673 try whole_cache_manifest.addFilePostContents(resolved_path, source.bytes, source.stat); 4674 } 4675 } else { 4676 new_decl.analysis = .file_failure; 4677 } 4678 4679 try new_decl.finalizeNewArena(&new_decl_arena); 4680 } 4681 4682 /// Returns `true` if the Decl type changed. 4683 /// Returns `true` if this is the first time analyzing the Decl. 4684 /// Returns `false` otherwise. 4685 fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { 4686 const tracy = trace(@src()); 4687 defer tracy.end(); 4688 4689 const decl = mod.declPtr(decl_index); 4690 4691 if (decl.getFileScope().status != .success_zir) { 4692 return error.AnalysisFail; 4693 } 4694 4695 const gpa = mod.gpa; 4696 const zir = decl.getFileScope().zir; 4697 const zir_datas = zir.instructions.items(.data); 4698 4699 decl.analysis = .in_progress; 4700 4701 // We need the memory for the Type to go into the arena for the Decl 4702 var decl_arena = std.heap.ArenaAllocator.init(gpa); 4703 const decl_arena_allocator = decl_arena.allocator(); 4704 const decl_value_arena = blk: { 4705 errdefer decl_arena.deinit(); 4706 const s = try decl_arena_allocator.create(ValueArena); 4707 s.* = .{ .state = undefined }; 4708 break :blk s; 4709 }; 4710 defer { 4711 if (decl.value_arena) |value_arena| { 4712 assert(value_arena.state_acquired == null); 4713 decl_value_arena.prev = value_arena; 4714 } 4715 4716 decl_value_arena.state = decl_arena.state; 4717 decl.value_arena = decl_value_arena; 4718 } 4719 4720 var analysis_arena = std.heap.ArenaAllocator.init(gpa); 4721 defer analysis_arena.deinit(); 4722 const analysis_arena_allocator = analysis_arena.allocator(); 4723 4724 var sema: Sema = .{ 4725 .mod = mod, 4726 .gpa = gpa, 4727 .arena = analysis_arena_allocator, 4728 .perm_arena = decl_arena_allocator, 4729 .code = zir, 4730 .owner_decl = decl, 4731 .owner_decl_index = decl_index, 4732 .func = null, 4733 .fn_ret_ty = Type.void, 4734 .owner_func = null, 4735 }; 4736 defer sema.deinit(); 4737 4738 if (mod.declIsRoot(decl_index)) { 4739 log.debug("semaDecl root {*} ({s})", .{ decl, decl.name }); 4740 const main_struct_inst = Zir.main_struct_inst; 4741 const struct_obj = decl.getStruct().?; 4742 // This might not have gotten set in `semaFile` if the first time had 4743 // a ZIR failure, so we set it here in case. 4744 struct_obj.zir_index = main_struct_inst; 4745 try sema.analyzeStructDecl(decl, main_struct_inst, struct_obj); 4746 decl.analysis = .complete; 4747 decl.generation = mod.generation; 4748 return false; 4749 } 4750 log.debug("semaDecl {*} ({s})", .{ decl, decl.name }); 4751 4752 var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope); 4753 defer wip_captures.deinit(); 4754 4755 var block_scope: Sema.Block = .{ 4756 .parent = null, 4757 .sema = &sema, 4758 .src_decl = decl_index, 4759 .namespace = decl.src_namespace, 4760 .wip_capture_scope = wip_captures.scope, 4761 .instructions = .{}, 4762 .inlining = null, 4763 .is_comptime = true, 4764 }; 4765 defer { 4766 block_scope.instructions.deinit(gpa); 4767 block_scope.params.deinit(gpa); 4768 } 4769 4770 const zir_block_index = decl.zirBlockIndex(); 4771 const inst_data = zir_datas[zir_block_index].pl_node; 4772 const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index); 4773 const body = zir.extra[extra.end..][0..extra.data.body_len]; 4774 const result_ref = (try sema.analyzeBodyBreak(&block_scope, body)).?.operand; 4775 try wip_captures.finalize(); 4776 const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = 0 }; 4777 const section_src: LazySrcLoc = .{ .node_offset_var_decl_section = 0 }; 4778 const address_space_src: LazySrcLoc = .{ .node_offset_var_decl_addrspace = 0 }; 4779 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 }; 4780 const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 }; 4781 const decl_tv = try sema.resolveInstValue(&block_scope, init_src, result_ref, "global variable initializer must be comptime-known"); 4782 4783 // Note this resolves the type of the Decl, not the value; if this Decl 4784 // is a struct, for example, this resolves `type` (which needs no resolution), 4785 // not the struct itself. 4786 try sema.resolveTypeLayout(decl_tv.ty); 4787 4788 if (decl.kind == .@"usingnamespace") { 4789 if (!decl_tv.ty.eql(Type.type, mod)) { 4790 return sema.fail(&block_scope, ty_src, "expected type, found {}", .{ 4791 decl_tv.ty.fmt(mod), 4792 }); 4793 } 4794 const ty = try decl_tv.val.toType().copy(decl_arena_allocator); 4795 if (ty.getNamespace() == null) { 4796 return sema.fail(&block_scope, ty_src, "type {} has no namespace", .{ty.fmt(mod)}); 4797 } 4798 4799 decl.ty = Type.type; 4800 decl.val = try Value.Tag.ty.create(decl_arena_allocator, ty); 4801 decl.@"align" = 0; 4802 decl.@"linksection" = null; 4803 decl.has_tv = true; 4804 decl.owns_tv = false; 4805 decl.analysis = .complete; 4806 decl.generation = mod.generation; 4807 4808 return true; 4809 } 4810 4811 if (decl_tv.val.castTag(.function)) |fn_payload| { 4812 const func = fn_payload.data; 4813 const owns_tv = func.owner_decl == decl_index; 4814 if (owns_tv) { 4815 var prev_type_has_bits = false; 4816 var prev_is_inline = false; 4817 var type_changed = true; 4818 4819 if (decl.has_tv) { 4820 prev_type_has_bits = decl.ty.isFnOrHasRuntimeBits(mod); 4821 type_changed = !decl.ty.eql(decl_tv.ty, mod); 4822 if (decl.getFunction()) |prev_func| { 4823 prev_is_inline = prev_func.state == .inline_only; 4824 } 4825 } 4826 decl.clearValues(mod); 4827 4828 decl.ty = try decl_tv.ty.copy(decl_arena_allocator); 4829 decl.val = try decl_tv.val.copy(decl_arena_allocator); 4830 // linksection, align, and addrspace were already set by Sema 4831 decl.has_tv = true; 4832 decl.owns_tv = owns_tv; 4833 decl.analysis = .complete; 4834 decl.generation = mod.generation; 4835 4836 const is_inline = decl.ty.fnCallingConvention() == .Inline; 4837 if (decl.is_exported) { 4838 const export_src: LazySrcLoc = .{ .token_offset = @boolToInt(decl.is_pub) }; 4839 if (is_inline) { 4840 return sema.fail(&block_scope, export_src, "export of inline function", .{}); 4841 } 4842 // The scope needs to have the decl in it. 4843 const options: std.builtin.ExportOptions = .{ .name = mem.sliceTo(decl.name, 0) }; 4844 try sema.analyzeExport(&block_scope, export_src, options, decl_index); 4845 } 4846 return type_changed or is_inline != prev_is_inline; 4847 } 4848 } 4849 var type_changed = true; 4850 if (decl.has_tv) { 4851 type_changed = !decl.ty.eql(decl_tv.ty, mod); 4852 } 4853 decl.clearValues(mod); 4854 4855 decl.owns_tv = false; 4856 var queue_linker_work = false; 4857 var is_extern = false; 4858 switch (decl_tv.val.ip_index) { 4859 .generic_poison => unreachable, 4860 .unreachable_value => unreachable, 4861 4862 .none => switch (decl_tv.val.tag()) { 4863 .variable => { 4864 const variable = decl_tv.val.castTag(.variable).?.data; 4865 if (variable.owner_decl == decl_index) { 4866 decl.owns_tv = true; 4867 queue_linker_work = true; 4868 4869 const copied_init = try variable.init.copy(decl_arena_allocator); 4870 variable.init = copied_init; 4871 } 4872 }, 4873 .extern_fn => { 4874 const extern_fn = decl_tv.val.castTag(.extern_fn).?.data; 4875 if (extern_fn.owner_decl == decl_index) { 4876 decl.owns_tv = true; 4877 queue_linker_work = true; 4878 is_extern = true; 4879 } 4880 }, 4881 4882 .function => {}, 4883 4884 else => { 4885 log.debug("send global const to linker: {*} ({s})", .{ decl, decl.name }); 4886 queue_linker_work = true; 4887 }, 4888 }, 4889 else => { 4890 log.debug("send global const to linker: {*} ({s})", .{ decl, decl.name }); 4891 queue_linker_work = true; 4892 }, 4893 } 4894 4895 decl.ty = try decl_tv.ty.copy(decl_arena_allocator); 4896 decl.val = try decl_tv.val.copy(decl_arena_allocator); 4897 decl.@"align" = blk: { 4898 const align_ref = decl.zirAlignRef(); 4899 if (align_ref == .none) break :blk 0; 4900 break :blk try sema.resolveAlign(&block_scope, align_src, align_ref); 4901 }; 4902 decl.@"linksection" = blk: { 4903 const linksection_ref = decl.zirLinksectionRef(); 4904 if (linksection_ref == .none) break :blk null; 4905 const bytes = try sema.resolveConstString(&block_scope, section_src, linksection_ref, "linksection must be comptime-known"); 4906 if (mem.indexOfScalar(u8, bytes, 0) != null) { 4907 return sema.fail(&block_scope, section_src, "linksection cannot contain null bytes", .{}); 4908 } else if (bytes.len == 0) { 4909 return sema.fail(&block_scope, section_src, "linksection cannot be empty", .{}); 4910 } 4911 break :blk (try decl_arena_allocator.dupeZ(u8, bytes)).ptr; 4912 }; 4913 decl.@"addrspace" = blk: { 4914 const addrspace_ctx: Sema.AddressSpaceContext = switch (decl_tv.val.ip_index) { 4915 .none => switch (decl_tv.val.tag()) { 4916 .function, .extern_fn => .function, 4917 .variable => .variable, 4918 else => .constant, 4919 }, 4920 else => .constant, 4921 }; 4922 4923 const target = sema.mod.getTarget(); 4924 break :blk switch (decl.zirAddrspaceRef()) { 4925 .none => switch (addrspace_ctx) { 4926 .function => target_util.defaultAddressSpace(target, .function), 4927 .variable => target_util.defaultAddressSpace(target, .global_mutable), 4928 .constant => target_util.defaultAddressSpace(target, .global_constant), 4929 else => unreachable, 4930 }, 4931 else => |addrspace_ref| try sema.analyzeAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx), 4932 }; 4933 }; 4934 decl.has_tv = true; 4935 decl.analysis = .complete; 4936 decl.generation = mod.generation; 4937 4938 const has_runtime_bits = is_extern or 4939 (queue_linker_work and try sema.typeHasRuntimeBits(decl.ty)); 4940 4941 if (has_runtime_bits) { 4942 log.debug("queue linker work for {*} ({s})", .{ decl, decl.name }); 4943 4944 // Needed for codegen_decl which will call updateDecl and then the 4945 // codegen backend wants full access to the Decl Type. 4946 try sema.resolveTypeFully(decl.ty); 4947 4948 try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index }); 4949 4950 if (type_changed and mod.emit_h != null) { 4951 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl_index }); 4952 } 4953 } 4954 4955 if (decl.is_exported) { 4956 const export_src: LazySrcLoc = .{ .token_offset = @boolToInt(decl.is_pub) }; 4957 // The scope needs to have the decl in it. 4958 const options: std.builtin.ExportOptions = .{ .name = mem.sliceTo(decl.name, 0) }; 4959 try sema.analyzeExport(&block_scope, export_src, options, decl_index); 4960 } 4961 4962 return type_changed; 4963 } 4964 4965 /// Returns the depender's index of the dependee. 4966 pub fn declareDeclDependency(mod: *Module, depender_index: Decl.Index, dependee_index: Decl.Index) !void { 4967 return mod.declareDeclDependencyType(depender_index, dependee_index, .normal); 4968 } 4969 4970 /// Returns the depender's index of the dependee. 4971 pub fn declareDeclDependencyType(mod: *Module, depender_index: Decl.Index, dependee_index: Decl.Index, dep_type: Decl.DepType) !void { 4972 if (depender_index == dependee_index) return; 4973 4974 const depender = mod.declPtr(depender_index); 4975 const dependee = mod.declPtr(dependee_index); 4976 4977 if (depender.dependencies.get(dependee_index)) |cur_type| { 4978 if (@enumToInt(cur_type) >= @enumToInt(dep_type)) { 4979 // We already have this dependency (or stricter) marked 4980 return; 4981 } 4982 } 4983 4984 log.debug("{*} ({s}) depends on {*} ({s})", .{ 4985 depender, depender.name, dependee, dependee.name, 4986 }); 4987 4988 if (dependee.deletion_flag) { 4989 dependee.deletion_flag = false; 4990 assert(mod.deletion_set.swapRemove(dependee_index)); 4991 } 4992 4993 try depender.dependencies.ensureUnusedCapacity(mod.gpa, 1); 4994 try dependee.dependants.ensureUnusedCapacity(mod.gpa, 1); 4995 4996 dependee.dependants.putAssumeCapacity(depender_index, dep_type); 4997 depender.dependencies.putAssumeCapacity(dependee_index, dep_type); 4998 } 4999 5000 pub const ImportFileResult = struct { 5001 file: *File, 5002 is_new: bool, 5003 is_pkg: bool, 5004 }; 5005 5006 pub fn importPkg(mod: *Module, pkg: *Package) !ImportFileResult { 5007 const gpa = mod.gpa; 5008 5009 // The resolved path is used as the key in the import table, to detect if 5010 // an import refers to the same as another, despite different relative paths 5011 // or differently mapped package names. 5012 const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{ 5013 pkg.root_src_directory.path orelse ".", pkg.root_src_path, 5014 }); 5015 var keep_resolved_path = false; 5016 defer if (!keep_resolved_path) gpa.free(resolved_path); 5017 5018 const gop = try mod.import_table.getOrPut(gpa, resolved_path); 5019 errdefer _ = mod.import_table.pop(); 5020 if (gop.found_existing) { 5021 try gop.value_ptr.*.addReference(mod.*, .{ .root = pkg }); 5022 return ImportFileResult{ 5023 .file = gop.value_ptr.*, 5024 .is_new = false, 5025 .is_pkg = true, 5026 }; 5027 } 5028 5029 const sub_file_path = try gpa.dupe(u8, pkg.root_src_path); 5030 errdefer gpa.free(sub_file_path); 5031 5032 const new_file = try gpa.create(File); 5033 errdefer gpa.destroy(new_file); 5034 5035 keep_resolved_path = true; // It's now owned by import_table. 5036 gop.value_ptr.* = new_file; 5037 new_file.* = .{ 5038 .sub_file_path = sub_file_path, 5039 .source = undefined, 5040 .source_loaded = false, 5041 .tree_loaded = false, 5042 .zir_loaded = false, 5043 .stat = undefined, 5044 .tree = undefined, 5045 .zir = undefined, 5046 .status = .never_loaded, 5047 .pkg = pkg, 5048 .root_decl = .none, 5049 }; 5050 try new_file.addReference(mod.*, .{ .root = pkg }); 5051 return ImportFileResult{ 5052 .file = new_file, 5053 .is_new = true, 5054 .is_pkg = true, 5055 }; 5056 } 5057 5058 pub fn importFile( 5059 mod: *Module, 5060 cur_file: *File, 5061 import_string: []const u8, 5062 ) !ImportFileResult { 5063 if (std.mem.eql(u8, import_string, "std")) { 5064 return mod.importPkg(mod.main_pkg.table.get("std").?); 5065 } 5066 if (std.mem.eql(u8, import_string, "builtin")) { 5067 return mod.importPkg(mod.main_pkg.table.get("builtin").?); 5068 } 5069 if (std.mem.eql(u8, import_string, "root")) { 5070 return mod.importPkg(mod.root_pkg); 5071 } 5072 if (cur_file.pkg.table.get(import_string)) |pkg| { 5073 return mod.importPkg(pkg); 5074 } 5075 if (!mem.endsWith(u8, import_string, ".zig")) { 5076 return error.PackageNotFound; 5077 } 5078 const gpa = mod.gpa; 5079 5080 // The resolved path is used as the key in the import table, to detect if 5081 // an import refers to the same as another, despite different relative paths 5082 // or differently mapped package names. 5083 const cur_pkg_dir_path = cur_file.pkg.root_src_directory.path orelse "."; 5084 const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{ 5085 cur_pkg_dir_path, cur_file.sub_file_path, "..", import_string, 5086 }); 5087 var keep_resolved_path = false; 5088 defer if (!keep_resolved_path) gpa.free(resolved_path); 5089 5090 const gop = try mod.import_table.getOrPut(gpa, resolved_path); 5091 errdefer _ = mod.import_table.pop(); 5092 if (gop.found_existing) return ImportFileResult{ 5093 .file = gop.value_ptr.*, 5094 .is_new = false, 5095 .is_pkg = false, 5096 }; 5097 5098 const new_file = try gpa.create(File); 5099 errdefer gpa.destroy(new_file); 5100 5101 const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path}); 5102 defer gpa.free(resolved_root_path); 5103 5104 const sub_file_path = p: { 5105 if (mem.startsWith(u8, resolved_path, resolved_root_path)) { 5106 // +1 for the directory separator here. 5107 break :p try gpa.dupe(u8, resolved_path[resolved_root_path.len + 1 ..]); 5108 } 5109 if (mem.eql(u8, resolved_root_path, ".") and 5110 !isUpDir(resolved_path) and 5111 !std.fs.path.isAbsolute(resolved_path)) 5112 { 5113 break :p try gpa.dupe(u8, resolved_path); 5114 } 5115 return error.ImportOutsidePkgPath; 5116 }; 5117 errdefer gpa.free(sub_file_path); 5118 5119 log.debug("new importFile. resolved_root_path={s}, resolved_path={s}, sub_file_path={s}, import_string={s}", .{ 5120 resolved_root_path, resolved_path, sub_file_path, import_string, 5121 }); 5122 5123 keep_resolved_path = true; // It's now owned by import_table. 5124 gop.value_ptr.* = new_file; 5125 new_file.* = .{ 5126 .sub_file_path = sub_file_path, 5127 .source = undefined, 5128 .source_loaded = false, 5129 .tree_loaded = false, 5130 .zir_loaded = false, 5131 .stat = undefined, 5132 .tree = undefined, 5133 .zir = undefined, 5134 .status = .never_loaded, 5135 .pkg = cur_file.pkg, 5136 .root_decl = .none, 5137 }; 5138 return ImportFileResult{ 5139 .file = new_file, 5140 .is_new = true, 5141 .is_pkg = false, 5142 }; 5143 } 5144 5145 pub fn embedFile(mod: *Module, cur_file: *File, import_string: []const u8) !*EmbedFile { 5146 const gpa = mod.gpa; 5147 5148 if (cur_file.pkg.table.get(import_string)) |pkg| { 5149 const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{ 5150 pkg.root_src_directory.path orelse ".", pkg.root_src_path, 5151 }); 5152 var keep_resolved_path = false; 5153 defer if (!keep_resolved_path) gpa.free(resolved_path); 5154 5155 const gop = try mod.embed_table.getOrPut(gpa, resolved_path); 5156 errdefer assert(mod.embed_table.remove(resolved_path)); 5157 if (gop.found_existing) return gop.value_ptr.*; 5158 5159 const sub_file_path = try gpa.dupe(u8, pkg.root_src_path); 5160 errdefer gpa.free(sub_file_path); 5161 5162 return newEmbedFile(mod, pkg, sub_file_path, resolved_path, &keep_resolved_path, gop); 5163 } 5164 5165 // The resolved path is used as the key in the table, to detect if a file 5166 // refers to the same as another, despite different relative paths. 5167 const cur_pkg_dir_path = cur_file.pkg.root_src_directory.path orelse "."; 5168 const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{ 5169 cur_pkg_dir_path, cur_file.sub_file_path, "..", import_string, 5170 }); 5171 var keep_resolved_path = false; 5172 defer if (!keep_resolved_path) gpa.free(resolved_path); 5173 5174 const gop = try mod.embed_table.getOrPut(gpa, resolved_path); 5175 errdefer assert(mod.embed_table.remove(resolved_path)); 5176 if (gop.found_existing) return gop.value_ptr.*; 5177 5178 const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path}); 5179 defer gpa.free(resolved_root_path); 5180 5181 const sub_file_path = p: { 5182 if (mem.startsWith(u8, resolved_path, resolved_root_path)) { 5183 // +1 for the directory separator here. 5184 break :p try gpa.dupe(u8, resolved_path[resolved_root_path.len + 1 ..]); 5185 } 5186 if (mem.eql(u8, resolved_root_path, ".") and 5187 !isUpDir(resolved_path) and 5188 !std.fs.path.isAbsolute(resolved_path)) 5189 { 5190 break :p try gpa.dupe(u8, resolved_path); 5191 } 5192 return error.ImportOutsidePkgPath; 5193 }; 5194 errdefer gpa.free(sub_file_path); 5195 5196 return newEmbedFile(mod, cur_file.pkg, sub_file_path, resolved_path, &keep_resolved_path, gop); 5197 } 5198 5199 fn newEmbedFile( 5200 mod: *Module, 5201 pkg: *Package, 5202 sub_file_path: []const u8, 5203 resolved_path: []const u8, 5204 keep_resolved_path: *bool, 5205 gop: std.StringHashMapUnmanaged(*EmbedFile).GetOrPutResult, 5206 ) !*EmbedFile { 5207 const gpa = mod.gpa; 5208 5209 const new_file = try gpa.create(EmbedFile); 5210 errdefer gpa.destroy(new_file); 5211 5212 var file = try pkg.root_src_directory.handle.openFile(sub_file_path, .{}); 5213 defer file.close(); 5214 5215 const actual_stat = try file.stat(); 5216 const stat: Cache.File.Stat = .{ 5217 .size = actual_stat.size, 5218 .inode = actual_stat.inode, 5219 .mtime = actual_stat.mtime, 5220 }; 5221 const size_usize = std.math.cast(usize, actual_stat.size) orelse return error.Overflow; 5222 const bytes = try file.readToEndAllocOptions(gpa, std.math.maxInt(u32), size_usize, 1, 0); 5223 errdefer gpa.free(bytes); 5224 5225 if (mod.comp.whole_cache_manifest) |whole_cache_manifest| { 5226 const copied_resolved_path = try gpa.dupe(u8, resolved_path); 5227 errdefer gpa.free(copied_resolved_path); 5228 mod.comp.whole_cache_manifest_mutex.lock(); 5229 defer mod.comp.whole_cache_manifest_mutex.unlock(); 5230 try whole_cache_manifest.addFilePostContents(copied_resolved_path, bytes, stat); 5231 } 5232 5233 keep_resolved_path.* = true; // It's now owned by embed_table. 5234 gop.value_ptr.* = new_file; 5235 new_file.* = .{ 5236 .sub_file_path = sub_file_path, 5237 .bytes = bytes, 5238 .stat = stat, 5239 .pkg = pkg, 5240 .owner_decl = undefined, // Set by Sema immediately after this function returns. 5241 }; 5242 return new_file; 5243 } 5244 5245 pub fn detectEmbedFileUpdate(mod: *Module, embed_file: *EmbedFile) !void { 5246 var file = try embed_file.pkg.root_src_directory.handle.openFile(embed_file.sub_file_path, .{}); 5247 defer file.close(); 5248 5249 const stat = try file.stat(); 5250 5251 const unchanged_metadata = 5252 stat.size == embed_file.stat.size and 5253 stat.mtime == embed_file.stat.mtime and 5254 stat.inode == embed_file.stat.inode; 5255 5256 if (unchanged_metadata) return; 5257 5258 const gpa = mod.gpa; 5259 const size_usize = std.math.cast(usize, stat.size) orelse return error.Overflow; 5260 const bytes = try file.readToEndAllocOptions(gpa, std.math.maxInt(u32), size_usize, 1, 0); 5261 gpa.free(embed_file.bytes); 5262 embed_file.bytes = bytes; 5263 embed_file.stat = .{ 5264 .size = stat.size, 5265 .mtime = stat.mtime, 5266 .inode = stat.inode, 5267 }; 5268 5269 mod.comp.mutex.lock(); 5270 defer mod.comp.mutex.unlock(); 5271 try mod.comp.work_queue.writeItem(.{ .update_embed_file = embed_file }); 5272 } 5273 5274 pub fn scanNamespace( 5275 mod: *Module, 5276 namespace: *Namespace, 5277 extra_start: usize, 5278 decls_len: u32, 5279 parent_decl: *Decl, 5280 ) Allocator.Error!usize { 5281 const tracy = trace(@src()); 5282 defer tracy.end(); 5283 5284 const gpa = mod.gpa; 5285 const zir = namespace.file_scope.zir; 5286 5287 try mod.comp.work_queue.ensureUnusedCapacity(decls_len); 5288 try namespace.decls.ensureTotalCapacity(gpa, decls_len); 5289 5290 const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable; 5291 var extra_index = extra_start + bit_bags_count; 5292 var bit_bag_index: usize = extra_start; 5293 var cur_bit_bag: u32 = undefined; 5294 var decl_i: u32 = 0; 5295 var scan_decl_iter: ScanDeclIter = .{ 5296 .module = mod, 5297 .namespace = namespace, 5298 .parent_decl = parent_decl, 5299 }; 5300 while (decl_i < decls_len) : (decl_i += 1) { 5301 if (decl_i % 8 == 0) { 5302 cur_bit_bag = zir.extra[bit_bag_index]; 5303 bit_bag_index += 1; 5304 } 5305 const flags = @truncate(u4, cur_bit_bag); 5306 cur_bit_bag >>= 4; 5307 5308 const decl_sub_index = extra_index; 5309 extra_index += 8; // src_hash(4) + line(1) + name(1) + value(1) + doc_comment(1) 5310 extra_index += @truncate(u1, flags >> 2); // Align 5311 extra_index += @as(u2, @truncate(u1, flags >> 3)) * 2; // Link section or address space, consists of 2 Refs 5312 5313 try scanDecl(&scan_decl_iter, decl_sub_index, flags); 5314 } 5315 return extra_index; 5316 } 5317 5318 const ScanDeclIter = struct { 5319 module: *Module, 5320 namespace: *Namespace, 5321 parent_decl: *Decl, 5322 usingnamespace_index: usize = 0, 5323 comptime_index: usize = 0, 5324 unnamed_test_index: usize = 0, 5325 }; 5326 5327 fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Error!void { 5328 const tracy = trace(@src()); 5329 defer tracy.end(); 5330 5331 const mod = iter.module; 5332 const namespace = iter.namespace; 5333 const gpa = mod.gpa; 5334 const zir = namespace.file_scope.zir; 5335 5336 // zig fmt: off 5337 const is_pub = (flags & 0b0001) != 0; 5338 const export_bit = (flags & 0b0010) != 0; 5339 const has_align = (flags & 0b0100) != 0; 5340 const has_linksection_or_addrspace = (flags & 0b1000) != 0; 5341 // zig fmt: on 5342 5343 const line_off = zir.extra[decl_sub_index + 4]; 5344 const line = iter.parent_decl.relativeToLine(line_off); 5345 const decl_name_index = zir.extra[decl_sub_index + 5]; 5346 const decl_doccomment_index = zir.extra[decl_sub_index + 7]; 5347 const decl_zir_index = zir.extra[decl_sub_index + 6]; 5348 const decl_block_inst_data = zir.instructions.items(.data)[decl_zir_index].pl_node; 5349 const decl_node = iter.parent_decl.relativeToNodeIndex(decl_block_inst_data.src_node); 5350 5351 // Every Decl needs a name. 5352 var is_named_test = false; 5353 var kind: Decl.Kind = .named; 5354 const decl_name: [:0]const u8 = switch (decl_name_index) { 5355 0 => name: { 5356 if (export_bit) { 5357 const i = iter.usingnamespace_index; 5358 iter.usingnamespace_index += 1; 5359 kind = .@"usingnamespace"; 5360 break :name try std.fmt.allocPrintZ(gpa, "usingnamespace_{d}", .{i}); 5361 } else { 5362 const i = iter.comptime_index; 5363 iter.comptime_index += 1; 5364 kind = .@"comptime"; 5365 break :name try std.fmt.allocPrintZ(gpa, "comptime_{d}", .{i}); 5366 } 5367 }, 5368 1 => name: { 5369 const i = iter.unnamed_test_index; 5370 iter.unnamed_test_index += 1; 5371 kind = .@"test"; 5372 break :name try std.fmt.allocPrintZ(gpa, "test_{d}", .{i}); 5373 }, 5374 2 => name: { 5375 is_named_test = true; 5376 const test_name = zir.nullTerminatedString(decl_doccomment_index); 5377 kind = .@"test"; 5378 break :name try std.fmt.allocPrintZ(gpa, "decltest.{s}", .{test_name}); 5379 }, 5380 else => name: { 5381 const raw_name = zir.nullTerminatedString(decl_name_index); 5382 if (raw_name.len == 0) { 5383 is_named_test = true; 5384 const test_name = zir.nullTerminatedString(decl_name_index + 1); 5385 kind = .@"test"; 5386 break :name try std.fmt.allocPrintZ(gpa, "test.{s}", .{test_name}); 5387 } else { 5388 break :name try gpa.dupeZ(u8, raw_name); 5389 } 5390 }, 5391 }; 5392 var must_free_decl_name = true; 5393 defer if (must_free_decl_name) gpa.free(decl_name); 5394 5395 const is_exported = export_bit and decl_name_index != 0; 5396 if (kind == .@"usingnamespace") try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1); 5397 5398 // We create a Decl for it regardless of analysis status. 5399 const gop = try namespace.decls.getOrPutContextAdapted( 5400 gpa, 5401 @as([]const u8, mem.sliceTo(decl_name, 0)), 5402 DeclAdapter{ .mod = mod }, 5403 Namespace.DeclContext{ .module = mod }, 5404 ); 5405 const comp = mod.comp; 5406 if (!gop.found_existing) { 5407 const new_decl_index = try mod.allocateNewDecl(namespace, decl_node, iter.parent_decl.src_scope); 5408 const new_decl = mod.declPtr(new_decl_index); 5409 new_decl.kind = kind; 5410 new_decl.name = decl_name; 5411 must_free_decl_name = false; 5412 if (kind == .@"usingnamespace") { 5413 namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, is_pub); 5414 } 5415 log.debug("scan new {*} ({s}) into {*}", .{ new_decl, decl_name, namespace }); 5416 new_decl.src_line = line; 5417 gop.key_ptr.* = new_decl_index; 5418 // Exported decls, comptime decls, usingnamespace decls, and 5419 // test decls if in test mode, get analyzed. 5420 const decl_pkg = namespace.file_scope.pkg; 5421 const want_analysis = is_exported or switch (decl_name_index) { 5422 0 => true, // comptime or usingnamespace decl 5423 1 => blk: { 5424 // test decl with no name. Skip the part where we check against 5425 // the test name filter. 5426 if (!comp.bin_file.options.is_test) break :blk false; 5427 if (decl_pkg != mod.main_pkg) break :blk false; 5428 try mod.test_functions.put(gpa, new_decl_index, {}); 5429 break :blk true; 5430 }, 5431 else => blk: { 5432 if (!is_named_test) break :blk false; 5433 if (!comp.bin_file.options.is_test) break :blk false; 5434 if (decl_pkg != mod.main_pkg) break :blk false; 5435 if (comp.test_filter) |test_filter| { 5436 if (mem.indexOf(u8, decl_name, test_filter) == null) { 5437 break :blk false; 5438 } 5439 } 5440 try mod.test_functions.put(gpa, new_decl_index, {}); 5441 break :blk true; 5442 }, 5443 }; 5444 if (want_analysis) { 5445 comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl_index }); 5446 } 5447 new_decl.is_pub = is_pub; 5448 new_decl.is_exported = is_exported; 5449 new_decl.has_align = has_align; 5450 new_decl.has_linksection_or_addrspace = has_linksection_or_addrspace; 5451 new_decl.zir_decl_index = @intCast(u32, decl_sub_index); 5452 new_decl.alive = true; // This Decl corresponds to an AST node and therefore always alive. 5453 return; 5454 } 5455 const decl_index = gop.key_ptr.*; 5456 const decl = mod.declPtr(decl_index); 5457 if (kind == .@"test") { 5458 const src_loc = SrcLoc{ 5459 .file_scope = decl.getFileScope(), 5460 .parent_decl_node = decl.src_node, 5461 .lazy = .{ .token_offset = 1 }, 5462 }; 5463 const msg = try ErrorMsg.create( 5464 gpa, 5465 src_loc, 5466 "duplicate test name: {s}", 5467 .{decl_name}, 5468 ); 5469 errdefer msg.destroy(gpa); 5470 try mod.failed_decls.putNoClobber(gpa, decl_index, msg); 5471 const other_src_loc = SrcLoc{ 5472 .file_scope = namespace.file_scope, 5473 .parent_decl_node = decl_node, 5474 .lazy = .{ .token_offset = 1 }, 5475 }; 5476 try mod.errNoteNonLazy(other_src_loc, msg, "other test here", .{}); 5477 } 5478 log.debug("scan existing {*} ({s}) of {*}", .{ decl, decl.name, namespace }); 5479 // Update the AST node of the decl; even if its contents are unchanged, it may 5480 // have been re-ordered. 5481 decl.src_node = decl_node; 5482 decl.src_line = line; 5483 5484 decl.is_pub = is_pub; 5485 decl.is_exported = is_exported; 5486 decl.kind = kind; 5487 decl.has_align = has_align; 5488 decl.has_linksection_or_addrspace = has_linksection_or_addrspace; 5489 decl.zir_decl_index = @intCast(u32, decl_sub_index); 5490 if (decl.getFunction()) |_| { 5491 switch (comp.bin_file.tag) { 5492 .coff, .elf, .macho, .plan9 => { 5493 // TODO Look into detecting when this would be unnecessary by storing enough state 5494 // in `Decl` to notice that the line number did not change. 5495 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index }); 5496 }, 5497 .c, .wasm, .spirv, .nvptx => {}, 5498 } 5499 } 5500 } 5501 5502 /// Make it as if the semantic analysis for this Decl never happened. 5503 pub fn clearDecl( 5504 mod: *Module, 5505 decl_index: Decl.Index, 5506 outdated_decls: ?*std.AutoArrayHashMap(Decl.Index, void), 5507 ) Allocator.Error!void { 5508 const tracy = trace(@src()); 5509 defer tracy.end(); 5510 5511 const decl = mod.declPtr(decl_index); 5512 log.debug("clearing {*} ({s})", .{ decl, decl.name }); 5513 5514 const gpa = mod.gpa; 5515 try mod.deletion_set.ensureUnusedCapacity(gpa, decl.dependencies.count()); 5516 5517 if (outdated_decls) |map| { 5518 _ = map.swapRemove(decl_index); 5519 try map.ensureUnusedCapacity(decl.dependants.count()); 5520 } 5521 5522 // Remove itself from its dependencies. 5523 for (decl.dependencies.keys()) |dep_index| { 5524 const dep = mod.declPtr(dep_index); 5525 dep.removeDependant(decl_index); 5526 if (dep.dependants.count() == 0 and !dep.deletion_flag) { 5527 log.debug("insert {*} ({s}) dependant {*} ({s}) into deletion set", .{ 5528 decl, decl.name, dep, dep.name, 5529 }); 5530 // We don't recursively perform a deletion here, because during the update, 5531 // another reference to it may turn up. 5532 dep.deletion_flag = true; 5533 mod.deletion_set.putAssumeCapacity(dep_index, {}); 5534 } 5535 } 5536 decl.dependencies.clearRetainingCapacity(); 5537 5538 // Anything that depends on this deleted decl needs to be re-analyzed. 5539 for (decl.dependants.keys()) |dep_index| { 5540 const dep = mod.declPtr(dep_index); 5541 dep.removeDependency(decl_index); 5542 if (outdated_decls) |map| { 5543 map.putAssumeCapacity(dep_index, {}); 5544 } 5545 } 5546 decl.dependants.clearRetainingCapacity(); 5547 5548 if (mod.failed_decls.fetchSwapRemove(decl_index)) |kv| { 5549 kv.value.destroy(gpa); 5550 } 5551 if (mod.cimport_errors.fetchSwapRemove(decl_index)) |kv| { 5552 for (kv.value) |err| err.deinit(gpa); 5553 } 5554 if (mod.emit_h) |emit_h| { 5555 if (emit_h.failed_decls.fetchSwapRemove(decl_index)) |kv| { 5556 kv.value.destroy(gpa); 5557 } 5558 assert(emit_h.decl_table.swapRemove(decl_index)); 5559 } 5560 _ = mod.compile_log_decls.swapRemove(decl_index); 5561 try mod.deleteDeclExports(decl_index); 5562 5563 if (decl.has_tv) { 5564 if (decl.ty.isFnOrHasRuntimeBits(mod)) { 5565 mod.comp.bin_file.freeDecl(decl_index); 5566 } 5567 if (decl.getInnerNamespace()) |namespace| { 5568 try namespace.deleteAllDecls(mod, outdated_decls); 5569 } 5570 } 5571 decl.clearValues(mod); 5572 5573 if (decl.deletion_flag) { 5574 decl.deletion_flag = false; 5575 assert(mod.deletion_set.swapRemove(decl_index)); 5576 } 5577 5578 decl.analysis = .unreferenced; 5579 } 5580 5581 /// This function is exclusively called for anonymous decls. 5582 pub fn deleteUnusedDecl(mod: *Module, decl_index: Decl.Index) void { 5583 const decl = mod.declPtr(decl_index); 5584 log.debug("deleteUnusedDecl {d} ({s})", .{ decl_index, decl.name }); 5585 5586 assert(!mod.declIsRoot(decl_index)); 5587 assert(decl.src_namespace.anon_decls.swapRemove(decl_index)); 5588 5589 const dependants = decl.dependants.keys(); 5590 for (dependants) |dep| { 5591 mod.declPtr(dep).removeDependency(decl_index); 5592 } 5593 5594 for (decl.dependencies.keys()) |dep| { 5595 mod.declPtr(dep).removeDependant(decl_index); 5596 } 5597 mod.destroyDecl(decl_index); 5598 } 5599 5600 /// We don't perform a deletion here, because this Decl or another one 5601 /// may end up referencing it before the update is complete. 5602 fn markDeclForDeletion(mod: *Module, decl_index: Decl.Index) !void { 5603 const decl = mod.declPtr(decl_index); 5604 decl.deletion_flag = true; 5605 try mod.deletion_set.put(mod.gpa, decl_index, {}); 5606 } 5607 5608 /// Cancel the creation of an anon decl and delete any references to it. 5609 /// If other decls depend on this decl, they must be aborted first. 5610 pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void { 5611 const decl = mod.declPtr(decl_index); 5612 log.debug("abortAnonDecl {*} ({s})", .{ decl, decl.name }); 5613 5614 assert(!mod.declIsRoot(decl_index)); 5615 assert(decl.src_namespace.anon_decls.swapRemove(decl_index)); 5616 5617 // An aborted decl must not have dependants -- they must have 5618 // been aborted first and removed from this list. 5619 assert(decl.dependants.count() == 0); 5620 5621 for (decl.dependencies.keys()) |dep_index| { 5622 const dep = mod.declPtr(dep_index); 5623 dep.removeDependant(decl_index); 5624 } 5625 5626 mod.destroyDecl(decl_index); 5627 } 5628 5629 /// Delete all the Export objects that are caused by this Decl. Re-analysis of 5630 /// this Decl will cause them to be re-created (or not). 5631 fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void { 5632 var export_owners = (mod.export_owners.fetchSwapRemove(decl_index) orelse return).value; 5633 5634 for (export_owners.items) |exp| { 5635 if (mod.decl_exports.getPtr(exp.exported_decl)) |value_ptr| { 5636 // Remove exports with owner_decl matching the regenerating decl. 5637 const list = value_ptr.items; 5638 var i: usize = 0; 5639 var new_len = list.len; 5640 while (i < new_len) { 5641 if (list[i].owner_decl == decl_index) { 5642 mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]); 5643 new_len -= 1; 5644 } else { 5645 i += 1; 5646 } 5647 } 5648 value_ptr.shrinkAndFree(mod.gpa, new_len); 5649 if (new_len == 0) { 5650 assert(mod.decl_exports.swapRemove(exp.exported_decl)); 5651 } 5652 } 5653 if (mod.comp.bin_file.cast(link.File.Elf)) |elf| { 5654 elf.deleteDeclExport(decl_index, exp.options.name); 5655 } 5656 if (mod.comp.bin_file.cast(link.File.MachO)) |macho| { 5657 try macho.deleteDeclExport(decl_index, exp.options.name); 5658 } 5659 if (mod.comp.bin_file.cast(link.File.Wasm)) |wasm| { 5660 wasm.deleteDeclExport(decl_index); 5661 } 5662 if (mod.comp.bin_file.cast(link.File.Coff)) |coff| { 5663 coff.deleteDeclExport(decl_index, exp.options.name); 5664 } 5665 if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| { 5666 failed_kv.value.destroy(mod.gpa); 5667 } 5668 mod.gpa.free(exp.options.name); 5669 mod.gpa.destroy(exp); 5670 } 5671 export_owners.deinit(mod.gpa); 5672 } 5673 5674 pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { 5675 const tracy = trace(@src()); 5676 defer tracy.end(); 5677 5678 const gpa = mod.gpa; 5679 const decl_index = func.owner_decl; 5680 const decl = mod.declPtr(decl_index); 5681 5682 // Use the Decl's arena for captured values. 5683 var decl_arena: std.heap.ArenaAllocator = undefined; 5684 const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena); 5685 defer decl.value_arena.?.release(&decl_arena); 5686 5687 var sema: Sema = .{ 5688 .mod = mod, 5689 .gpa = gpa, 5690 .arena = arena, 5691 .perm_arena = decl_arena_allocator, 5692 .code = decl.getFileScope().zir, 5693 .owner_decl = decl, 5694 .owner_decl_index = decl_index, 5695 .func = func, 5696 .fn_ret_ty = decl.ty.fnReturnType(), 5697 .owner_func = func, 5698 .branch_quota = @max(func.branch_quota, Sema.default_branch_quota), 5699 }; 5700 defer sema.deinit(); 5701 5702 // reset in case calls to errorable functions are removed. 5703 func.calls_or_awaits_errorable_fn = false; 5704 5705 // First few indexes of extra are reserved and set at the end. 5706 const reserved_count = @typeInfo(Air.ExtraIndex).Enum.fields.len; 5707 try sema.air_extra.ensureTotalCapacity(gpa, reserved_count); 5708 sema.air_extra.items.len += reserved_count; 5709 5710 var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope); 5711 defer wip_captures.deinit(); 5712 5713 var inner_block: Sema.Block = .{ 5714 .parent = null, 5715 .sema = &sema, 5716 .src_decl = decl_index, 5717 .namespace = decl.src_namespace, 5718 .wip_capture_scope = wip_captures.scope, 5719 .instructions = .{}, 5720 .inlining = null, 5721 .is_comptime = false, 5722 }; 5723 defer inner_block.instructions.deinit(gpa); 5724 5725 const fn_info = sema.code.getFnInfo(func.zir_body_inst); 5726 const zir_tags = sema.code.instructions.items(.tag); 5727 5728 // Here we are performing "runtime semantic analysis" for a function body, which means 5729 // we must map the parameter ZIR instructions to `arg` AIR instructions. 5730 // AIR requires the `arg` parameters to be the first N instructions. 5731 // This could be a generic function instantiation, however, in which case we need to 5732 // map the comptime parameters to constant values and only emit arg AIR instructions 5733 // for the runtime ones. 5734 const fn_ty = decl.ty; 5735 const fn_ty_info = fn_ty.fnInfo(); 5736 const runtime_params_len = @intCast(u32, fn_ty_info.param_types.len); 5737 try inner_block.instructions.ensureTotalCapacityPrecise(gpa, runtime_params_len); 5738 try sema.air_instructions.ensureUnusedCapacity(gpa, fn_info.total_params_len * 2); // * 2 for the `addType` 5739 try sema.inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body); 5740 5741 var runtime_param_index: usize = 0; 5742 var total_param_index: usize = 0; 5743 for (fn_info.param_body) |inst| { 5744 switch (zir_tags[inst]) { 5745 .param, .param_comptime, .param_anytype, .param_anytype_comptime => {}, 5746 else => continue, 5747 } 5748 const param_ty = if (func.comptime_args) |comptime_args| t: { 5749 const arg_tv = comptime_args[total_param_index]; 5750 5751 const arg_val = if (!arg_tv.val.isGenericPoison()) 5752 arg_tv.val 5753 else if (try arg_tv.ty.onePossibleValue(mod)) |opv| 5754 opv 5755 else 5756 break :t arg_tv.ty; 5757 5758 const arg = try sema.addConstant(arg_tv.ty, arg_val); 5759 sema.inst_map.putAssumeCapacityNoClobber(inst, arg); 5760 total_param_index += 1; 5761 continue; 5762 } else fn_ty_info.param_types[runtime_param_index]; 5763 5764 const opt_opv = sema.typeHasOnePossibleValue(param_ty) catch |err| switch (err) { 5765 error.NeededSourceLocation => unreachable, 5766 error.GenericPoison => unreachable, 5767 error.ComptimeReturn => unreachable, 5768 error.ComptimeBreak => unreachable, 5769 else => |e| return e, 5770 }; 5771 if (opt_opv) |opv| { 5772 const arg = try sema.addConstant(param_ty, opv); 5773 sema.inst_map.putAssumeCapacityNoClobber(inst, arg); 5774 total_param_index += 1; 5775 runtime_param_index += 1; 5776 continue; 5777 } 5778 const air_ty = try sema.addType(param_ty); 5779 const arg_index = @intCast(u32, sema.air_instructions.len); 5780 inner_block.instructions.appendAssumeCapacity(arg_index); 5781 sema.air_instructions.appendAssumeCapacity(.{ 5782 .tag = .arg, 5783 .data = .{ .arg = .{ 5784 .ty = air_ty, 5785 .src_index = @intCast(u32, total_param_index), 5786 } }, 5787 }); 5788 sema.inst_map.putAssumeCapacityNoClobber(inst, Air.indexToRef(arg_index)); 5789 total_param_index += 1; 5790 runtime_param_index += 1; 5791 } 5792 5793 func.state = .in_progress; 5794 log.debug("set {s} to in_progress", .{decl.name}); 5795 5796 const last_arg_index = inner_block.instructions.items.len; 5797 5798 // Save the error trace as our first action in the function. 5799 // If this is unnecessary after all, Liveness will clean it up for us. 5800 const error_return_trace_index = try sema.analyzeSaveErrRetIndex(&inner_block); 5801 sema.error_return_trace_index_on_fn_entry = error_return_trace_index; 5802 inner_block.error_return_trace_index = error_return_trace_index; 5803 5804 sema.analyzeBody(&inner_block, fn_info.body) catch |err| switch (err) { 5805 // TODO make these unreachable instead of @panic 5806 error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"), 5807 error.GenericPoison => @panic("zig compiler bug: GenericPoison"), 5808 error.ComptimeReturn => @panic("zig compiler bug: ComptimeReturn"), 5809 else => |e| return e, 5810 }; 5811 5812 { 5813 var it = sema.unresolved_inferred_allocs.keyIterator(); 5814 while (it.next()) |ptr_inst| { 5815 // The lack of a resolve_inferred_alloc means that this instruction 5816 // is unused so it just has to be a no-op. 5817 sema.air_instructions.set(ptr_inst.*, .{ 5818 .tag = .alloc, 5819 .data = .{ .ty = Type.single_const_pointer_to_comptime_int }, 5820 }); 5821 } 5822 } 5823 5824 // If we don't get an error return trace from a caller, create our own. 5825 if (func.calls_or_awaits_errorable_fn and 5826 mod.comp.bin_file.options.error_return_tracing and 5827 !sema.fn_ret_ty.isError(mod)) 5828 { 5829 sema.setupErrorReturnTrace(&inner_block, last_arg_index) catch |err| switch (err) { 5830 // TODO make these unreachable instead of @panic 5831 error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"), 5832 error.GenericPoison => @panic("zig compiler bug: GenericPoison"), 5833 error.ComptimeReturn => @panic("zig compiler bug: ComptimeReturn"), 5834 error.ComptimeBreak => @panic("zig compiler bug: ComptimeBreak"), 5835 else => |e| return e, 5836 }; 5837 } 5838 5839 try wip_captures.finalize(); 5840 5841 // Copy the block into place and mark that as the main block. 5842 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + 5843 inner_block.instructions.items.len); 5844 const main_block_index = sema.addExtraAssumeCapacity(Air.Block{ 5845 .body_len = @intCast(u32, inner_block.instructions.items.len), 5846 }); 5847 sema.air_extra.appendSliceAssumeCapacity(inner_block.instructions.items); 5848 sema.air_extra.items[@enumToInt(Air.ExtraIndex.main_block)] = main_block_index; 5849 5850 func.state = .success; 5851 log.debug("set {s} to success", .{decl.name}); 5852 5853 // Finally we must resolve the return type and parameter types so that backends 5854 // have full access to type information. 5855 // Crucially, this happens *after* we set the function state to success above, 5856 // so that dependencies on the function body will now be satisfied rather than 5857 // result in circular dependency errors. 5858 sema.resolveFnTypes(fn_ty_info) catch |err| switch (err) { 5859 error.NeededSourceLocation => unreachable, 5860 error.GenericPoison => unreachable, 5861 error.ComptimeReturn => unreachable, 5862 error.ComptimeBreak => unreachable, 5863 error.AnalysisFail => { 5864 // In this case our function depends on a type that had a compile error. 5865 // We should not try to lower this function. 5866 decl.analysis = .dependency_failure; 5867 return error.AnalysisFail; 5868 }, 5869 else => |e| return e, 5870 }; 5871 5872 // Similarly, resolve any queued up types that were requested to be resolved for 5873 // the backends. 5874 for (sema.types_to_resolve.items) |inst_ref| { 5875 const ty = sema.getTmpAir().getRefType(inst_ref); 5876 sema.resolveTypeFully(ty) catch |err| switch (err) { 5877 error.NeededSourceLocation => unreachable, 5878 error.GenericPoison => unreachable, 5879 error.ComptimeReturn => unreachable, 5880 error.ComptimeBreak => unreachable, 5881 error.AnalysisFail => { 5882 // In this case our function depends on a type that had a compile error. 5883 // We should not try to lower this function. 5884 decl.analysis = .dependency_failure; 5885 return error.AnalysisFail; 5886 }, 5887 else => |e| return e, 5888 }; 5889 } 5890 5891 return Air{ 5892 .instructions = sema.air_instructions.toOwnedSlice(), 5893 .extra = try sema.air_extra.toOwnedSlice(gpa), 5894 .values = try sema.air_values.toOwnedSlice(gpa), 5895 }; 5896 } 5897 5898 fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void { 5899 const decl = mod.declPtr(decl_index); 5900 log.debug("mark outdated {*} ({s})", .{ decl, decl.name }); 5901 try mod.comp.work_queue.writeItem(.{ .analyze_decl = decl_index }); 5902 if (mod.failed_decls.fetchSwapRemove(decl_index)) |kv| { 5903 kv.value.destroy(mod.gpa); 5904 } 5905 if (mod.cimport_errors.fetchSwapRemove(decl_index)) |kv| { 5906 for (kv.value) |err| err.deinit(mod.gpa); 5907 } 5908 if (decl.has_tv and decl.owns_tv) { 5909 if (decl.val.castTag(.function)) |payload| { 5910 const func = payload.data; 5911 _ = mod.align_stack_fns.remove(func); 5912 } 5913 } 5914 if (mod.emit_h) |emit_h| { 5915 if (emit_h.failed_decls.fetchSwapRemove(decl_index)) |kv| { 5916 kv.value.destroy(mod.gpa); 5917 } 5918 } 5919 _ = mod.compile_log_decls.swapRemove(decl_index); 5920 decl.analysis = .outdated; 5921 } 5922 5923 pub fn allocateNewDecl( 5924 mod: *Module, 5925 namespace: *Namespace, 5926 src_node: Ast.Node.Index, 5927 src_scope: ?*CaptureScope, 5928 ) !Decl.Index { 5929 const decl_and_index: struct { 5930 new_decl: *Decl, 5931 decl_index: Decl.Index, 5932 } = if (mod.decls_free_list.popOrNull()) |decl_index| d: { 5933 break :d .{ 5934 .new_decl = mod.declPtr(decl_index), 5935 .decl_index = decl_index, 5936 }; 5937 } else d: { 5938 const decl = try mod.allocated_decls.addOne(mod.gpa); 5939 errdefer mod.allocated_decls.shrinkRetainingCapacity(mod.allocated_decls.len - 1); 5940 if (mod.emit_h) |mod_emit_h| { 5941 const decl_emit_h = try mod_emit_h.allocated_emit_h.addOne(mod.gpa); 5942 decl_emit_h.* = .{}; 5943 } 5944 break :d .{ 5945 .new_decl = decl, 5946 .decl_index = @intToEnum(Decl.Index, mod.allocated_decls.len - 1), 5947 }; 5948 }; 5949 5950 decl_and_index.new_decl.* = .{ 5951 .name = undefined, 5952 .src_namespace = namespace, 5953 .src_node = src_node, 5954 .src_line = undefined, 5955 .has_tv = false, 5956 .owns_tv = false, 5957 .ty = undefined, 5958 .val = undefined, 5959 .@"align" = undefined, 5960 .@"linksection" = undefined, 5961 .@"addrspace" = .generic, 5962 .analysis = .unreferenced, 5963 .deletion_flag = false, 5964 .zir_decl_index = 0, 5965 .src_scope = src_scope, 5966 .generation = 0, 5967 .is_pub = false, 5968 .is_exported = false, 5969 .has_linksection_or_addrspace = false, 5970 .has_align = false, 5971 .alive = false, 5972 .kind = .anon, 5973 }; 5974 5975 return decl_and_index.decl_index; 5976 } 5977 5978 /// Get error value for error tag `name`. 5979 pub fn getErrorValue(mod: *Module, name: []const u8) !std.StringHashMapUnmanaged(ErrorInt).KV { 5980 const gop = try mod.global_error_set.getOrPut(mod.gpa, name); 5981 if (gop.found_existing) { 5982 return std.StringHashMapUnmanaged(ErrorInt).KV{ 5983 .key = gop.key_ptr.*, 5984 .value = gop.value_ptr.*, 5985 }; 5986 } 5987 5988 errdefer assert(mod.global_error_set.remove(name)); 5989 try mod.error_name_list.ensureUnusedCapacity(mod.gpa, 1); 5990 gop.key_ptr.* = try mod.gpa.dupe(u8, name); 5991 gop.value_ptr.* = @intCast(ErrorInt, mod.error_name_list.items.len); 5992 mod.error_name_list.appendAssumeCapacity(gop.key_ptr.*); 5993 return std.StringHashMapUnmanaged(ErrorInt).KV{ 5994 .key = gop.key_ptr.*, 5995 .value = gop.value_ptr.*, 5996 }; 5997 } 5998 5999 pub fn createAnonymousDecl(mod: *Module, block: *Sema.Block, typed_value: TypedValue) !Decl.Index { 6000 const src_decl = mod.declPtr(block.src_decl); 6001 return mod.createAnonymousDeclFromDecl(src_decl, block.namespace, block.wip_capture_scope, typed_value); 6002 } 6003 6004 pub fn createAnonymousDeclFromDecl( 6005 mod: *Module, 6006 src_decl: *Decl, 6007 namespace: *Namespace, 6008 src_scope: ?*CaptureScope, 6009 tv: TypedValue, 6010 ) !Decl.Index { 6011 const new_decl_index = try mod.allocateNewDecl(namespace, src_decl.src_node, src_scope); 6012 errdefer mod.destroyDecl(new_decl_index); 6013 const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{ 6014 src_decl.name, @enumToInt(new_decl_index), 6015 }); 6016 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, tv, name); 6017 return new_decl_index; 6018 } 6019 6020 /// Takes ownership of `name` even if it returns an error. 6021 pub fn initNewAnonDecl( 6022 mod: *Module, 6023 new_decl_index: Decl.Index, 6024 src_line: u32, 6025 namespace: *Namespace, 6026 typed_value: TypedValue, 6027 name: [:0]u8, 6028 ) !void { 6029 errdefer mod.gpa.free(name); 6030 6031 const new_decl = mod.declPtr(new_decl_index); 6032 6033 new_decl.name = name; 6034 new_decl.src_line = src_line; 6035 new_decl.ty = typed_value.ty; 6036 new_decl.val = typed_value.val; 6037 new_decl.@"align" = 0; 6038 new_decl.@"linksection" = null; 6039 new_decl.has_tv = true; 6040 new_decl.analysis = .complete; 6041 new_decl.generation = mod.generation; 6042 6043 try namespace.anon_decls.putNoClobber(mod.gpa, new_decl_index, {}); 6044 6045 // The Decl starts off with alive=false and the codegen backend will set alive=true 6046 // if the Decl is referenced by an instruction or another constant. Otherwise, 6047 // the Decl will be garbage collected by the `codegen_decl` task instead of sent 6048 // to the linker. 6049 if (typed_value.ty.isFnOrHasRuntimeBits(mod)) { 6050 try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = new_decl_index }); 6051 } 6052 } 6053 6054 pub fn errNoteNonLazy( 6055 mod: *Module, 6056 src_loc: SrcLoc, 6057 parent: *ErrorMsg, 6058 comptime format: []const u8, 6059 args: anytype, 6060 ) error{OutOfMemory}!void { 6061 if (src_loc.lazy == .unneeded) { 6062 assert(parent.src_loc.lazy == .unneeded); 6063 return; 6064 } 6065 const msg = try std.fmt.allocPrint(mod.gpa, format, args); 6066 errdefer mod.gpa.free(msg); 6067 6068 parent.notes = try mod.gpa.realloc(parent.notes, parent.notes.len + 1); 6069 parent.notes[parent.notes.len - 1] = .{ 6070 .src_loc = src_loc, 6071 .msg = msg, 6072 }; 6073 } 6074 6075 pub fn getTarget(mod: Module) Target { 6076 return mod.comp.bin_file.options.target; 6077 } 6078 6079 pub fn optimizeMode(mod: Module) std.builtin.Mode { 6080 return mod.comp.bin_file.options.optimize_mode; 6081 } 6082 6083 fn lockAndClearFileCompileError(mod: *Module, file: *File) void { 6084 switch (file.status) { 6085 .success_zir, .retryable_failure => {}, 6086 .never_loaded, .parse_failure, .astgen_failure => { 6087 mod.comp.mutex.lock(); 6088 defer mod.comp.mutex.unlock(); 6089 if (mod.failed_files.fetchSwapRemove(file)) |kv| { 6090 if (kv.value) |msg| msg.destroy(mod.gpa); // Delete previous error message. 6091 } 6092 }, 6093 } 6094 } 6095 6096 pub const SwitchProngSrc = union(enum) { 6097 scalar: u32, 6098 multi: Multi, 6099 range: Multi, 6100 multi_capture: u32, 6101 6102 pub const Multi = struct { 6103 prong: u32, 6104 item: u32, 6105 }; 6106 6107 pub const RangeExpand = enum { none, first, last }; 6108 6109 /// This function is intended to be called only when it is certain that we need 6110 /// the LazySrcLoc in order to emit a compile error. 6111 pub fn resolve( 6112 prong_src: SwitchProngSrc, 6113 gpa: Allocator, 6114 decl: *Decl, 6115 switch_node_offset: i32, 6116 range_expand: RangeExpand, 6117 ) LazySrcLoc { 6118 @setCold(true); 6119 const tree = decl.getFileScope().getTree(gpa) catch |err| { 6120 // In this case we emit a warning + a less precise source location. 6121 log.warn("unable to load {s}: {s}", .{ 6122 decl.getFileScope().sub_file_path, @errorName(err), 6123 }); 6124 return LazySrcLoc.nodeOffset(0); 6125 }; 6126 const switch_node = decl.relativeToNodeIndex(switch_node_offset); 6127 const main_tokens = tree.nodes.items(.main_token); 6128 const node_datas = tree.nodes.items(.data); 6129 const node_tags = tree.nodes.items(.tag); 6130 const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange); 6131 const case_nodes = tree.extra_data[extra.start..extra.end]; 6132 6133 var multi_i: u32 = 0; 6134 var scalar_i: u32 = 0; 6135 for (case_nodes) |case_node| { 6136 const case = tree.fullSwitchCase(case_node).?; 6137 if (case.ast.values.len == 0) 6138 continue; 6139 if (case.ast.values.len == 1 and 6140 node_tags[case.ast.values[0]] == .identifier and 6141 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_")) 6142 { 6143 continue; 6144 } 6145 const is_multi = case.ast.values.len != 1 or 6146 node_tags[case.ast.values[0]] == .switch_range; 6147 6148 switch (prong_src) { 6149 .scalar => |i| if (!is_multi and i == scalar_i) return LazySrcLoc.nodeOffset( 6150 decl.nodeIndexToRelative(case.ast.values[0]), 6151 ), 6152 .multi_capture => |i| if (is_multi and i == multi_i) { 6153 return LazySrcLoc{ .node_offset_switch_prong_capture = decl.nodeIndexToRelative(case_node) }; 6154 }, 6155 .multi => |s| if (is_multi and s.prong == multi_i) { 6156 var item_i: u32 = 0; 6157 for (case.ast.values) |item_node| { 6158 if (node_tags[item_node] == .switch_range) continue; 6159 6160 if (item_i == s.item) return LazySrcLoc.nodeOffset( 6161 decl.nodeIndexToRelative(item_node), 6162 ); 6163 item_i += 1; 6164 } else unreachable; 6165 }, 6166 .range => |s| if (is_multi and s.prong == multi_i) { 6167 var range_i: u32 = 0; 6168 for (case.ast.values) |range| { 6169 if (node_tags[range] != .switch_range) continue; 6170 6171 if (range_i == s.item) switch (range_expand) { 6172 .none => return LazySrcLoc.nodeOffset( 6173 decl.nodeIndexToRelative(range), 6174 ), 6175 .first => return LazySrcLoc.nodeOffset( 6176 decl.nodeIndexToRelative(node_datas[range].lhs), 6177 ), 6178 .last => return LazySrcLoc.nodeOffset( 6179 decl.nodeIndexToRelative(node_datas[range].rhs), 6180 ), 6181 }; 6182 range_i += 1; 6183 } else unreachable; 6184 }, 6185 } 6186 if (is_multi) { 6187 multi_i += 1; 6188 } else { 6189 scalar_i += 1; 6190 } 6191 } else unreachable; 6192 } 6193 }; 6194 6195 pub const PeerTypeCandidateSrc = union(enum) { 6196 /// Do not print out error notes for candidate sources 6197 none: void, 6198 /// When we want to know the the src of candidate i, look up at 6199 /// index i in this slice 6200 override: []const ?LazySrcLoc, 6201 /// resolvePeerTypes originates from a @TypeOf(...) call 6202 typeof_builtin_call_node_offset: i32, 6203 6204 pub fn resolve( 6205 self: PeerTypeCandidateSrc, 6206 gpa: Allocator, 6207 decl: *Decl, 6208 candidate_i: usize, 6209 ) ?LazySrcLoc { 6210 @setCold(true); 6211 6212 switch (self) { 6213 .none => { 6214 return null; 6215 }, 6216 .override => |candidate_srcs| { 6217 if (candidate_i >= candidate_srcs.len) 6218 return null; 6219 return candidate_srcs[candidate_i]; 6220 }, 6221 .typeof_builtin_call_node_offset => |node_offset| { 6222 switch (candidate_i) { 6223 0 => return LazySrcLoc{ .node_offset_builtin_call_arg0 = node_offset }, 6224 1 => return LazySrcLoc{ .node_offset_builtin_call_arg1 = node_offset }, 6225 2 => return LazySrcLoc{ .node_offset_builtin_call_arg2 = node_offset }, 6226 3 => return LazySrcLoc{ .node_offset_builtin_call_arg3 = node_offset }, 6227 4 => return LazySrcLoc{ .node_offset_builtin_call_arg4 = node_offset }, 6228 5 => return LazySrcLoc{ .node_offset_builtin_call_arg5 = node_offset }, 6229 else => {}, 6230 } 6231 6232 const tree = decl.getFileScope().getTree(gpa) catch |err| { 6233 // In this case we emit a warning + a less precise source location. 6234 log.warn("unable to load {s}: {s}", .{ 6235 decl.getFileScope().sub_file_path, @errorName(err), 6236 }); 6237 return LazySrcLoc.nodeOffset(0); 6238 }; 6239 const node = decl.relativeToNodeIndex(node_offset); 6240 const node_datas = tree.nodes.items(.data); 6241 const params = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs]; 6242 6243 return LazySrcLoc{ .node_abs = params[candidate_i] }; 6244 }, 6245 } 6246 } 6247 }; 6248 6249 const FieldSrcQuery = struct { 6250 index: usize, 6251 range: enum { name, type, value, alignment } = .name, 6252 }; 6253 6254 fn queryFieldSrc( 6255 tree: Ast, 6256 query: FieldSrcQuery, 6257 file_scope: *File, 6258 container_decl: Ast.full.ContainerDecl, 6259 ) SrcLoc { 6260 var field_index: usize = 0; 6261 for (container_decl.ast.members) |member_node| { 6262 const field = tree.fullContainerField(member_node) orelse continue; 6263 if (field_index == query.index) { 6264 return switch (query.range) { 6265 .name => .{ 6266 .file_scope = file_scope, 6267 .parent_decl_node = 0, 6268 .lazy = .{ .token_abs = field.ast.main_token }, 6269 }, 6270 .type => .{ 6271 .file_scope = file_scope, 6272 .parent_decl_node = 0, 6273 .lazy = .{ .node_abs = field.ast.type_expr }, 6274 }, 6275 .value => .{ 6276 .file_scope = file_scope, 6277 .parent_decl_node = 0, 6278 .lazy = .{ .node_abs = field.ast.value_expr }, 6279 }, 6280 .alignment => .{ 6281 .file_scope = file_scope, 6282 .parent_decl_node = 0, 6283 .lazy = .{ .node_abs = field.ast.align_expr }, 6284 }, 6285 }; 6286 } 6287 field_index += 1; 6288 } 6289 unreachable; 6290 } 6291 6292 pub fn paramSrc( 6293 func_node_offset: i32, 6294 gpa: Allocator, 6295 decl: *Decl, 6296 param_i: usize, 6297 ) LazySrcLoc { 6298 @setCold(true); 6299 const tree = decl.getFileScope().getTree(gpa) catch |err| { 6300 // In this case we emit a warning + a less precise source location. 6301 log.warn("unable to load {s}: {s}", .{ 6302 decl.getFileScope().sub_file_path, @errorName(err), 6303 }); 6304 return LazySrcLoc.nodeOffset(0); 6305 }; 6306 const node = decl.relativeToNodeIndex(func_node_offset); 6307 var buf: [1]Ast.Node.Index = undefined; 6308 const full = tree.fullFnProto(&buf, node).?; 6309 var it = full.iterate(tree); 6310 var i: usize = 0; 6311 while (it.next()) |param| : (i += 1) { 6312 if (i == param_i) { 6313 if (param.anytype_ellipsis3) |some| { 6314 const main_token = tree.nodes.items(.main_token)[decl.src_node]; 6315 return .{ .token_offset_param = @bitCast(i32, some) - @bitCast(i32, main_token) }; 6316 } 6317 return .{ .node_offset_param = decl.nodeIndexToRelative(param.type_expr) }; 6318 } 6319 } 6320 unreachable; 6321 } 6322 6323 pub fn argSrc( 6324 call_node_offset: i32, 6325 gpa: Allocator, 6326 decl: *Decl, 6327 start_arg_i: usize, 6328 bound_arg_src: ?LazySrcLoc, 6329 ) LazySrcLoc { 6330 if (start_arg_i == 0 and bound_arg_src != null) return bound_arg_src.?; 6331 const arg_i = start_arg_i - @boolToInt(bound_arg_src != null); 6332 @setCold(true); 6333 const tree = decl.getFileScope().getTree(gpa) catch |err| { 6334 // In this case we emit a warning + a less precise source location. 6335 log.warn("unable to load {s}: {s}", .{ 6336 decl.getFileScope().sub_file_path, @errorName(err), 6337 }); 6338 return LazySrcLoc.nodeOffset(0); 6339 }; 6340 const node_tags = tree.nodes.items(.tag); 6341 const node = decl.relativeToNodeIndex(call_node_offset); 6342 var args: [1]Ast.Node.Index = undefined; 6343 const full = switch (node_tags[node]) { 6344 .call_one, .call_one_comma, .async_call_one, .async_call_one_comma => tree.callOne(&args, node), 6345 .call, .call_comma, .async_call, .async_call_comma => tree.callFull(node), 6346 .builtin_call => { 6347 const node_datas = tree.nodes.items(.data); 6348 const call_args_node = tree.extra_data[node_datas[node].rhs - 1]; 6349 const call_args_offset = decl.nodeIndexToRelative(call_args_node); 6350 return initSrc(call_args_offset, gpa, decl, arg_i); 6351 }, 6352 else => unreachable, 6353 }; 6354 return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(full.ast.params[arg_i])); 6355 } 6356 6357 pub fn initSrc( 6358 init_node_offset: i32, 6359 gpa: Allocator, 6360 decl: *Decl, 6361 init_index: usize, 6362 ) LazySrcLoc { 6363 @setCold(true); 6364 const tree = decl.getFileScope().getTree(gpa) catch |err| { 6365 // In this case we emit a warning + a less precise source location. 6366 log.warn("unable to load {s}: {s}", .{ 6367 decl.getFileScope().sub_file_path, @errorName(err), 6368 }); 6369 return LazySrcLoc.nodeOffset(0); 6370 }; 6371 const node_tags = tree.nodes.items(.tag); 6372 const node = decl.relativeToNodeIndex(init_node_offset); 6373 var buf: [2]Ast.Node.Index = undefined; 6374 switch (node_tags[node]) { 6375 .array_init_one, 6376 .array_init_one_comma, 6377 .array_init_dot_two, 6378 .array_init_dot_two_comma, 6379 .array_init_dot, 6380 .array_init_dot_comma, 6381 .array_init, 6382 .array_init_comma, 6383 => { 6384 const full = tree.fullArrayInit(&buf, node).?.ast.elements; 6385 return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(full[init_index])); 6386 }, 6387 .struct_init_one, 6388 .struct_init_one_comma, 6389 .struct_init_dot_two, 6390 .struct_init_dot_two_comma, 6391 .struct_init_dot, 6392 .struct_init_dot_comma, 6393 .struct_init, 6394 .struct_init_comma, 6395 => { 6396 const full = tree.fullStructInit(&buf, node).?.ast.fields; 6397 return LazySrcLoc{ .node_offset_initializer = decl.nodeIndexToRelative(full[init_index]) }; 6398 }, 6399 else => return LazySrcLoc.nodeOffset(init_node_offset), 6400 } 6401 } 6402 6403 pub fn optionsSrc(gpa: Allocator, decl: *Decl, base_src: LazySrcLoc, wanted: []const u8) LazySrcLoc { 6404 @setCold(true); 6405 const tree = decl.getFileScope().getTree(gpa) catch |err| { 6406 // In this case we emit a warning + a less precise source location. 6407 log.warn("unable to load {s}: {s}", .{ 6408 decl.getFileScope().sub_file_path, @errorName(err), 6409 }); 6410 return LazySrcLoc.nodeOffset(0); 6411 }; 6412 6413 const o_i: struct { off: i32, i: u8 } = switch (base_src) { 6414 .node_offset_builtin_call_arg0 => |n| .{ .off = n, .i = 0 }, 6415 .node_offset_builtin_call_arg1 => |n| .{ .off = n, .i = 1 }, 6416 else => unreachable, 6417 }; 6418 6419 const node = decl.relativeToNodeIndex(o_i.off); 6420 const node_datas = tree.nodes.items(.data); 6421 const node_tags = tree.nodes.items(.tag); 6422 const arg_node = switch (node_tags[node]) { 6423 .builtin_call_two, .builtin_call_two_comma => switch (o_i.i) { 6424 0 => node_datas[node].lhs, 6425 1 => node_datas[node].rhs, 6426 else => unreachable, 6427 }, 6428 .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + o_i.i], 6429 else => unreachable, 6430 }; 6431 var buf: [2]std.zig.Ast.Node.Index = undefined; 6432 const init_nodes = if (tree.fullStructInit(&buf, arg_node)) |struct_init| struct_init.ast.fields else return base_src; 6433 for (init_nodes) |init_node| { 6434 // . IDENTIFIER = init_node 6435 const name_token = tree.firstToken(init_node) - 2; 6436 const name = tree.tokenSlice(name_token); 6437 if (std.mem.eql(u8, name, wanted)) { 6438 return LazySrcLoc{ .node_offset_initializer = decl.nodeIndexToRelative(init_node) }; 6439 } 6440 } 6441 return base_src; 6442 } 6443 6444 /// Called from `performAllTheWork`, after all AstGen workers have finished, 6445 /// and before the main semantic analysis loop begins. 6446 pub fn processOutdatedAndDeletedDecls(mod: *Module) !void { 6447 // Ultimately, the goal is to queue up `analyze_decl` tasks in the work queue 6448 // for the outdated decls, but we cannot queue up the tasks until after 6449 // we find out which ones have been deleted, otherwise there would be 6450 // deleted Decl pointers in the work queue. 6451 var outdated_decls = std.AutoArrayHashMap(Decl.Index, void).init(mod.gpa); 6452 defer outdated_decls.deinit(); 6453 for (mod.import_table.values()) |file| { 6454 try outdated_decls.ensureUnusedCapacity(file.outdated_decls.items.len); 6455 for (file.outdated_decls.items) |decl_index| { 6456 outdated_decls.putAssumeCapacity(decl_index, {}); 6457 } 6458 file.outdated_decls.clearRetainingCapacity(); 6459 6460 // Handle explicitly deleted decls from the source code. This is one of two 6461 // places that Decl deletions happen. The other is in `Compilation`, after 6462 // `performAllTheWork`, where we iterate over `Module.deletion_set` and 6463 // delete Decls which are no longer referenced. 6464 // If a Decl is explicitly deleted from source, and also no longer referenced, 6465 // it may be both in this `deleted_decls` set, as well as in the 6466 // `Module.deletion_set`. To avoid deleting it twice, we remove it from the 6467 // deletion set at this time. 6468 for (file.deleted_decls.items) |decl_index| { 6469 const decl = mod.declPtr(decl_index); 6470 log.debug("deleted from source: {*} ({s})", .{ decl, decl.name }); 6471 6472 // Remove from the namespace it resides in, preserving declaration order. 6473 assert(decl.zir_decl_index != 0); 6474 _ = decl.src_namespace.decls.orderedRemoveAdapted(@as([]const u8, mem.sliceTo(decl.name, 0)), DeclAdapter{ .mod = mod }); 6475 6476 try mod.clearDecl(decl_index, &outdated_decls); 6477 mod.destroyDecl(decl_index); 6478 } 6479 file.deleted_decls.clearRetainingCapacity(); 6480 } 6481 // Finally we can queue up re-analysis tasks after we have processed 6482 // the deleted decls. 6483 for (outdated_decls.keys()) |key| { 6484 try mod.markOutdatedDecl(key); 6485 } 6486 } 6487 6488 /// Called from `Compilation.update`, after everything is done, just before 6489 /// reporting compile errors. In this function we emit exported symbol collision 6490 /// errors and communicate exported symbols to the linker backend. 6491 pub fn processExports(mod: *Module) !void { 6492 const gpa = mod.gpa; 6493 // Map symbol names to `Export` for name collision detection. 6494 var symbol_exports: std.StringArrayHashMapUnmanaged(*Export) = .{}; 6495 defer symbol_exports.deinit(gpa); 6496 6497 var it = mod.decl_exports.iterator(); 6498 while (it.next()) |entry| { 6499 const exported_decl = entry.key_ptr.*; 6500 const exports = entry.value_ptr.items; 6501 for (exports) |new_export| { 6502 const gop = try symbol_exports.getOrPut(gpa, new_export.options.name); 6503 if (gop.found_existing) { 6504 new_export.status = .failed_retryable; 6505 try mod.failed_exports.ensureUnusedCapacity(gpa, 1); 6506 const src_loc = new_export.getSrcLoc(mod); 6507 const msg = try ErrorMsg.create(gpa, src_loc, "exported symbol collision: {s}", .{ 6508 new_export.options.name, 6509 }); 6510 errdefer msg.destroy(gpa); 6511 const other_export = gop.value_ptr.*; 6512 const other_src_loc = other_export.getSrcLoc(mod); 6513 try mod.errNoteNonLazy(other_src_loc, msg, "other symbol here", .{}); 6514 mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg); 6515 new_export.status = .failed; 6516 } else { 6517 gop.value_ptr.* = new_export; 6518 } 6519 } 6520 mod.comp.bin_file.updateDeclExports(mod, exported_decl, exports) catch |err| switch (err) { 6521 error.OutOfMemory => return error.OutOfMemory, 6522 else => { 6523 const new_export = exports[0]; 6524 new_export.status = .failed_retryable; 6525 try mod.failed_exports.ensureUnusedCapacity(gpa, 1); 6526 const src_loc = new_export.getSrcLoc(mod); 6527 const msg = try ErrorMsg.create(gpa, src_loc, "unable to export: {s}", .{ 6528 @errorName(err), 6529 }); 6530 mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg); 6531 }, 6532 }; 6533 } 6534 } 6535 6536 pub fn populateTestFunctions( 6537 mod: *Module, 6538 main_progress_node: *std.Progress.Node, 6539 ) !void { 6540 const gpa = mod.gpa; 6541 const builtin_pkg = mod.main_pkg.table.get("builtin").?; 6542 const builtin_file = (mod.importPkg(builtin_pkg) catch unreachable).file; 6543 const root_decl = mod.declPtr(builtin_file.root_decl.unwrap().?); 6544 const builtin_namespace = root_decl.src_namespace; 6545 const decl_index = builtin_namespace.decls.getKeyAdapted(@as([]const u8, "test_functions"), DeclAdapter{ .mod = mod }).?; 6546 { 6547 // We have to call `ensureDeclAnalyzed` here in case `builtin.test_functions` 6548 // was not referenced by start code. 6549 mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); 6550 mod.sema_prog_node.activate(); 6551 defer { 6552 mod.sema_prog_node.end(); 6553 mod.sema_prog_node = undefined; 6554 } 6555 try mod.ensureDeclAnalyzed(decl_index); 6556 } 6557 const decl = mod.declPtr(decl_index); 6558 var buf: Type.SlicePtrFieldTypeBuffer = undefined; 6559 const tmp_test_fn_ty = decl.ty.slicePtrFieldType(&buf, mod).childType(mod); 6560 6561 const array_decl_index = d: { 6562 // Add mod.test_functions to an array decl then make the test_functions 6563 // decl reference it as a slice. 6564 var new_decl_arena = std.heap.ArenaAllocator.init(gpa); 6565 errdefer new_decl_arena.deinit(); 6566 const arena = new_decl_arena.allocator(); 6567 6568 const test_fn_vals = try arena.alloc(Value, mod.test_functions.count()); 6569 const array_decl_index = try mod.createAnonymousDeclFromDecl(decl, decl.src_namespace, null, .{ 6570 .ty = try Type.Tag.array.create(arena, .{ 6571 .len = test_fn_vals.len, 6572 .elem_type = try tmp_test_fn_ty.copy(arena), 6573 }), 6574 .val = try Value.Tag.aggregate.create(arena, test_fn_vals), 6575 }); 6576 const array_decl = mod.declPtr(array_decl_index); 6577 6578 // Add a dependency on each test name and function pointer. 6579 try array_decl.dependencies.ensureUnusedCapacity(gpa, test_fn_vals.len * 2); 6580 6581 for (mod.test_functions.keys(), 0..) |test_decl_index, i| { 6582 const test_decl = mod.declPtr(test_decl_index); 6583 const test_name_slice = mem.sliceTo(test_decl.name, 0); 6584 const test_name_decl_index = n: { 6585 var name_decl_arena = std.heap.ArenaAllocator.init(gpa); 6586 errdefer name_decl_arena.deinit(); 6587 const bytes = try name_decl_arena.allocator().dupe(u8, test_name_slice); 6588 const test_name_decl_index = try mod.createAnonymousDeclFromDecl(array_decl, array_decl.src_namespace, null, .{ 6589 .ty = try Type.array(name_decl_arena.allocator(), bytes.len, null, Type.u8, mod), 6590 .val = try Value.Tag.bytes.create(name_decl_arena.allocator(), bytes), 6591 }); 6592 try mod.declPtr(test_name_decl_index).finalizeNewArena(&name_decl_arena); 6593 break :n test_name_decl_index; 6594 }; 6595 array_decl.dependencies.putAssumeCapacityNoClobber(test_decl_index, .normal); 6596 array_decl.dependencies.putAssumeCapacityNoClobber(test_name_decl_index, .normal); 6597 try mod.linkerUpdateDecl(test_name_decl_index); 6598 6599 const field_vals = try arena.create([3]Value); 6600 field_vals.* = .{ 6601 try Value.Tag.slice.create(arena, .{ 6602 .ptr = try Value.Tag.decl_ref.create(arena, test_name_decl_index), 6603 .len = try mod.intValue(Type.usize, test_name_slice.len), 6604 }), // name 6605 try Value.Tag.decl_ref.create(arena, test_decl_index), // func 6606 Value.null, // async_frame_size 6607 }; 6608 test_fn_vals[i] = try Value.Tag.aggregate.create(arena, field_vals); 6609 } 6610 6611 try array_decl.finalizeNewArena(&new_decl_arena); 6612 break :d array_decl_index; 6613 }; 6614 try mod.linkerUpdateDecl(array_decl_index); 6615 6616 { 6617 var new_decl_arena = std.heap.ArenaAllocator.init(gpa); 6618 errdefer new_decl_arena.deinit(); 6619 const arena = new_decl_arena.allocator(); 6620 6621 { 6622 // This copy accesses the old Decl Type/Value so it must be done before `clearValues`. 6623 const new_ty = try Type.ptr(arena, mod, .{ 6624 .size = .Slice, 6625 .pointee_type = try tmp_test_fn_ty.copy(arena), 6626 .mutable = false, 6627 .@"addrspace" = .generic, 6628 }); 6629 const new_var = try gpa.create(Var); 6630 errdefer gpa.destroy(new_var); 6631 new_var.* = decl.val.castTag(.variable).?.data.*; 6632 new_var.init = try Value.Tag.slice.create(arena, .{ 6633 .ptr = try Value.Tag.decl_ref.create(arena, array_decl_index), 6634 .len = try mod.intValue(Type.usize, mod.test_functions.count()), 6635 }); 6636 const new_val = try Value.Tag.variable.create(arena, new_var); 6637 6638 // Since we are replacing the Decl's value we must perform cleanup on the 6639 // previous value. 6640 decl.clearValues(mod); 6641 decl.ty = new_ty; 6642 decl.val = new_val; 6643 decl.has_tv = true; 6644 } 6645 6646 try decl.finalizeNewArena(&new_decl_arena); 6647 } 6648 try mod.linkerUpdateDecl(decl_index); 6649 } 6650 6651 pub fn linkerUpdateDecl(mod: *Module, decl_index: Decl.Index) !void { 6652 const comp = mod.comp; 6653 6654 const no_bin_file = (comp.bin_file.options.emit == null and 6655 comp.emit_asm == null and 6656 comp.emit_llvm_ir == null and 6657 comp.emit_llvm_bc == null); 6658 6659 const dump_llvm_ir = builtin.mode == .Debug and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null); 6660 6661 if (no_bin_file and !dump_llvm_ir) return; 6662 6663 const decl = mod.declPtr(decl_index); 6664 6665 comp.bin_file.updateDecl(mod, decl_index) catch |err| switch (err) { 6666 error.OutOfMemory => return error.OutOfMemory, 6667 error.AnalysisFail => { 6668 decl.analysis = .codegen_failure; 6669 return; 6670 }, 6671 else => { 6672 const gpa = mod.gpa; 6673 try mod.failed_decls.ensureUnusedCapacity(gpa, 1); 6674 mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( 6675 gpa, 6676 decl.srcLoc(), 6677 "unable to codegen: {s}", 6678 .{@errorName(err)}, 6679 )); 6680 decl.analysis = .codegen_failure_retryable; 6681 return; 6682 }, 6683 }; 6684 } 6685 6686 fn reportRetryableFileError( 6687 mod: *Module, 6688 file: *File, 6689 comptime format: []const u8, 6690 args: anytype, 6691 ) error{OutOfMemory}!void { 6692 file.status = .retryable_failure; 6693 6694 const err_msg = try ErrorMsg.create( 6695 mod.gpa, 6696 .{ 6697 .file_scope = file, 6698 .parent_decl_node = 0, 6699 .lazy = .entire_file, 6700 }, 6701 format, 6702 args, 6703 ); 6704 errdefer err_msg.destroy(mod.gpa); 6705 6706 mod.comp.mutex.lock(); 6707 defer mod.comp.mutex.unlock(); 6708 6709 const gop = try mod.failed_files.getOrPut(mod.gpa, file); 6710 if (gop.found_existing) { 6711 if (gop.value_ptr.*) |old_err_msg| { 6712 old_err_msg.destroy(mod.gpa); 6713 } 6714 } 6715 gop.value_ptr.* = err_msg; 6716 } 6717 6718 pub fn markReferencedDeclsAlive(mod: *Module, val: Value) void { 6719 if (val.ip_index != .none) return; 6720 switch (val.tag()) { 6721 .decl_ref_mut => return mod.markDeclIndexAlive(val.castTag(.decl_ref_mut).?.data.decl_index), 6722 .extern_fn => return mod.markDeclIndexAlive(val.castTag(.extern_fn).?.data.owner_decl), 6723 .function => return mod.markDeclIndexAlive(val.castTag(.function).?.data.owner_decl), 6724 .variable => return mod.markDeclIndexAlive(val.castTag(.variable).?.data.owner_decl), 6725 .decl_ref => return mod.markDeclIndexAlive(val.cast(Value.Payload.Decl).?.data), 6726 6727 .repeated, 6728 .eu_payload, 6729 .opt_payload, 6730 .empty_array_sentinel, 6731 => return mod.markReferencedDeclsAlive(val.cast(Value.Payload.SubValue).?.data), 6732 6733 .eu_payload_ptr, 6734 .opt_payload_ptr, 6735 => return mod.markReferencedDeclsAlive(val.cast(Value.Payload.PayloadPtr).?.data.container_ptr), 6736 6737 .slice => { 6738 const slice = val.cast(Value.Payload.Slice).?.data; 6739 mod.markReferencedDeclsAlive(slice.ptr); 6740 mod.markReferencedDeclsAlive(slice.len); 6741 }, 6742 6743 .elem_ptr => { 6744 const elem_ptr = val.cast(Value.Payload.ElemPtr).?.data; 6745 return mod.markReferencedDeclsAlive(elem_ptr.array_ptr); 6746 }, 6747 .field_ptr => { 6748 const field_ptr = val.cast(Value.Payload.FieldPtr).?.data; 6749 return mod.markReferencedDeclsAlive(field_ptr.container_ptr); 6750 }, 6751 .aggregate => { 6752 for (val.castTag(.aggregate).?.data) |field_val| { 6753 mod.markReferencedDeclsAlive(field_val); 6754 } 6755 }, 6756 .@"union" => { 6757 const data = val.cast(Value.Payload.Union).?.data; 6758 mod.markReferencedDeclsAlive(data.tag); 6759 mod.markReferencedDeclsAlive(data.val); 6760 }, 6761 6762 else => {}, 6763 } 6764 } 6765 6766 pub fn markDeclAlive(mod: *Module, decl: *Decl) void { 6767 if (decl.alive) return; 6768 decl.alive = true; 6769 6770 // This is the first time we are marking this Decl alive. We must 6771 // therefore recurse into its value and mark any Decl it references 6772 // as also alive, so that any Decl referenced does not get garbage collected. 6773 mod.markReferencedDeclsAlive(decl.val); 6774 } 6775 6776 fn markDeclIndexAlive(mod: *Module, decl_index: Decl.Index) void { 6777 return mod.markDeclAlive(mod.declPtr(decl_index)); 6778 } 6779 6780 pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u8) !void { 6781 try mod.global_assembly.ensureUnusedCapacity(mod.gpa, 1); 6782 6783 const duped_source = try mod.gpa.dupe(u8, source); 6784 errdefer mod.gpa.free(duped_source); 6785 6786 mod.global_assembly.putAssumeCapacityNoClobber(decl_index, duped_source); 6787 } 6788 6789 pub fn wantDllExports(mod: Module) bool { 6790 return mod.comp.bin_file.options.dll_export_fns and mod.getTarget().os.tag == .windows; 6791 } 6792 6793 pub fn getDeclExports(mod: Module, decl_index: Decl.Index) []const *Export { 6794 if (mod.decl_exports.get(decl_index)) |l| { 6795 return l.items; 6796 } else { 6797 return &[0]*Export{}; 6798 } 6799 } 6800 6801 pub const Feature = enum { 6802 panic_fn, 6803 panic_unwrap_error, 6804 safety_check_formatted, 6805 error_return_trace, 6806 is_named_enum_value, 6807 error_set_has_value, 6808 field_reordering, 6809 }; 6810 6811 pub fn backendSupportsFeature(mod: Module, feature: Feature) bool { 6812 return switch (feature) { 6813 .panic_fn => mod.comp.bin_file.options.target.ofmt == .c or 6814 mod.comp.bin_file.options.use_llvm, 6815 .panic_unwrap_error => mod.comp.bin_file.options.target.ofmt == .c or 6816 mod.comp.bin_file.options.use_llvm, 6817 .safety_check_formatted => mod.comp.bin_file.options.target.ofmt == .c or 6818 mod.comp.bin_file.options.use_llvm, 6819 .error_return_trace => mod.comp.bin_file.options.use_llvm, 6820 .is_named_enum_value => mod.comp.bin_file.options.use_llvm, 6821 .error_set_has_value => mod.comp.bin_file.options.use_llvm or mod.comp.bin_file.options.target.isWasm(), 6822 .field_reordering => mod.comp.bin_file.options.use_llvm, 6823 }; 6824 } 6825 6826 /// Shortcut for calling `intern_pool.get`. 6827 pub fn intern(mod: *Module, key: InternPool.Key) Allocator.Error!InternPool.Index { 6828 return mod.intern_pool.get(mod.gpa, key); 6829 } 6830 6831 pub fn intType(mod: *Module, signedness: std.builtin.Signedness, bits: u16) Allocator.Error!Type { 6832 const i = try intern(mod, .{ .int_type = .{ 6833 .signedness = signedness, 6834 .bits = bits, 6835 } }); 6836 return i.toType(); 6837 } 6838 6839 pub fn arrayType(mod: *Module, info: InternPool.Key.ArrayType) Allocator.Error!Type { 6840 if (std.debug.runtime_safety and info.sentinel != .none) { 6841 const sent_ty = mod.intern_pool.indexToKey(info.sentinel).typeOf(); 6842 assert(sent_ty == info.child); 6843 } 6844 const i = try intern(mod, .{ .array_type = info }); 6845 return i.toType(); 6846 } 6847 6848 pub fn vectorType(mod: *Module, info: InternPool.Key.VectorType) Allocator.Error!Type { 6849 const i = try intern(mod, .{ .vector_type = info }); 6850 return i.toType(); 6851 } 6852 6853 pub fn optionalType(mod: *Module, child_type: InternPool.Index) Allocator.Error!Type { 6854 const i = try intern(mod, .{ .opt_type = child_type }); 6855 return i.toType(); 6856 } 6857 6858 pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type { 6859 if (std.debug.runtime_safety and info.sentinel != .none) { 6860 const sent_ty = mod.intern_pool.indexToKey(info.sentinel).typeOf(); 6861 assert(sent_ty == info.elem_type); 6862 } 6863 const i = try intern(mod, .{ .ptr_type = info }); 6864 return i.toType(); 6865 } 6866 6867 pub fn singleMutPtrType(mod: *Module, child_type: Type) Allocator.Error!Type { 6868 if (child_type.ip_index == .none) { 6869 // TODO remove this after all types can be represented via the InternPool 6870 return Type.Tag.pointer.create(mod.tmp_hack_arena.allocator(), .{ 6871 .pointee_type = child_type, 6872 .@"addrspace" = .generic, 6873 }); 6874 } 6875 return ptrType(mod, .{ .elem_type = child_type.ip_index }); 6876 } 6877 6878 pub fn singleConstPtrType(mod: *Module, child_type: Type) Allocator.Error!Type { 6879 if (child_type.ip_index == .none) { 6880 // TODO remove this after all types can be represented via the InternPool 6881 return Type.Tag.pointer.create(mod.tmp_hack_arena.allocator(), .{ 6882 .pointee_type = child_type, 6883 .mutable = false, 6884 .@"addrspace" = .generic, 6885 }); 6886 } 6887 return ptrType(mod, .{ .elem_type = child_type.ip_index, .is_const = true }); 6888 } 6889 6890 pub fn ptrIntValue(mod: *Module, ty: Type, x: u64) Allocator.Error!Value { 6891 assert(ty.zigTypeTag(mod) == .Pointer); 6892 const i = try intern(mod, .{ .ptr = .{ 6893 .ty = ty.ip_index, 6894 .addr = .{ .int = try intern(mod, .{ .int = .{ 6895 .ty = ty.ip_index, 6896 .storage = .{ .u64 = x }, 6897 } }) }, 6898 } }); 6899 return i.toValue(); 6900 } 6901 6902 pub fn intValue(mod: *Module, ty: Type, x: anytype) Allocator.Error!Value { 6903 if (std.debug.runtime_safety) { 6904 const tag = ty.zigTypeTag(mod); 6905 assert(tag == .Int or tag == .ComptimeInt); 6906 } 6907 if (std.math.cast(u64, x)) |casted| return intValue_u64(mod, ty, casted); 6908 if (std.math.cast(i64, x)) |casted| return intValue_i64(mod, ty, casted); 6909 var limbs_buffer: [4]usize = undefined; 6910 var big_int = BigIntMutable.init(&limbs_buffer, x); 6911 return intValue_big(mod, ty, big_int.toConst()); 6912 } 6913 6914 pub fn intValue_big(mod: *Module, ty: Type, x: BigIntConst) Allocator.Error!Value { 6915 const i = try intern(mod, .{ .int = .{ 6916 .ty = ty.ip_index, 6917 .storage = .{ .big_int = x }, 6918 } }); 6919 return i.toValue(); 6920 } 6921 6922 pub fn intValue_u64(mod: *Module, ty: Type, x: u64) Allocator.Error!Value { 6923 const i = try intern(mod, .{ .int = .{ 6924 .ty = ty.ip_index, 6925 .storage = .{ .u64 = x }, 6926 } }); 6927 return i.toValue(); 6928 } 6929 6930 pub fn intValue_i64(mod: *Module, ty: Type, x: i64) Allocator.Error!Value { 6931 const i = try intern(mod, .{ .int = .{ 6932 .ty = ty.ip_index, 6933 .storage = .{ .i64 = x }, 6934 } }); 6935 return i.toValue(); 6936 } 6937 6938 pub fn smallestUnsignedInt(mod: *Module, max: u64) Allocator.Error!Type { 6939 return intType(mod, .unsigned, Type.smallestUnsignedBits(max)); 6940 } 6941 6942 /// Returns the smallest possible integer type containing both `min` and 6943 /// `max`. Asserts that neither value is undef. 6944 /// TODO: if #3806 is implemented, this becomes trivial 6945 pub fn intFittingRange(mod: *Module, min: Value, max: Value) !Type { 6946 assert(!min.isUndef()); 6947 assert(!max.isUndef()); 6948 6949 if (std.debug.runtime_safety) { 6950 assert(Value.order(min, max, mod).compare(.lte)); 6951 } 6952 6953 const sign = min.orderAgainstZero(mod) == .lt; 6954 6955 const min_val_bits = intBitsForValue(mod, min, sign); 6956 const max_val_bits = intBitsForValue(mod, max, sign); 6957 6958 return mod.intType( 6959 if (sign) .signed else .unsigned, 6960 @max(min_val_bits, max_val_bits), 6961 ); 6962 } 6963 6964 /// Given a value representing an integer, returns the number of bits necessary to represent 6965 /// this value in an integer. If `sign` is true, returns the number of bits necessary in a 6966 /// twos-complement integer; otherwise in an unsigned integer. 6967 /// Asserts that `val` is not undef. If `val` is negative, asserts that `sign` is true. 6968 pub fn intBitsForValue(mod: *Module, val: Value, sign: bool) u16 { 6969 assert(!val.isUndef()); 6970 6971 const key = mod.intern_pool.indexToKey(val.ip_index); 6972 switch (key.int.storage) { 6973 .i64 => |x| { 6974 if (std.math.cast(u64, x)) |casted| return Type.smallestUnsignedBits(casted); 6975 assert(sign); 6976 // Protect against overflow in the following negation. 6977 if (x == std.math.minInt(i64)) return 64; 6978 return Type.smallestUnsignedBits(@intCast(u64, -x - 1)) + 1; 6979 }, 6980 .u64 => |x| { 6981 return Type.smallestUnsignedBits(x) + @boolToInt(sign); 6982 }, 6983 .big_int => |big| { 6984 if (big.positive) return @intCast(u16, big.bitCountAbs() + @boolToInt(sign)); 6985 6986 // Zero is still a possibility, in which case unsigned is fine 6987 if (big.eqZero()) return 0; 6988 6989 return @intCast(u16, big.bitCountTwosComp()); 6990 }, 6991 } 6992 } 6993 6994 pub const AtomicPtrAlignmentError = error{ 6995 FloatTooBig, 6996 IntTooBig, 6997 BadType, 6998 OutOfMemory, 6999 }; 7000 7001 pub const AtomicPtrAlignmentDiagnostics = struct { 7002 bits: u16 = undefined, 7003 max_bits: u16 = undefined, 7004 }; 7005 7006 /// If ABI alignment of `ty` is OK for atomic operations, returns 0. 7007 /// Otherwise returns the alignment required on a pointer for the target 7008 /// to perform atomic operations. 7009 // TODO this function does not take into account CPU features, which can affect 7010 // this value. Audit this! 7011 pub fn atomicPtrAlignment( 7012 mod: *Module, 7013 ty: Type, 7014 diags: *AtomicPtrAlignmentDiagnostics, 7015 ) AtomicPtrAlignmentError!u32 { 7016 const target = mod.getTarget(); 7017 const max_atomic_bits: u16 = switch (target.cpu.arch) { 7018 .avr, 7019 .msp430, 7020 .spu_2, 7021 => 16, 7022 7023 .arc, 7024 .arm, 7025 .armeb, 7026 .hexagon, 7027 .m68k, 7028 .le32, 7029 .mips, 7030 .mipsel, 7031 .nvptx, 7032 .powerpc, 7033 .powerpcle, 7034 .r600, 7035 .riscv32, 7036 .sparc, 7037 .sparcel, 7038 .tce, 7039 .tcele, 7040 .thumb, 7041 .thumbeb, 7042 .x86, 7043 .xcore, 7044 .amdil, 7045 .hsail, 7046 .spir, 7047 .kalimba, 7048 .lanai, 7049 .shave, 7050 .wasm32, 7051 .renderscript32, 7052 .csky, 7053 .spirv32, 7054 .dxil, 7055 .loongarch32, 7056 .xtensa, 7057 => 32, 7058 7059 .amdgcn, 7060 .bpfel, 7061 .bpfeb, 7062 .le64, 7063 .mips64, 7064 .mips64el, 7065 .nvptx64, 7066 .powerpc64, 7067 .powerpc64le, 7068 .riscv64, 7069 .sparc64, 7070 .s390x, 7071 .amdil64, 7072 .hsail64, 7073 .spir64, 7074 .wasm64, 7075 .renderscript64, 7076 .ve, 7077 .spirv64, 7078 .loongarch64, 7079 => 64, 7080 7081 .aarch64, 7082 .aarch64_be, 7083 .aarch64_32, 7084 => 128, 7085 7086 .x86_64 => if (std.Target.x86.featureSetHas(target.cpu.features, .cx16)) 128 else 64, 7087 }; 7088 7089 const int_ty = switch (ty.zigTypeTag(mod)) { 7090 .Int => ty, 7091 .Enum => try ty.intTagType(mod), 7092 .Float => { 7093 const bit_count = ty.floatBits(target); 7094 if (bit_count > max_atomic_bits) { 7095 diags.* = .{ 7096 .bits = bit_count, 7097 .max_bits = max_atomic_bits, 7098 }; 7099 return error.FloatTooBig; 7100 } 7101 return 0; 7102 }, 7103 .Bool => return 0, 7104 else => { 7105 if (ty.isPtrAtRuntime(mod)) return 0; 7106 return error.BadType; 7107 }, 7108 }; 7109 7110 const bit_count = int_ty.intInfo(mod).bits; 7111 if (bit_count > max_atomic_bits) { 7112 diags.* = .{ 7113 .bits = bit_count, 7114 .max_bits = max_atomic_bits, 7115 }; 7116 return error.IntTooBig; 7117 } 7118 7119 return 0; 7120 }