@@ -411,6 +411,46 @@ pub const WipCaptureScope = struct {
411411 }
412412};
413413
414+ const ValueArena = struct {
415+ state : std.heap.ArenaAllocator.State ,
416+ state_acquired : ? * std.heap.ArenaAllocator.State = null ,
417+
418+ /// If this ValueArena replaced an existing one during re-analysis, this is the previous instance
419+ prev : ? * ValueArena = null ,
420+
421+ /// Returns an allocator backed by either promoting `state`, or by the existing ArenaAllocator
422+ /// that has already promoted `state`. `out_arena_allocator` provides storage for the initial promotion,
423+ /// and must live until the matching call to release().
424+ pub fn acquire (self : * ValueArena , child_allocator : Allocator , out_arena_allocator : * std.heap.ArenaAllocator ) Allocator {
425+ if (self .state_acquired ) | state_acquired | {
426+ return @fieldParentPtr (std .heap .ArenaAllocator , "state" , state_acquired ).allocator ();
427+ }
428+
429+ out_arena_allocator .* = self .state .promote (child_allocator );
430+ self .state_acquired = & out_arena_allocator .state ;
431+ return out_arena_allocator .allocator ();
432+ }
433+
434+ /// Releases the allocator acquired by `acquire. `arena_allocator` must match the one passed to `acquire`.
435+ pub fn release (self : * ValueArena , arena_allocator : * std.heap.ArenaAllocator ) void {
436+ if (@fieldParentPtr (std .heap .ArenaAllocator , "state" , self .state_acquired .? ) == arena_allocator ) {
437+ self .state = self .state_acquired .?.* ;
438+ self .state_acquired = null ;
439+ }
440+ }
441+
442+ pub fn deinit (self : ValueArena , child_allocator : Allocator ) void {
443+ assert (self .state_acquired == null );
444+
445+ const prev = self .prev ;
446+ self .state .promote (child_allocator ).deinit ();
447+
448+ if (prev ) | p | {
449+ p .deinit (child_allocator );
450+ }
451+ }
452+ };
453+
414454pub const Decl = struct {
415455 /// Allocated with Module's allocator; outlives the ZIR code.
416456 name : [* :0 ]const u8 ,
@@ -429,7 +469,7 @@ pub const Decl = struct {
429469 @"addrspace" : std.builtin.AddressSpace ,
430470 /// The memory for ty, val, align, linksection, and captures.
431471 /// If this is `null` then there is no memory management needed.
432- value_arena : ? * std.heap.ArenaAllocator.State = null ,
472+ value_arena : ? * ValueArena = null ,
433473 /// The direct parent namespace of the Decl.
434474 /// Reference to externally owned memory.
435475 /// In the case of the Decl corresponding to a file, this is
@@ -607,15 +647,15 @@ pub const Decl = struct {
607647 variable .deinit (gpa );
608648 gpa .destroy (variable );
609649 }
610- if (decl .value_arena ) | arena_state | {
650+ if (decl .value_arena ) | value_arena | {
611651 if (decl .owns_tv ) {
612652 if (decl .val .castTag (.str_lit )) | str_lit | {
613653 mod .string_literal_table .getPtrContext (str_lit .data , .{
614654 .bytes = & mod .string_literal_bytes ,
615655 }).?.* = .none ;
616656 }
617657 }
618- arena_state . promote ( gpa ). deinit ();
658+ value_arena . deinit (gpa );
619659 decl .value_arena = null ;
620660 decl .has_tv = false ;
621661 decl .owns_tv = false ;
@@ -624,9 +664,9 @@ pub const Decl = struct {
624664
625665 pub fn finalizeNewArena (decl : * Decl , arena : * std.heap.ArenaAllocator ) ! void {
626666 assert (decl .value_arena == null );
627- const arena_state = try arena .allocator ().create (std . heap . ArenaAllocator . State );
628- arena_state .* = arena .state ;
629- decl .value_arena = arena_state ;
667+ const value_arena = try arena .allocator ().create (ValueArena );
668+ value_arena .* = .{ . state = arena .state } ;
669+ decl .value_arena = value_arena ;
630670 }
631671
632672 /// This name is relative to the containing namespace of the decl.
@@ -4537,15 +4577,20 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
45374577 // We need the memory for the Type to go into the arena for the Decl
45384578 var decl_arena = std .heap .ArenaAllocator .init (gpa );
45394579 const decl_arena_allocator = decl_arena .allocator ();
4540-
4541- const decl_arena_state = blk : {
4580+ const decl_value_arena = blk : {
45424581 errdefer decl_arena .deinit ();
4543- const s = try decl_arena_allocator .create (std .heap .ArenaAllocator .State );
4582+ const s = try decl_arena_allocator .create (ValueArena );
4583+ s .* = .{ .state = undefined };
45444584 break :blk s ;
45454585 };
45464586 defer {
4547- decl_arena_state .* = decl_arena .state ;
4548- decl .value_arena = decl_arena_state ;
4587+ if (decl .value_arena ) | value_arena | {
4588+ assert (value_arena .state_acquired == null );
4589+ decl_value_arena .prev = value_arena ;
4590+ }
4591+
4592+ decl_value_arena .state = decl_arena .state ;
4593+ decl .value_arena = decl_value_arena ;
45494594 }
45504595
45514596 var analysis_arena = std .heap .ArenaAllocator .init (gpa );
@@ -5493,9 +5538,9 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air {
54935538 const decl = mod .declPtr (decl_index );
54945539
54955540 // Use the Decl's arena for captured values.
5496- var decl_arena = decl . value_arena .? . promote ( gpa ) ;
5497- defer decl .value_arena .?.* = decl_arena . state ;
5498- const decl_arena_allocator = decl_arena . allocator ( );
5541+ var decl_arena : std.heap.ArenaAllocator = undefined ;
5542+ const decl_arena_allocator = decl .value_arena .? .acquire ( gpa , & decl_arena ) ;
5543+ defer decl . value_arena .? . release ( & decl_arena );
54995544
55005545 var sema : Sema = .{
55015546 .mod = mod ,
0 commit comments