@@ -114,6 +114,11 @@ pub(crate) struct CodegenCx<'ll, 'tcx> {
114114 /// Pre-reserved constant memory bytes for statics with explicit placement overrides.
115115 /// Computed lazily on first call to `static_addrspace`.
116116 constant_memory_reserved : Cell < Option < u64 > > ,
117+ /// Tracks how many reserved bytes have already been placed (and thus already
118+ /// counted in `constant_memory_usage`). This prevents double-counting: without it,
119+ /// the effective limit for automatic statics subtracts the full reservation even
120+ /// though some of that reserved space is already reflected in `constant_memory_usage`.
121+ explicit_constant_memory_placed : Cell < u64 > ,
117122 /// Cache of address space decisions per static instance, to prevent
118123 /// double-counting when `static_addrspace` is called multiple times
119124 /// (e.g., during both predefine and RAUW phases).
@@ -190,6 +195,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
190195 last_call_llfn : Cell :: new ( None ) ,
191196 constant_memory_usage : Cell :: new ( 0 ) ,
192197 constant_memory_reserved : Cell :: new ( None ) ,
198+ explicit_constant_memory_placed : Cell :: new ( 0 ) ,
193199 static_addrspace_cache : Default :: default ( ) ,
194200 } ;
195201 cx. build_intrinsics_map ( ) ;
@@ -418,7 +424,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
418424
419425 // Mutable or non-freeze statics cannot go in constant memory
420426 if is_mutable || !self . type_is_freeze ( ty) {
421- return AddressSpace :: ZERO ;
427+ return AddressSpace ( 1 ) ;
422428 }
423429
424430 // Resolve memory space from overrides (priorities 2-4)
@@ -440,14 +446,18 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
440446 let current_usage = self . constant_memory_usage . get ( ) ;
441447 let new_usage = current_usage + size_bytes;
442448
443- // For automatic placement, the effective limit is reduced by the space
444- // reserved for explicitly placed statics (so they always fit).
449+ // For automatic placement, the effective limit is reduced by the reserved
450+ // space that has NOT yet been placed. Reserved space that has already been
451+ // placed is already reflected in `constant_memory_usage`, so subtracting
452+ // the full reservation would double-count it.
445453 // For explicit overrides, use the full limit.
446454 let effective_limit = if explicit_constant {
447455 CONSTANT_MEMORY_SIZE_LIMIT_BYTES
448456 } else {
449457 let reserved = self . get_constant_memory_reserved ( ) ;
450- CONSTANT_MEMORY_SIZE_LIMIT_BYTES . saturating_sub ( reserved)
458+ let already_placed = self . explicit_constant_memory_placed . get ( ) ;
459+ let remaining_reservation = reserved. saturating_sub ( already_placed) ;
460+ CONSTANT_MEMORY_SIZE_LIMIT_BYTES . saturating_sub ( remaining_reservation)
451461 } ;
452462
453463 // Check if this single static is too large for constant memory
@@ -499,6 +509,10 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
499509
500510 // If successfully placed in constant memory: update cumulative usage
501511 self . constant_memory_usage . set ( new_usage) ;
512+ if explicit_constant {
513+ self . explicit_constant_memory_placed
514+ . set ( self . explicit_constant_memory_placed . get ( ) + size_bytes) ;
515+ }
502516
503517 // If approaching the threshold: warns
504518 if new_usage > CONSTANT_MEMORY_WARNING_THRESHOLD_BYTES
0 commit comments