33//! After a const evaluation has computed a value, before we destroy the const evaluator's session
44//! memory, we need to extract all memory allocations to the global memory pool so they stay around.
55
6- use rustc:: ty:: { Ty , ParamEnv , self } ;
6+ use rustc:: ty:: { Ty , self } ;
77use rustc:: mir:: interpret:: { InterpResult , ErrorHandled } ;
88use rustc:: hir;
99use rustc:: hir:: def_id:: DefId ;
@@ -18,10 +18,10 @@ use super::{
1818use crate :: const_eval:: { CompileTimeInterpreter , CompileTimeEvalContext } ;
1919
2020struct InternVisitor < ' rt , ' mir , ' tcx > {
21- /// previously encountered safe references
22- ref_tracking : & ' rt mut RefTracking < ( MPlaceTy < ' tcx > , Mutability , InternMode ) > ,
21+ /// The ectx from which we intern.
2322 ecx : & ' rt mut CompileTimeEvalContext < ' mir , ' tcx > ,
24- param_env : ParamEnv < ' tcx > ,
23+ /// Previously encountered safe references.
24+ ref_tracking : & ' rt mut RefTracking < ( MPlaceTy < ' tcx > , Mutability , InternMode ) > ,
2525 /// The root node of the value that we're looking at. This field is never mutated and only used
2626 /// for sanity assertions that will ICE when `const_qualif` screws up.
2727 mode : InternMode ,
@@ -53,74 +53,93 @@ enum InternMode {
5353/// into the memory of other constants or statics
5454struct IsStaticOrFn ;
5555
56+ /// Intern an allocation without looking at its children.
57+ /// `mode` is the mode of the environment where we found this pointer.
58+ /// `mutablity` is the mutability of the place to be interned; even if that says
59+ /// `immutable` things might become mutable if `ty` is not frozen.
60+ fn intern_shallow < ' rt , ' mir , ' tcx > (
61+ ecx : & ' rt mut CompileTimeEvalContext < ' mir , ' tcx > ,
62+ leftover_relocations : & ' rt mut FxHashSet < AllocId > ,
63+ mode : InternMode ,
64+ alloc_id : AllocId ,
65+ mutability : Mutability ,
66+ ty : Option < Ty < ' tcx > > ,
67+ ) -> InterpResult < ' tcx , Option < IsStaticOrFn > > {
68+ trace ! (
69+ "InternVisitor::intern {:?} with {:?}" ,
70+ alloc_id, mutability,
71+ ) ;
72+ // remove allocation
73+ let tcx = ecx. tcx ;
74+ let memory = ecx. memory_mut ( ) ;
75+ let ( kind, mut alloc) = match memory. alloc_map . remove ( & alloc_id) {
76+ Some ( entry) => entry,
77+ None => {
78+ // Pointer not found in local memory map. It is either a pointer to the global
79+ // map, or dangling.
80+ // If the pointer is dangling (neither in local nor global memory), we leave it
81+ // to validation to error. The `delay_span_bug` ensures that we don't forget such
82+ // a check in validation.
83+ if tcx. alloc_map . lock ( ) . get ( alloc_id) . is_none ( ) {
84+ tcx. sess . delay_span_bug ( ecx. tcx . span , "tried to intern dangling pointer" ) ;
85+ }
86+ // treat dangling pointers like other statics
87+ // just to stop trying to recurse into them
88+ return Ok ( Some ( IsStaticOrFn ) ) ;
89+ } ,
90+ } ;
91+ // This match is just a canary for future changes to `MemoryKind`, which most likely need
92+ // changes in this function.
93+ match kind {
94+ MemoryKind :: Stack | MemoryKind :: Vtable => { } ,
95+ }
96+ // Set allocation mutability as appropriate. This is used by LLVM to put things into
97+ // read-only memory, and also by Miri when evluating other constants/statics that
98+ // access this one.
99+ if mode == InternMode :: Static {
100+ let frozen = ty. map_or ( true , |ty| ty. is_freeze (
101+ ecx. tcx . tcx ,
102+ ecx. param_env ,
103+ ecx. tcx . span ,
104+ ) ) ;
105+ // For statics, allocation mutability is the combination of the place mutability and
106+ // the type mutability.
107+ // The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere.
108+ if mutability == Mutability :: Immutable && frozen {
109+ alloc. mutability = Mutability :: Immutable ;
110+ } else {
111+ // Just making sure we are not "upgrading" an immutable allocation to mutable.
112+ assert_eq ! ( alloc. mutability, Mutability :: Mutable ) ;
113+ }
114+ } else {
115+ // We *could* be non-frozen at `ConstBase`, for constants like `Cell::new(0)`.
116+ // But we still intern that as immutable as the memory cannot be changed once the
117+ // initial value was computed.
118+ // Constants are never mutable.
119+ alloc. mutability = Mutability :: Immutable ;
120+ } ;
121+ // link the alloc id to the actual allocation
122+ let alloc = tcx. intern_const_alloc ( alloc) ;
123+ leftover_relocations. extend ( alloc. relocations ( ) . iter ( ) . map ( |& ( _, ( ( ) , reloc) ) | reloc) ) ;
124+ tcx. alloc_map . lock ( ) . set_alloc_id_memory ( alloc_id, alloc) ;
125+ Ok ( None )
126+ }
127+
56128impl < ' rt , ' mir , ' tcx > InternVisitor < ' rt , ' mir , ' tcx > {
57- /// Intern an allocation without looking at its children.
58- /// `mutablity` is the mutability of the place to be interned; even if that says
59- /// `immutable` things might become mutable if `ty` is not frozen.
60129 fn intern_shallow (
61130 & mut self ,
62131 alloc_id : AllocId ,
63132 mutability : Mutability ,
64133 ty : Option < Ty < ' tcx > > ,
65134 ) -> InterpResult < ' tcx , Option < IsStaticOrFn > > {
66- trace ! (
67- "InternVisitor::intern {:?} with {:?}" ,
68- alloc_id, mutability,
69- ) ;
70- // remove allocation
71- let tcx = self . ecx . tcx ;
72- let memory = self . ecx . memory_mut ( ) ;
73- let ( kind, mut alloc) = match memory. alloc_map . remove ( & alloc_id) {
74- Some ( entry) => entry,
75- None => {
76- // Pointer not found in local memory map. It is either a pointer to the global
77- // map, or dangling.
78- // If the pointer is dangling (neither in local nor global memory), we leave it
79- // to validation to error. The `delay_span_bug` ensures that we don't forget such
80- // a check in validation.
81- if tcx. alloc_map . lock ( ) . get ( alloc_id) . is_none ( ) {
82- tcx. sess . delay_span_bug ( self . ecx . tcx . span , "tried to intern dangling pointer" ) ;
83- }
84- // treat dangling pointers like other statics
85- // just to stop trying to recurse into them
86- return Ok ( Some ( IsStaticOrFn ) ) ;
87- } ,
88- } ;
89- // This match is just a canary for future changes to `MemoryKind`, which most likely need
90- // changes in this function.
91- match kind {
92- MemoryKind :: Stack | MemoryKind :: Vtable => { } ,
93- }
94- // Set allocation mutability as appropriate. This is used by LLVM to put things into
95- // read-only memory, and also by Miri when evluating other constants/statics that
96- // access this one.
97- if self . mode == InternMode :: Static {
98- let frozen = ty. map_or ( true , |ty| ty. is_freeze (
99- self . ecx . tcx . tcx ,
100- self . param_env ,
101- self . ecx . tcx . span ,
102- ) ) ;
103- // For statics, allocation mutability is the combination of the place mutability and
104- // the type mutability.
105- // The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere.
106- if mutability == Mutability :: Immutable && frozen {
107- alloc. mutability = Mutability :: Immutable ;
108- } else {
109- // Just making sure we are not "upgrading" an immutable allocation to mutable.
110- assert_eq ! ( alloc. mutability, Mutability :: Mutable ) ;
111- }
112- } else {
113- // We *could* be non-frozen at `ConstBase`, for constants like `Cell::new(0)`.
114- // But we still intern that as immutable as the memory cannot be changed once the
115- // initial value was computed.
116- // Constants are never mutable.
117- alloc. mutability = Mutability :: Immutable ;
118- } ;
119- // link the alloc id to the actual allocation
120- let alloc = tcx. intern_const_alloc ( alloc) ;
121- self . leftover_relocations . extend ( alloc. relocations ( ) . iter ( ) . map ( |& ( _, ( ( ) , reloc) ) | reloc) ) ;
122- tcx. alloc_map . lock ( ) . set_alloc_id_memory ( alloc_id, alloc) ;
123- Ok ( None )
135+ intern_shallow (
136+ self . ecx ,
137+ self . leftover_relocations ,
138+ self . mode ,
139+ alloc_id,
140+ mutability,
141+ ty,
142+ )
124143 }
125144}
126145
171190 // Handle trait object vtables
172191 if let Ok ( meta) = value. to_meta ( ) {
173192 if let ty:: Dynamic ( ..) =
174- self . ecx . tcx . struct_tail_erasing_lifetimes ( referenced_ty, self . param_env ) . sty
193+ self . ecx . tcx . struct_tail_erasing_lifetimes (
194+ referenced_ty, self . ecx . param_env ) . sty
175195 {
176196 if let Ok ( vtable) = meta. unwrap ( ) . to_ptr ( ) {
177197 // explitly choose `Immutable` here, since vtables are immutable, even
203223 ( InternMode :: Const , hir:: Mutability :: MutMutable ) => {
204224 match referenced_ty. sty {
205225 ty:: Array ( _, n)
206- if n. eval_usize ( self . ecx . tcx . tcx , self . param_env ) == 0 => { }
226+ if n. eval_usize ( self . ecx . tcx . tcx , self . ecx . param_env ) == 0 => { }
207227 ty:: Slice ( _)
208228 if value. to_meta ( ) . unwrap ( ) . unwrap ( ) . to_usize ( self . ecx ) ? == 0 => { }
209229 _ => bug ! ( "const qualif failed to prevent mutable references" ) ,
@@ -246,9 +266,6 @@ pub fn intern_const_alloc_recursive(
246266 ecx : & mut CompileTimeEvalContext < ' mir , ' tcx > ,
247267 def_id : DefId ,
248268 ret : MPlaceTy < ' tcx > ,
249- // FIXME(oli-obk): can we scrap the param env? I think we can, the final value of a const eval
250- // must always be monomorphic, right?
251- param_env : ty:: ParamEnv < ' tcx > ,
252269) -> InterpResult < ' tcx > {
253270 let tcx = ecx. tcx ;
254271 // this `mutability` is the mutability of the place, ignoring the type
@@ -264,22 +281,21 @@ pub fn intern_const_alloc_recursive(
264281 let leftover_relocations = & mut FxHashSet :: default ( ) ;
265282
266283 // start with the outermost allocation
267- InternVisitor {
268- ref_tracking : & mut ref_tracking,
284+ intern_shallow (
269285 ecx,
270- mode : base_intern_mode,
271286 leftover_relocations,
272- param_env,
273- mutability : base_mutability,
274- } . intern_shallow ( ret. ptr . to_ptr ( ) ?. alloc_id , base_mutability, Some ( ret. layout . ty ) ) ?;
287+ base_intern_mode,
288+ ret. ptr . to_ptr ( ) ?. alloc_id ,
289+ base_mutability,
290+ Some ( ret. layout . ty )
291+ ) ?;
275292
276293 while let Some ( ( ( mplace, mutability, mode) , _) ) = ref_tracking. todo . pop ( ) {
277294 let interned = InternVisitor {
278295 ref_tracking : & mut ref_tracking,
279296 ecx,
280297 mode,
281298 leftover_relocations,
282- param_env,
283299 mutability,
284300 } . visit_value ( mplace) ;
285301 if let Err ( error) = interned {
0 commit comments