@@ -41,7 +41,6 @@ use ty::{self, TyCtxt, Instance};
4141use ty:: layout:: { self , Size } ;
4242use middle:: region;
4343use std:: io;
44- use std:: hash:: Hash ;
4544use rustc_serialize:: { Encoder , Decodable , Encodable } ;
4645use rustc_data_structures:: fx:: FxHashMap ;
4746use rustc_data_structures:: sync:: { Lock as Mutex , HashMapExt } ;
@@ -90,7 +89,7 @@ impl ::rustc_serialize::UseSpecializedEncodable for AllocId {}
9089impl :: rustc_serialize:: UseSpecializedDecodable for AllocId { }
9190
9291#[ derive( RustcDecodable , RustcEncodable ) ]
93- enum AllocKind {
92+ enum AllocDiscriminant {
9493 Alloc ,
9594 Fn ,
9695 Static ,
@@ -104,23 +103,23 @@ pub fn specialized_encode_alloc_id<
104103 tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
105104 alloc_id : AllocId ,
106105) -> Result < ( ) , E :: Error > {
107- let alloc_type : AllocType < ' tcx , & ' tcx Allocation > =
106+ let alloc_kind : AllocKind < ' tcx > =
108107 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) => {
111110 trace ! ( "encoding {:?} with {:#?}" , alloc_id, alloc) ;
112- AllocKind :: Alloc . encode ( encoder) ?;
111+ AllocDiscriminant :: Alloc . encode ( encoder) ?;
113112 alloc. encode ( encoder) ?;
114113 }
115- AllocType :: Function ( fn_instance) => {
114+ AllocKind :: Function ( fn_instance) => {
116115 trace ! ( "encoding {:?} with {:#?}" , alloc_id, fn_instance) ;
117- AllocKind :: Fn . encode ( encoder) ?;
116+ AllocDiscriminant :: Fn . encode ( encoder) ?;
118117 fn_instance. encode ( encoder) ?;
119118 }
120- AllocType :: Static ( did) => {
119+ AllocKind :: Static ( did) => {
121120 // referring to statics doesn't need to know about their allocations,
122121 // just about its DefId
123- AllocKind :: Static . encode ( encoder) ?;
122+ AllocDiscriminant :: Static . encode ( encoder) ?;
124123 did. encode ( encoder) ?;
125124 }
126125 }
@@ -189,10 +188,10 @@ impl<'s> AllocDecodingSession<'s> {
189188 let idx = decoder. read_u32 ( ) ? as usize ;
190189 let pos = self . state . data_offsets [ idx] as usize ;
191190
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
193192 // AllocId.
194193 let ( alloc_kind, pos) = decoder. with_position ( pos, |decoder| {
195- let alloc_kind = AllocKind :: decode ( decoder) ?;
194+ let alloc_kind = AllocDiscriminant :: decode ( decoder) ?;
196195 Ok ( ( alloc_kind, decoder. position ( ) ) )
197196 } ) ?;
198197
@@ -208,7 +207,7 @@ impl<'s> AllocDecodingSession<'s> {
208207 ref mut entry @ State :: Empty => {
209208 // We are allowed to decode
210209 match alloc_kind {
211- AllocKind :: Alloc => {
210+ AllocDiscriminant :: Alloc => {
212211 // If this is an allocation, we need to reserve an
213212 // AllocId so we can decode cyclic graphs.
214213 let alloc_id = decoder. tcx ( ) . alloc_map . lock ( ) . reserve ( ) ;
@@ -217,7 +216,7 @@ impl<'s> AllocDecodingSession<'s> {
217216 alloc_id) ;
218217 Some ( alloc_id)
219218 } ,
220- AllocKind :: Fn | AllocKind :: Static => {
219+ AllocDiscriminant :: Fn | AllocDiscriminant :: Static => {
221220 // Fns and statics cannot be cyclic and their AllocId
222221 // is determined later by interning
223222 * entry = State :: InProgressNonAlloc (
@@ -251,23 +250,23 @@ impl<'s> AllocDecodingSession<'s> {
251250 // Now decode the actual data
252251 let alloc_id = decoder. with_position ( pos, |decoder| {
253252 match alloc_kind {
254- AllocKind :: Alloc => {
253+ AllocDiscriminant :: Alloc => {
255254 let allocation = <& ' tcx Allocation as Decodable >:: decode ( decoder) ?;
256255 // We already have a reserved AllocId.
257256 let alloc_id = alloc_id. unwrap ( ) ;
258257 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) ;
260259 Ok ( alloc_id)
261260 } ,
262- AllocKind :: Fn => {
261+ AllocDiscriminant :: Fn => {
263262 assert ! ( alloc_id. is_none( ) ) ;
264263 trace ! ( "creating fn alloc id" ) ;
265264 let instance = ty:: Instance :: decode ( decoder) ?;
266265 trace ! ( "decoded fn alloc instance: {:?}" , instance) ;
267266 let alloc_id = decoder. tcx ( ) . alloc_map . lock ( ) . create_fn_alloc ( instance) ;
268267 Ok ( alloc_id)
269268 } ,
270- AllocKind :: Static => {
269+ AllocDiscriminant :: Static => {
271270 assert ! ( alloc_id. is_none( ) ) ;
272271 trace ! ( "creating extern static alloc id at" ) ;
273272 let did = DefId :: decode ( decoder) ?;
@@ -292,39 +291,42 @@ impl fmt::Display for AllocId {
292291}
293292
294293#[ derive( Debug , Clone , Eq , PartialEq , Hash , RustcDecodable , RustcEncodable ) ]
295- pub enum AllocType < ' tcx , M > {
294+ pub enum AllocKind < ' tcx > {
296295 /// The alloc id is used as a function pointer
297296 Function ( Instance < ' tcx > ) ,
298297 /// The alloc id points to a "lazy" static variable that did not get computed (yet).
299298 /// This is also used to break the cycle in recursive statics.
300299 Static ( DefId ) ,
301300 /// The alloc id points to memory
302- Memory ( M )
301+ Memory ( & ' tcx Allocation ) ,
303302}
304303
305- pub struct AllocMap < ' tcx , M > {
304+ pub struct AllocMap < ' tcx > {
306305 /// 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 > > ,
308307
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 > ,
311310
312311 /// The AllocId to assign to the next requested id.
313312 /// Always incremented, never gets smaller.
314313 next_id : AllocId ,
315314}
316315
317- impl < ' tcx , M : fmt :: Debug + Eq + Hash + Clone > AllocMap < ' tcx , M > {
316+ impl < ' tcx > AllocMap < ' tcx > {
318317 pub fn new ( ) -> Self {
319318 AllocMap {
320- id_to_type : Default :: default ( ) ,
319+ id_to_kind : Default :: default ( ) ,
321320 type_interner : Default :: default ( ) ,
322321 next_id : AllocId ( 0 ) ,
323322 }
324323 }
325324
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
327326 /// 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.
328330 pub fn reserve (
329331 & mut self ,
330332 ) -> AllocId {
@@ -337,53 +339,73 @@ impl<'tcx, M: fmt::Debug + Eq + Hash + Clone> AllocMap<'tcx, M> {
337339 next
338340 }
339341
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 ) {
342344 return alloc_id;
343345 }
344346 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) ;
348350 id
349351 }
350352
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.
354357 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
356361 }
357362
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 ( )
360370 }
361371
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 {
363374 match self . get ( id) {
364- Some ( AllocType :: Memory ( mem) ) => mem,
375+ Some ( AllocKind :: Memory ( mem) ) => mem,
365376 _ => bug ! ( "expected allocation id {} to point to memory" , id) ,
366377 }
367378 }
368379
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.
369382 pub fn intern_static ( & mut self , static_id : DefId ) -> AllocId {
370- self . intern ( AllocType :: Static ( static_id) )
383+ self . intern ( AllocKind :: Static ( static_id) )
371384 }
372385
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 {
374392 let id = self . reserve ( ) ;
375- self . set_id_memory ( id, mem) ;
393+ self . set_alloc_id_memory ( id, mem) ;
376394 id
377395 }
378396
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) ) {
381401 bug ! ( "tried to set allocation id {}, but it was already existing as {:#?}" , id, old) ;
382402 }
383403 }
384404
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) ) ;
387409 }
388410}
389411
0 commit comments