3
3
//! After a const evaluation has computed a value, before we destroy the const evaluator's session
4
4
//! memory, we need to extract all memory allocations to the global memory pool so they stay around.
5
5
6
- use rustc:: ty:: { Ty , ParamEnv , self } ;
6
+ use rustc:: ty:: { Ty , self } ;
7
7
use rustc:: mir:: interpret:: { InterpResult , ErrorHandled } ;
8
8
use rustc:: hir;
9
9
use rustc:: hir:: def_id:: DefId ;
@@ -18,10 +18,10 @@ use super::{
18
18
use crate :: const_eval:: { CompileTimeInterpreter , CompileTimeEvalContext } ;
19
19
20
20
struct 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.
23
22
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 ) > ,
25
25
/// The root node of the value that we're looking at. This field is never mutated and only used
26
26
/// for sanity assertions that will ICE when `const_qualif` screws up.
27
27
mode : InternMode ,
@@ -53,74 +53,93 @@ enum InternMode {
53
53
/// into the memory of other constants or statics
54
54
struct IsStaticOrFn ;
55
55
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
+
56
128
impl < ' 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.
60
129
fn intern_shallow (
61
130
& mut self ,
62
131
alloc_id : AllocId ,
63
132
mutability : Mutability ,
64
133
ty : Option < Ty < ' tcx > > ,
65
134
) -> 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
+ )
124
143
}
125
144
}
126
145
171
190
// Handle trait object vtables
172
191
if let Ok ( meta) = value. to_meta ( ) {
173
192
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
175
195
{
176
196
if let Ok ( vtable) = meta. unwrap ( ) . to_ptr ( ) {
177
197
// explitly choose `Immutable` here, since vtables are immutable, even
203
223
( InternMode :: Const , hir:: Mutability :: MutMutable ) => {
204
224
match referenced_ty. sty {
205
225
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 => { }
207
227
ty:: Slice ( _)
208
228
if value. to_meta ( ) . unwrap ( ) . unwrap ( ) . to_usize ( self . ecx ) ? == 0 => { }
209
229
_ => bug ! ( "const qualif failed to prevent mutable references" ) ,
@@ -246,9 +266,6 @@ pub fn intern_const_alloc_recursive(
246
266
ecx : & mut CompileTimeEvalContext < ' mir , ' tcx > ,
247
267
def_id : DefId ,
248
268
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 > ,
252
269
) -> InterpResult < ' tcx > {
253
270
let tcx = ecx. tcx ;
254
271
// this `mutability` is the mutability of the place, ignoring the type
@@ -264,22 +281,21 @@ pub fn intern_const_alloc_recursive(
264
281
let leftover_relocations = & mut FxHashSet :: default ( ) ;
265
282
266
283
// start with the outermost allocation
267
- InternVisitor {
268
- ref_tracking : & mut ref_tracking,
284
+ intern_shallow (
269
285
ecx,
270
- mode : base_intern_mode,
271
286
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
+ ) ?;
275
292
276
293
while let Some ( ( ( mplace, mutability, mode) , _) ) = ref_tracking. todo . pop ( ) {
277
294
let interned = InternVisitor {
278
295
ref_tracking : & mut ref_tracking,
279
296
ecx,
280
297
mode,
281
298
leftover_relocations,
282
- param_env,
283
299
mutability,
284
300
} . visit_value ( mplace) ;
285
301
if let Err ( error) = interned {
0 commit comments