@@ -41,7 +41,6 @@ use ty::{self, TyCtxt, Instance};
41
41
use ty:: layout:: { self , Size } ;
42
42
use middle:: region;
43
43
use std:: io;
44
- use std:: hash:: Hash ;
45
44
use rustc_serialize:: { Encoder , Decodable , Encodable } ;
46
45
use rustc_data_structures:: fx:: FxHashMap ;
47
46
use rustc_data_structures:: sync:: { Lock as Mutex , HashMapExt } ;
@@ -90,7 +89,7 @@ impl ::rustc_serialize::UseSpecializedEncodable for AllocId {}
90
89
impl :: rustc_serialize:: UseSpecializedDecodable for AllocId { }
91
90
92
91
#[ derive( RustcDecodable , RustcEncodable ) ]
93
- enum AllocKind {
92
+ enum AllocDiscriminant {
94
93
Alloc ,
95
94
Fn ,
96
95
Static ,
@@ -104,23 +103,23 @@ pub fn specialized_encode_alloc_id<
104
103
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
105
104
alloc_id : AllocId ,
106
105
) -> Result < ( ) , E :: Error > {
107
- let alloc_type : AllocType < ' tcx , & ' tcx Allocation > =
106
+ let alloc_kind : AllocKind < ' tcx > =
108
107
tcx. alloc_map . lock ( ) . get ( alloc_id) . expect ( "no value for AllocId" ) ;
109
- match alloc_type {
110
- AllocType :: Memory ( alloc) => {
108
+ match alloc_kind {
109
+ AllocKind :: Memory ( alloc) => {
111
110
trace ! ( "encoding {:?} with {:#?}" , alloc_id, alloc) ;
112
- AllocKind :: Alloc . encode ( encoder) ?;
111
+ AllocDiscriminant :: Alloc . encode ( encoder) ?;
113
112
alloc. encode ( encoder) ?;
114
113
}
115
- AllocType :: Function ( fn_instance) => {
114
+ AllocKind :: Function ( fn_instance) => {
116
115
trace ! ( "encoding {:?} with {:#?}" , alloc_id, fn_instance) ;
117
- AllocKind :: Fn . encode ( encoder) ?;
116
+ AllocDiscriminant :: Fn . encode ( encoder) ?;
118
117
fn_instance. encode ( encoder) ?;
119
118
}
120
- AllocType :: Static ( did) => {
119
+ AllocKind :: Static ( did) => {
121
120
// referring to statics doesn't need to know about their allocations,
122
121
// just about its DefId
123
- AllocKind :: Static . encode ( encoder) ?;
122
+ AllocDiscriminant :: Static . encode ( encoder) ?;
124
123
did. encode ( encoder) ?;
125
124
}
126
125
}
@@ -189,10 +188,10 @@ impl<'s> AllocDecodingSession<'s> {
189
188
let idx = decoder. read_u32 ( ) ? as usize ;
190
189
let pos = self . state . data_offsets [ idx] as usize ;
191
190
192
- // Decode the AllocKind now so that we know if we have to reserve an
191
+ // Decode the AllocDiscriminant now so that we know if we have to reserve an
193
192
// AllocId.
194
193
let ( alloc_kind, pos) = decoder. with_position ( pos, |decoder| {
195
- let alloc_kind = AllocKind :: decode ( decoder) ?;
194
+ let alloc_kind = AllocDiscriminant :: decode ( decoder) ?;
196
195
Ok ( ( alloc_kind, decoder. position ( ) ) )
197
196
} ) ?;
198
197
@@ -208,7 +207,7 @@ impl<'s> AllocDecodingSession<'s> {
208
207
ref mut entry @ State :: Empty => {
209
208
// We are allowed to decode
210
209
match alloc_kind {
211
- AllocKind :: Alloc => {
210
+ AllocDiscriminant :: Alloc => {
212
211
// If this is an allocation, we need to reserve an
213
212
// AllocId so we can decode cyclic graphs.
214
213
let alloc_id = decoder. tcx ( ) . alloc_map . lock ( ) . reserve ( ) ;
@@ -217,7 +216,7 @@ impl<'s> AllocDecodingSession<'s> {
217
216
alloc_id) ;
218
217
Some ( alloc_id)
219
218
} ,
220
- AllocKind :: Fn | AllocKind :: Static => {
219
+ AllocDiscriminant :: Fn | AllocDiscriminant :: Static => {
221
220
// Fns and statics cannot be cyclic and their AllocId
222
221
// is determined later by interning
223
222
* entry = State :: InProgressNonAlloc (
@@ -251,23 +250,23 @@ impl<'s> AllocDecodingSession<'s> {
251
250
// Now decode the actual data
252
251
let alloc_id = decoder. with_position ( pos, |decoder| {
253
252
match alloc_kind {
254
- AllocKind :: Alloc => {
253
+ AllocDiscriminant :: Alloc => {
255
254
let allocation = <& ' tcx Allocation as Decodable >:: decode ( decoder) ?;
256
255
// We already have a reserved AllocId.
257
256
let alloc_id = alloc_id. unwrap ( ) ;
258
257
trace ! ( "decoded alloc {:?} {:#?}" , alloc_id, allocation) ;
259
- decoder. tcx ( ) . alloc_map . lock ( ) . set_id_same_memory ( alloc_id, allocation) ;
258
+ decoder. tcx ( ) . alloc_map . lock ( ) . set_alloc_id_same_memory ( alloc_id, allocation) ;
260
259
Ok ( alloc_id)
261
260
} ,
262
- AllocKind :: Fn => {
261
+ AllocDiscriminant :: Fn => {
263
262
assert ! ( alloc_id. is_none( ) ) ;
264
263
trace ! ( "creating fn alloc id" ) ;
265
264
let instance = ty:: Instance :: decode ( decoder) ?;
266
265
trace ! ( "decoded fn alloc instance: {:?}" , instance) ;
267
266
let alloc_id = decoder. tcx ( ) . alloc_map . lock ( ) . create_fn_alloc ( instance) ;
268
267
Ok ( alloc_id)
269
268
} ,
270
- AllocKind :: Static => {
269
+ AllocDiscriminant :: Static => {
271
270
assert ! ( alloc_id. is_none( ) ) ;
272
271
trace ! ( "creating extern static alloc id at" ) ;
273
272
let did = DefId :: decode ( decoder) ?;
@@ -292,39 +291,42 @@ impl fmt::Display for AllocId {
292
291
}
293
292
294
293
#[ derive( Debug , Clone , Eq , PartialEq , Hash , RustcDecodable , RustcEncodable ) ]
295
- pub enum AllocType < ' tcx , M > {
294
+ pub enum AllocKind < ' tcx > {
296
295
/// The alloc id is used as a function pointer
297
296
Function ( Instance < ' tcx > ) ,
298
297
/// The alloc id points to a "lazy" static variable that did not get computed (yet).
299
298
/// This is also used to break the cycle in recursive statics.
300
299
Static ( DefId ) ,
301
300
/// The alloc id points to memory
302
- Memory ( M )
301
+ Memory ( & ' tcx Allocation ) ,
303
302
}
304
303
305
- pub struct AllocMap < ' tcx , M > {
304
+ pub struct AllocMap < ' tcx > {
306
305
/// Lets you know what an AllocId refers to
307
- id_to_type : FxHashMap < AllocId , AllocType < ' tcx , M > > ,
306
+ id_to_kind : FxHashMap < AllocId , AllocKind < ' tcx > > ,
308
307
309
- /// Used to ensure that functions and statics only get one associated AllocId
310
- type_interner : FxHashMap < AllocType < ' tcx , M > , AllocId > ,
308
+ /// Used to ensure that statics only get one associated AllocId
309
+ type_interner : FxHashMap < AllocKind < ' tcx > , AllocId > ,
311
310
312
311
/// The AllocId to assign to the next requested id.
313
312
/// Always incremented, never gets smaller.
314
313
next_id : AllocId ,
315
314
}
316
315
317
- impl < ' tcx , M : fmt :: Debug + Eq + Hash + Clone > AllocMap < ' tcx , M > {
316
+ impl < ' tcx > AllocMap < ' tcx > {
318
317
pub fn new ( ) -> Self {
319
318
AllocMap {
320
- id_to_type : Default :: default ( ) ,
319
+ id_to_kind : Default :: default ( ) ,
321
320
type_interner : Default :: default ( ) ,
322
321
next_id : AllocId ( 0 ) ,
323
322
}
324
323
}
325
324
326
- /// obtains a new allocation ID that can be referenced but does not
325
+ /// Obtains a new allocation ID that can be referenced but does not
327
326
/// yet have an allocation backing it.
327
+ ///
328
+ /// Make sure to call `set_alloc_id_memory` or `set_alloc_id_same_memory` before returning such
329
+ /// an `AllocId` from a query.
328
330
pub fn reserve (
329
331
& mut self ,
330
332
) -> AllocId {
@@ -337,53 +339,73 @@ impl<'tcx, M: fmt::Debug + Eq + Hash + Clone> AllocMap<'tcx, M> {
337
339
next
338
340
}
339
341
340
- fn intern ( & mut self , alloc_type : AllocType < ' tcx , M > ) -> AllocId {
341
- if let Some ( & alloc_id) = self . type_interner . get ( & alloc_type ) {
342
+ fn intern ( & mut self , alloc_kind : AllocKind < ' tcx > ) -> AllocId {
343
+ if let Some ( & alloc_id) = self . type_interner . get ( & alloc_kind ) {
342
344
return alloc_id;
343
345
}
344
346
let id = self . reserve ( ) ;
345
- debug ! ( "creating alloc_type {:?} with id {}" , alloc_type , id) ;
346
- self . id_to_type . insert ( id, alloc_type . clone ( ) ) ;
347
- self . type_interner . insert ( alloc_type , id) ;
347
+ debug ! ( "creating alloc_kind {:?} with id {}" , alloc_kind , id) ;
348
+ self . id_to_kind . insert ( id, alloc_kind . clone ( ) ) ;
349
+ self . type_interner . insert ( alloc_kind , id) ;
348
350
id
349
351
}
350
352
351
- // FIXME: Check if functions have identity. If not, we should not intern these,
352
- // but instead create a new id per use.
353
- // Alternatively we could just make comparing function pointers an error.
353
+ /// Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
354
+ /// by the linker and functions can be duplicated across crates.
355
+ /// We thus generate a new `AllocId` for every mention of a function. This means that
356
+ /// `main as fn() == main as fn()` is false, while `let x = main as fn(); x == x` is true.
354
357
pub fn create_fn_alloc ( & mut self , instance : Instance < ' tcx > ) -> AllocId {
355
- self . intern ( AllocType :: Function ( instance) )
358
+ let id = self . reserve ( ) ;
359
+ self . id_to_kind . insert ( id, AllocKind :: Function ( instance) ) ;
360
+ id
356
361
}
357
362
358
- pub fn get ( & self , id : AllocId ) -> Option < AllocType < ' tcx , M > > {
359
- self . id_to_type . get ( & id) . cloned ( )
363
+ /// Returns `None` in case the `AllocId` is dangling. An `EvalContext` can still have a
364
+ /// local `Allocation` for that `AllocId`, but having such an `AllocId` in a constant is
365
+ /// illegal and will likely ICE.
366
+ /// This function exists to allow const eval to detect the difference between evaluation-
367
+ /// local dangling pointers and allocations in constants/statics.
368
+ pub fn get ( & self , id : AllocId ) -> Option < AllocKind < ' tcx > > {
369
+ self . id_to_kind . get ( & id) . cloned ( )
360
370
}
361
371
362
- pub fn unwrap_memory ( & self , id : AllocId ) -> M {
372
+ /// Panics if the `AllocId` does not refer to an `Allocation`
373
+ pub fn unwrap_memory ( & self , id : AllocId ) -> & ' tcx Allocation {
363
374
match self . get ( id) {
364
- Some ( AllocType :: Memory ( mem) ) => mem,
375
+ Some ( AllocKind :: Memory ( mem) ) => mem,
365
376
_ => bug ! ( "expected allocation id {} to point to memory" , id) ,
366
377
}
367
378
}
368
379
380
+ /// Generate an `AllocId` for a static or return a cached one in case this function has been
381
+ /// called on the same static before.
369
382
pub fn intern_static ( & mut self , static_id : DefId ) -> AllocId {
370
- self . intern ( AllocType :: Static ( static_id) )
383
+ self . intern ( AllocKind :: Static ( static_id) )
371
384
}
372
385
373
- pub fn allocate ( & mut self , mem : M ) -> AllocId {
386
+ /// Intern the `Allocation` and return a new `AllocId`, even if there's already an identical
387
+ /// `Allocation` with a different `AllocId`.
388
+ // FIXME: is this really necessary? Can we ensure `FOO` and `BAR` being different after codegen
389
+ // in `static FOO: u32 = 42; static BAR: u32 = 42;` even if they reuse the same allocation
390
+ // inside rustc?
391
+ pub fn allocate ( & mut self , mem : & ' tcx Allocation ) -> AllocId {
374
392
let id = self . reserve ( ) ;
375
- self . set_id_memory ( id, mem) ;
393
+ self . set_alloc_id_memory ( id, mem) ;
376
394
id
377
395
}
378
396
379
- pub fn set_id_memory ( & mut self , id : AllocId , mem : M ) {
380
- if let Some ( old) = self . id_to_type . insert ( id, AllocType :: Memory ( mem) ) {
397
+ /// Freeze an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to
398
+ /// call this function twice, even with the same `Allocation` will ICE the compiler.
399
+ pub fn set_alloc_id_memory ( & mut self , id : AllocId , mem : & ' tcx Allocation ) {
400
+ if let Some ( old) = self . id_to_kind . insert ( id, AllocKind :: Memory ( mem) ) {
381
401
bug ! ( "tried to set allocation id {}, but it was already existing as {:#?}" , id, old) ;
382
402
}
383
403
}
384
404
385
- pub fn set_id_same_memory ( & mut self , id : AllocId , mem : M ) {
386
- self . id_to_type . insert_same ( id, AllocType :: Memory ( mem) ) ;
405
+ /// Freeze an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called
406
+ /// twice for the same `(AllocId, Allocation)` pair.
407
+ fn set_alloc_id_same_memory ( & mut self , id : AllocId , mem : & ' tcx Allocation ) {
408
+ self . id_to_kind . insert_same ( id, AllocKind :: Memory ( mem) ) ;
387
409
}
388
410
}
389
411
0 commit comments