@@ -170,12 +170,14 @@ pub type CompileTimeInterpCx<'tcx> = InterpCx<'tcx, CompileTimeMachine<'tcx>>;
170170#[ derive( Debug , PartialEq , Eq , Copy , Clone ) ]
171171pub enum MemoryKind {
172172 Heap ,
173+ HeapLeaked ,
173174}
174175
175176impl fmt:: Display for MemoryKind {
176177 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
177178 match self {
178179 MemoryKind :: Heap => write ! ( f, "heap allocation" ) ,
180+ MemoryKind :: HeapLeaked => write ! ( f, "leaked heap allocation" ) ,
179181 }
180182 }
181183}
@@ -185,6 +187,17 @@ impl interpret::MayLeak for MemoryKind {
185187 fn may_leak ( self ) -> bool {
186188 match self {
187189 MemoryKind :: Heap => false ,
190+ MemoryKind :: HeapLeaked => true ,
191+ }
192+ }
193+ }
194+
195+ impl interpret:: IsConstHeap for MemoryKind {
196+ #[ inline( always) ]
197+ fn is_const_heap ( & self ) -> bool {
198+ match self {
199+ MemoryKind :: Heap => true ,
200+ MemoryKind :: HeapLeaked => false ,
188201 }
189202 }
190203}
@@ -197,6 +210,13 @@ impl interpret::MayLeak for ! {
197210 }
198211}
199212
213+ impl interpret:: IsConstHeap for ! {
214+ #[ inline( always) ]
215+ fn is_const_heap ( & self ) -> bool {
216+ * self
217+ }
218+ }
219+
200220impl < ' tcx > CompileTimeInterpCx < ' tcx > {
201221 fn location_triple_for_span ( & self , span : Span ) -> ( Symbol , u32 , u32 ) {
202222 let topmost = span. ctxt ( ) . outer_expn ( ) . expansion_cause ( ) . unwrap_or ( span) ;
@@ -457,6 +477,46 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
457477 ) ?;
458478 }
459479 }
480+
481+ sym:: const_leak => {
482+ let ptr = ecx. read_pointer ( & args[ 0 ] ) ?;
483+ let size = ecx. read_scalar ( & args[ 1 ] ) ?. to_target_usize ( ecx) ?;
484+ let align = ecx. read_scalar ( & args[ 2 ] ) ?. to_target_usize ( ecx) ?;
485+
486+ let size = Size :: from_bytes ( size) ;
487+ let align = match Align :: from_bytes ( align) {
488+ Ok ( a) => a,
489+ Err ( err) => throw_ub_custom ! (
490+ fluent:: const_eval_invalid_align_details,
491+ name = "const_leak" ,
492+ err_kind = err. diag_ident( ) ,
493+ align = err. align( )
494+ ) ,
495+ } ;
496+
497+ // If an allocation is created in an another const,
498+ // we don't reallocate it.
499+ let ( alloc_id, _, _) = ecx. ptr_get_alloc_id ( ptr, 0 ) ?;
500+ let is_allocated_in_another_const = matches ! (
501+ ecx. tcx. try_get_global_alloc( alloc_id) ,
502+ Some ( interpret:: GlobalAlloc :: Memory ( _) )
503+ ) ;
504+
505+ if is_allocated_in_another_const {
506+ // just return the pointer that was passed in
507+ ecx. write_pointer ( ptr, dest) ?;
508+ } else {
509+ let ptr = ecx. leak_const_heap_ptr (
510+ ptr,
511+ size,
512+ align,
513+ interpret:: MemoryKind :: Machine ( MemoryKind :: Heap ) ,
514+ interpret:: MemoryKind :: Machine ( MemoryKind :: HeapLeaked ) ,
515+ ) ?;
516+ ecx. write_pointer ( ptr, dest) ?;
517+ }
518+ }
519+
460520 // The intrinsic represents whether the value is known to the optimizer (LLVM).
461521 // We're not doing any optimizations here, so there is no optimizer that could know the value.
462522 // (We know the value here in the machine of course, but this is the runtime of that code,
0 commit comments