@@ -19,9 +19,12 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
1919use rustc_hir as hir;
2020use rustc_hir:: definitions:: { DefPathData , DisambiguatorState } ;
2121use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrs ;
22- use rustc_middle:: mir:: interpret:: { ConstAllocation , CtfeProvenance , InterpResult } ;
22+ use rustc_middle:: mir:: interpret:: {
23+ AllocBytes , ConstAllocation , CtfeProvenance , InterpResult , Provenance ,
24+ } ;
2325use rustc_middle:: query:: TyCtxtAt ;
2426use rustc_middle:: span_bug;
27+ use rustc_middle:: ty:: TyCtxt ;
2528use rustc_middle:: ty:: layout:: TyAndLayout ;
2629use rustc_span:: def_id:: LocalDefId ;
2730use tracing:: { instrument, trace} ;
@@ -52,39 +55,30 @@ impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> {
5255 }
5356}
5457
55- /// Intern an allocation. Returns `Err` if the allocation does not exist in the local memory.
56- ///
57- /// `mutability` can be used to force immutable interning: if it is `Mutability::Not`, the
58- /// allocation is interned immutably; if it is `Mutability::Mut`, then the allocation *must be*
59- /// already mutable (as a sanity check).
60- ///
61- /// Returns an iterator over all relocations referred to by this allocation.
62- fn intern_shallow < ' tcx , M : CompileTimeMachine < ' tcx > > (
63- ecx : & mut InterpCx < ' tcx , M > ,
64- alloc_id : AllocId ,
58+ fn prepare_alloc < ' tcx , Prov : Provenance , Extra , Bytes : AllocBytes > (
59+ tcx : TyCtxt < ' tcx > ,
60+ kind : MemoryKind < const_eval:: MemoryKind > ,
61+ alloc : & mut Allocation < Prov , Extra , Bytes > ,
6562 mutability : Mutability ,
66- disambiguator : Option < & mut DisambiguatorState > ,
67- ) -> Result < impl Iterator < Item = CtfeProvenance > + ' tcx , InternError > {
68- trace ! ( "intern_shallow {:?}" , alloc_id) ;
69- // remove allocation
70- // FIXME(#120456) - is `swap_remove` correct?
71- let Some ( ( kind, mut alloc) ) = ecx. memory . alloc_map . swap_remove ( & alloc_id) else {
72- return Err ( InternError :: DanglingPointer ) ;
73- } ;
74-
63+ ) -> Result < ( ) , InternError > {
7564 match kind {
7665 MemoryKind :: Machine ( const_eval:: MemoryKind :: Heap { was_made_global } ) => {
7766 if !was_made_global {
7867 // Attempting to intern a `const_allocate`d pointer that was not made global via
79- // `const_make_global`. We want to error here, but we have to first put the
80- // allocation back into the `alloc_map` to keep things in a consistent state.
81- ecx. memory . alloc_map . insert ( alloc_id, ( kind, alloc) ) ;
68+ // `const_make_global`.
69+ tcx. dcx ( ) . delayed_bug ( "non-global heap allocation in const value" ) ;
8270 return Err ( InternError :: ConstAllocNotGlobal ) ;
8371 }
8472 }
8573 MemoryKind :: Stack | MemoryKind :: CallerLocation => { }
8674 }
8775
76+ if !alloc. provenance_merge_bytes ( & tcx) {
77+ // Per-byte provenance is not supported by backends, so we cannot accept it here.
78+ tcx. dcx ( ) . delayed_bug ( "partial pointer in const value" ) ;
79+ return Err ( InternError :: PartialPointer ) ;
80+ }
81+
8882 // Set allocation mutability as appropriate. This is used by LLVM to put things into
8983 // read-only memory, and also by Miri when evaluating other globals that
9084 // access this one.
@@ -97,6 +91,36 @@ fn intern_shallow<'tcx, M: CompileTimeMachine<'tcx>>(
9791 assert_eq ! ( alloc. mutability, Mutability :: Mut ) ;
9892 }
9993 }
94+ Ok ( ( ) )
95+ }
96+
97+ /// Intern an allocation. Returns `Err` if the allocation does not exist in the local memory.
98+ ///
99+ /// `mutability` can be used to force immutable interning: if it is `Mutability::Not`, the
100+ /// allocation is interned immutably; if it is `Mutability::Mut`, then the allocation *must be*
101+ /// already mutable (as a sanity check).
102+ ///
103+ /// Returns an iterator over all relocations referred to by this allocation.
104+ fn intern_shallow < ' tcx , M : CompileTimeMachine < ' tcx > > (
105+ ecx : & mut InterpCx < ' tcx , M > ,
106+ alloc_id : AllocId ,
107+ mutability : Mutability ,
108+ disambiguator : Option < & mut DisambiguatorState > ,
109+ ) -> Result < impl Iterator < Item = CtfeProvenance > + ' tcx , InternError > {
110+ trace ! ( "intern_shallow {:?}" , alloc_id) ;
111+ // remove allocation
112+ // FIXME(#120456) - is `swap_remove` correct?
113+ let Some ( ( kind, mut alloc) ) = ecx. memory . alloc_map . swap_remove ( & alloc_id) else {
114+ return Err ( InternError :: DanglingPointer ) ;
115+ } ;
116+
117+ if let Err ( err) = prepare_alloc ( * ecx. tcx , kind, & mut alloc, mutability) {
118+ // We want to error here, but we have to first put the
119+ // allocation back into the `alloc_map` to keep things in a consistent state.
120+ ecx. memory . alloc_map . insert ( alloc_id, ( kind, alloc) ) ;
121+ return Err ( err) ;
122+ }
123+
100124 // link the alloc id to the actual allocation
101125 let alloc = ecx. tcx . mk_const_alloc ( alloc) ;
102126 if let Some ( static_id) = ecx. machine . static_def_id ( ) {
@@ -166,6 +190,7 @@ pub enum InternError {
166190 BadMutablePointer ,
167191 DanglingPointer ,
168192 ConstAllocNotGlobal ,
193+ PartialPointer ,
169194}
170195
171196/// Intern `ret` and everything it references.
@@ -221,21 +246,18 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>(
221246 let mut todo: Vec < _ > = if is_static {
222247 // Do not steal the root allocation, we need it later to create the return value of `eval_static_initializer`.
223248 // But still change its mutability to match the requested one.
224- let alloc = ecx. memory . alloc_map . get_mut ( & base_alloc_id) . unwrap ( ) ;
225- alloc . 1 . mutability = base_mutability;
226- alloc. 1 . provenance ( ) . ptrs ( ) . iter ( ) . map ( |& ( _, prov) | prov) . collect ( )
249+ let ( kind , alloc) = ecx. memory . alloc_map . get_mut ( & base_alloc_id) . unwrap ( ) ;
250+ prepare_alloc ( * ecx . tcx , * kind , alloc , base_mutability) ? ;
251+ alloc. provenance ( ) . ptrs ( ) . iter ( ) . map ( |& ( _, prov) | prov) . collect ( )
227252 } else {
228- intern_shallow ( ecx, base_alloc_id, base_mutability, Some ( & mut disambiguator) )
229- . unwrap ( )
230- . collect ( )
253+ intern_shallow ( ecx, base_alloc_id, base_mutability, Some ( & mut disambiguator) ) ?. collect ( )
231254 } ;
232255 // We need to distinguish "has just been interned" from "was already in `tcx`",
233256 // so we track this in a separate set.
234257 let mut just_interned: FxHashSet < _ > = std:: iter:: once ( base_alloc_id) . collect ( ) ;
235258 // Whether we encountered a bad mutable pointer.
236259 // We want to first report "dangling" and then "mutable", so we need to delay reporting these
237260 // errors.
238- let mut result = Ok ( ( ) ) ;
239261 let mut found_bad_mutable_ptr = false ;
240262
241263 // Keep interning as long as there are things to intern.
@@ -310,28 +332,23 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>(
310332 // okay with losing some potential for immutability here. This can anyway only affect
311333 // `static mut`.
312334 just_interned. insert ( alloc_id) ;
313- match intern_shallow ( ecx, alloc_id, inner_mutability, Some ( & mut disambiguator) ) {
314- Ok ( nested) => todo. extend ( nested) ,
315- Err ( err) => {
316- ecx. tcx . dcx ( ) . delayed_bug ( "error during const interning" ) ;
317- result = Err ( err) ;
318- }
319- }
335+ let next = intern_shallow ( ecx, alloc_id, inner_mutability, Some ( & mut disambiguator) ) ?;
336+ todo. extend ( next) ;
320337 }
321- if found_bad_mutable_ptr && result . is_ok ( ) {
338+ if found_bad_mutable_ptr {
322339 // We found a mutable pointer inside a const where inner allocations should be immutable,
323340 // and there was no other error. This should usually never happen! However, this can happen
324341 // in unleash-miri mode, so report it as a normal error then.
325342 if ecx. tcx . sess . opts . unstable_opts . unleash_the_miri_inside_of_you {
326- result = Err ( InternError :: BadMutablePointer ) ;
343+ return Err ( InternError :: BadMutablePointer ) ;
327344 } else {
328345 span_bug ! (
329346 ecx. tcx. span,
330347 "the static const safety checks accepted a mutable pointer they should not have accepted"
331348 ) ;
332349 }
333350 }
334- result
351+ Ok ( ( ) )
335352}
336353
337354/// Intern `ret`. This function assumes that `ret` references no other allocation.
0 commit comments