@@ -17,8 +17,7 @@ use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk};
1717use  rustc_infer:: traits:: ObligationCauseCode ; 
1818use  rustc_middle:: traits:: { BuiltinImplSource ,  SignatureMismatchData } ; 
1919use  rustc_middle:: ty:: { 
20-     self ,  GenericArgs ,  GenericArgsRef ,  GenericParamDefKind ,  ToPolyTraitRef ,  TraitPredicate ,  Ty , 
21-     TyCtxt ,  Upcast , 
20+     self ,  GenericArgs ,  GenericArgsRef ,  GenericParamDefKind ,  ToPolyTraitRef ,  Ty ,  TyCtxt ,  Upcast , 
2221} ; 
2322use  rustc_middle:: { bug,  span_bug} ; 
2423use  rustc_span:: def_id:: DefId ; 
@@ -292,90 +291,120 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
292291        & mut  self , 
293292        obligation :  & PolyTraitObligation < ' tcx > , 
294293    )  -> Result < Vec < PredicateObligation < ' tcx > > ,  SelectionError < ' tcx > >  { 
295-         use  rustc_transmute:: { Answer ,  Condition } ; 
296-         #[ instrument( level = "debug" ,  skip( tcx,  obligation,  predicate) ) ]  
294+         use  rustc_transmute:: { Answer ,  Assume ,  Condition } ; 
295+ 
296+         /// Generate sub-obligations for reference-to-reference transmutations. 
297+ fn  reference_obligations < ' tcx > ( 
298+             tcx :  TyCtxt < ' tcx > , 
299+             obligation :  & PolyTraitObligation < ' tcx > , 
300+             ( src_lifetime,  src_ty,  src_mut) :  ( ty:: Region < ' tcx > ,  Ty < ' tcx > ,  Mutability ) , 
301+             ( dst_lifetime,  dst_ty,  dst_mut) :  ( ty:: Region < ' tcx > ,  Ty < ' tcx > ,  Mutability ) , 
302+             assume :  Assume , 
303+         )  -> Vec < PredicateObligation < ' tcx > >  { 
304+             let  make_transmute_obl = |src,  dst| { 
305+                 let  transmute_trait = obligation. predicate . def_id ( ) ; 
306+                 let  assume = obligation. predicate . skip_binder ( ) . trait_ref . args . const_at ( 2 ) ; 
307+                 let  trait_ref = ty:: TraitRef :: new ( 
308+                     tcx, 
309+                     transmute_trait, 
310+                     [ 
311+                         ty:: GenericArg :: from ( dst) , 
312+                         ty:: GenericArg :: from ( src) , 
313+                         ty:: GenericArg :: from ( assume) , 
314+                     ] , 
315+                 ) ; 
316+                 Obligation :: with_depth ( 
317+                     tcx, 
318+                     obligation. cause . clone ( ) , 
319+                     obligation. recursion_depth  + 1 , 
320+                     obligation. param_env , 
321+                     obligation. predicate . rebind ( trait_ref) , 
322+                 ) 
323+             } ; 
324+ 
325+             let  make_freeze_obl = |ty| { 
326+                 let  trait_ref = ty:: TraitRef :: new ( 
327+                     tcx, 
328+                     tcx. require_lang_item ( LangItem :: Freeze ,  None ) , 
329+                     [ ty:: GenericArg :: from ( ty) ] , 
330+                 ) ; 
331+                 Obligation :: with_depth ( 
332+                     tcx, 
333+                     obligation. cause . clone ( ) , 
334+                     obligation. recursion_depth  + 1 , 
335+                     obligation. param_env , 
336+                     trait_ref, 
337+                 ) 
338+             } ; 
339+ 
340+             let  make_outlives_obl = |target,  region| { 
341+                 let  outlives = ty:: OutlivesPredicate ( target,  region) ; 
342+                 Obligation :: with_depth ( 
343+                     tcx, 
344+                     obligation. cause . clone ( ) , 
345+                     obligation. recursion_depth  + 1 , 
346+                     obligation. param_env , 
347+                     obligation. predicate . rebind ( outlives) , 
348+                 ) 
349+             } ; 
350+ 
351+             // Given a transmutation from `&'a (mut) Src` and `&'dst (mut) Dst`, 
352+             // it is always the case that `Src` must be transmutable into `Dst`, 
353+             // and that that `'src` must outlive `'dst`. 
354+             let  mut  obls = vec ! [ make_transmute_obl( src_ty,  dst_ty) ] ; 
355+             if  !assume. lifetimes  { 
356+                 obls. push ( make_outlives_obl ( src_lifetime,  dst_lifetime) ) ; 
357+             } 
358+ 
359+             // Given a transmutation from `&Src`, both `Src` and `Dst` must be 
360+             // `Freeze`, otherwise, using the transmuted value could lead to 
361+             // data races. 
362+             if  src_mut == Mutability :: Not  { 
363+                 obls. extend ( [ make_freeze_obl ( src_ty) ,  make_freeze_obl ( dst_ty) ] ) 
364+             } 
365+ 
366+             // Given a transmutation into `&'dst mut Dst`, it also must be the 
367+             // case that `Dst` is transmutable into `Src`. For example, 
368+             // transmuting bool -> u8 is OK as long as you can't update that u8 
369+             // to be > 1, because you could later transmute the u8 back to a 
370+             // bool and get undefined behavior. It also must be the case that 
371+             // `'dst` lives exactly as long as `'src`. 
372+             if  dst_mut == Mutability :: Mut  { 
373+                 obls. push ( make_transmute_obl ( dst_ty,  src_ty) ) ; 
374+                 if  !assume. lifetimes  { 
375+                     obls. push ( make_outlives_obl ( dst_lifetime,  src_lifetime) ) ; 
376+                 } 
377+             } 
378+ 
379+             obls
380+         } 
381+ 
382+         /// Flatten the `Condition` tree into a conjunction of obligations. 
383+ #[ instrument( level = "debug" ,  skip( tcx,  obligation) ) ]  
297384        fn  flatten_answer_tree < ' tcx > ( 
298385            tcx :  TyCtxt < ' tcx > , 
299386            obligation :  & PolyTraitObligation < ' tcx > , 
300-             predicate :  TraitPredicate < ' tcx > , 
301387            cond :  Condition < rustc_transmute:: layout:: rustc:: Ref < ' tcx > > , 
388+             assume :  Assume , 
302389        )  -> Vec < PredicateObligation < ' tcx > >  { 
303390            match  cond { 
304391                // FIXME(bryangarza): Add separate `IfAny` case, instead of treating as `IfAll` 
305392                // Not possible until the trait solver supports disjunctions of obligations 
306393                Condition :: IfAll ( conds)  | Condition :: IfAny ( conds)  => conds
307394                    . into_iter ( ) 
308-                     . flat_map ( |cond| flatten_answer_tree ( tcx,  obligation,  predicate ,  cond ) ) 
395+                     . flat_map ( |cond| flatten_answer_tree ( tcx,  obligation,  cond ,  assume ) ) 
309396                    . collect ( ) , 
310-                 Condition :: IfTransmutable  {  src,  dst }  => { 
311-                     let  transmute_trait = obligation. predicate . def_id ( ) ; 
312-                     let  assume_const = predicate. trait_ref . args . const_at ( 2 ) ; 
313-                     let  make_transmute_obl = |from_ty,  to_ty| { 
314-                         let  trait_ref = ty:: TraitRef :: new ( 
315-                             tcx, 
316-                             transmute_trait, 
317-                             [ 
318-                                 ty:: GenericArg :: from ( to_ty) , 
319-                                 ty:: GenericArg :: from ( from_ty) , 
320-                                 ty:: GenericArg :: from ( assume_const) , 
321-                             ] , 
322-                         ) ; 
323-                         Obligation :: with_depth ( 
324-                             tcx, 
325-                             obligation. cause . clone ( ) , 
326-                             obligation. recursion_depth  + 1 , 
327-                             obligation. param_env , 
328-                             trait_ref, 
329-                         ) 
330-                     } ; 
331- 
332-                     let  make_freeze_obl = |ty| { 
333-                         let  trait_ref = ty:: TraitRef :: new ( 
334-                             tcx, 
335-                             tcx. require_lang_item ( LangItem :: Freeze ,  None ) , 
336-                             [ ty:: GenericArg :: from ( ty) ] , 
337-                         ) ; 
338-                         Obligation :: with_depth ( 
339-                             tcx, 
340-                             obligation. cause . clone ( ) , 
341-                             obligation. recursion_depth  + 1 , 
342-                             obligation. param_env , 
343-                             trait_ref, 
344-                         ) 
345-                     } ; 
346- 
347-                     let  mut  obls = vec ! [ ] ; 
348- 
349-                     // If the source is a shared reference, it must be `Freeze`; 
350-                     // otherwise, transmuting could lead to data races. 
351-                     if  src. mutability  == Mutability :: Not  { 
352-                         obls. extend ( [ make_freeze_obl ( src. ty ) ,  make_freeze_obl ( dst. ty ) ] ) 
353-                     } 
354- 
355-                     // If Dst is mutable, check bidirectionally. 
356-                     // For example, transmuting bool -> u8 is OK as long as you can't update that u8 
357-                     // to be > 1, because you could later transmute the u8 back to a bool and get UB. 
358-                     match  dst. mutability  { 
359-                         Mutability :: Not  => obls. push ( make_transmute_obl ( src. ty ,  dst. ty ) ) , 
360-                         Mutability :: Mut  => obls. extend ( [ 
361-                             make_transmute_obl ( src. ty ,  dst. ty ) , 
362-                             make_transmute_obl ( dst. ty ,  src. ty ) , 
363-                         ] ) , 
364-                     } 
365- 
366-                     obls
367-                 } 
397+                 Condition :: IfTransmutable  {  src,  dst }  => reference_obligations ( 
398+                     tcx, 
399+                     obligation, 
400+                     ( src. lifetime ,  src. ty ,  src. mutability ) , 
401+                     ( dst. lifetime ,  dst. ty ,  dst. mutability ) , 
402+                     assume, 
403+                 ) , 
368404            } 
369405        } 
370406
371-         // We erase regions here because transmutability calls layout queries, 
372-         // which does not handle inference regions and doesn't particularly 
373-         // care about other regions. Erasing late-bound regions is equivalent 
374-         // to instantiating the binder with placeholders then erasing those 
375-         // placeholder regions. 
376-         let  predicate = self 
377-             . tcx ( ) 
378-             . erase_regions ( self . tcx ( ) . instantiate_bound_regions_with_erased ( obligation. predicate ) ) ; 
407+         let  predicate = obligation. predicate . skip_binder ( ) ; 
379408
380409        let  Some ( assume)  = rustc_transmute:: Assume :: from_const ( 
381410            self . infcx . tcx , 
@@ -387,6 +416,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
387416
388417        let  dst = predicate. trait_ref . args . type_at ( 0 ) ; 
389418        let  src = predicate. trait_ref . args . type_at ( 1 ) ; 
419+ 
390420        debug ! ( ?src,  ?dst) ; 
391421        let  mut  transmute_env = rustc_transmute:: TransmuteTypeEnv :: new ( self . infcx ) ; 
392422        let  maybe_transmutable = transmute_env. is_transmutable ( 
@@ -397,7 +427,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
397427
398428        let  fully_flattened = match  maybe_transmutable { 
399429            Answer :: No ( _)  => Err ( Unimplemented ) ?, 
400-             Answer :: If ( cond)  => flatten_answer_tree ( self . tcx ( ) ,  obligation,  predicate ,  cond ) , 
430+             Answer :: If ( cond)  => flatten_answer_tree ( self . tcx ( ) ,  obligation,  cond ,  assume ) , 
401431            Answer :: Yes  => vec ! [ ] , 
402432        } ; 
403433
0 commit comments