22//!
33//! Box is not actually a pointer so it is incorrect to dereference it directly.
44
5- use rustc_abi:: FieldIdx ;
6- use rustc_hir :: def_id :: DefId ;
5+ use rustc_abi:: { FieldIdx , VariantIdx } ;
6+ use rustc_index :: IndexVec ;
77use rustc_middle:: mir:: visit:: MutVisitor ;
88use rustc_middle:: mir:: * ;
99use rustc_middle:: span_bug;
10- use rustc_middle:: ty:: { Ty , TyCtxt } ;
10+ use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
1111
1212use crate :: patch:: MirPatch ;
1313
1414/// Constructs the types used when accessing a Box's pointer
1515fn build_ptr_tys < ' tcx > (
1616 tcx : TyCtxt < ' tcx > ,
1717 pointee : Ty < ' tcx > ,
18- unique_did : DefId ,
19- nonnull_did : DefId ,
18+ unique_def : ty :: AdtDef < ' tcx > ,
19+ nonnull_def : ty :: AdtDef < ' tcx > ,
2020) -> ( Ty < ' tcx > , Ty < ' tcx > , Ty < ' tcx > ) {
2121 let args = tcx. mk_args ( & [ pointee. into ( ) ] ) ;
22- let unique_ty = tcx . type_of ( unique_did ) . instantiate ( tcx, args) ;
23- let nonnull_ty = tcx . type_of ( nonnull_did ) . instantiate ( tcx, args) ;
22+ let unique_ty = Ty :: new_adt ( tcx, unique_def , args) ;
23+ let nonnull_ty = Ty :: new_adt ( tcx, nonnull_def , args) ;
2424 let ptr_ty = Ty :: new_imm_ptr ( tcx, pointee) ;
2525
2626 ( unique_ty, nonnull_ty, ptr_ty)
@@ -36,8 +36,8 @@ pub(super) fn build_projection<'tcx>(
3636
3737struct ElaborateBoxDerefVisitor < ' a , ' tcx > {
3838 tcx : TyCtxt < ' tcx > ,
39- unique_did : DefId ,
40- nonnull_did : DefId ,
39+ unique_def : ty :: AdtDef < ' tcx > ,
40+ nonnull_def : ty :: AdtDef < ' tcx > ,
4141 local_decls : & ' a mut LocalDecls < ' tcx > ,
4242 patch : MirPatch < ' tcx > ,
4343}
@@ -64,7 +64,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'a, 'tcx> {
6464 let source_info = self . local_decls [ place. local ] . source_info ;
6565
6666 let ( unique_ty, nonnull_ty, ptr_ty) =
67- build_ptr_tys ( tcx, boxed_ty, self . unique_did , self . nonnull_did ) ;
67+ build_ptr_tys ( tcx, boxed_ty, self . unique_def , self . nonnull_def ) ;
6868
6969 let ptr_local = self . patch . new_temp ( ptr_ty, source_info. span ) ;
7070
@@ -86,6 +86,68 @@ impl<'a, 'tcx> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'a, 'tcx> {
8686
8787 self . super_place ( place, context, location) ;
8888 }
89+
90+ fn visit_statement ( & mut self , stmt : & mut Statement < ' tcx > , location : Location ) {
91+ self . super_statement ( stmt, location) ;
92+
93+ let tcx = self . tcx ;
94+ let source_info = stmt. source_info ;
95+
96+ if let StatementKind :: Assign ( box ( _, ref mut rvalue) ) = stmt. kind
97+ && let Rvalue :: ShallowInitBox ( ref mut mutptr_to_u8, pointee) = * rvalue
98+ && let ty:: Adt ( box_adt, box_args) = Ty :: new_box ( tcx, pointee) . kind ( )
99+ {
100+ let args = tcx. mk_args ( & [ pointee. into ( ) ] ) ;
101+ let ( unique_ty, nonnull_ty, ptr_ty) =
102+ build_ptr_tys ( tcx, pointee, self . unique_def , self . nonnull_def ) ;
103+ let adt_kind = |def : ty:: AdtDef < ' tcx > , args| {
104+ Box :: new ( AggregateKind :: Adt ( def. did ( ) , VariantIdx :: ZERO , args, None , None ) )
105+ } ;
106+ let zst = |ty| {
107+ Operand :: Constant ( Box :: new ( ConstOperand {
108+ span : source_info. span ,
109+ user_ty : None ,
110+ const_ : Const :: zero_sized ( ty) ,
111+ } ) )
112+ } ;
113+
114+ let constptr = self . patch . new_temp ( ptr_ty, source_info. span ) ;
115+ self . patch . add_assign (
116+ location,
117+ constptr. into ( ) ,
118+ Rvalue :: Cast ( CastKind :: Transmute , mutptr_to_u8. clone ( ) , ptr_ty) ,
119+ ) ;
120+
121+ let nonnull = self . patch . new_temp ( nonnull_ty, source_info. span ) ;
122+ self . patch . add_assign (
123+ location,
124+ nonnull. into ( ) ,
125+ Rvalue :: Aggregate (
126+ adt_kind ( self . nonnull_def , args) ,
127+ IndexVec :: from_raw ( vec ! [ Operand :: Move ( constptr. into( ) ) ] ) ,
128+ ) ,
129+ ) ;
130+
131+ let unique = self . patch . new_temp ( unique_ty, source_info. span ) ;
132+ let phantomdata_ty =
133+ self . unique_def . non_enum_variant ( ) . fields [ FieldIdx :: ONE ] . ty ( tcx, args) ;
134+ self . patch . add_assign (
135+ location,
136+ unique. into ( ) ,
137+ Rvalue :: Aggregate (
138+ adt_kind ( self . unique_def , args) ,
139+ IndexVec :: from_raw ( vec ! [ Operand :: Move ( nonnull. into( ) ) , zst( phantomdata_ty) ] ) ,
140+ ) ,
141+ ) ;
142+
143+ let global_alloc_ty =
144+ box_adt. non_enum_variant ( ) . fields [ FieldIdx :: ONE ] . ty ( tcx, box_args) ;
145+ * rvalue = Rvalue :: Aggregate (
146+ adt_kind ( * box_adt, box_args) ,
147+ IndexVec :: from_raw ( vec ! [ Operand :: Move ( unique. into( ) ) , zst( global_alloc_ty) ] ) ,
148+ ) ;
149+ }
150+ }
89151}
90152
91153pub ( super ) struct ElaborateBoxDerefs ;
@@ -97,18 +159,22 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateBoxDerefs {
97159
98160 let unique_did = tcx. adt_def ( def_id) . non_enum_variant ( ) . fields [ FieldIdx :: ZERO ] . did ;
99161
100- let Some ( nonnull_def ) = tcx. type_of ( unique_did) . instantiate_identity ( ) . ty_adt_def ( ) else {
162+ let Some ( unique_def ) = tcx. type_of ( unique_did) . instantiate_identity ( ) . ty_adt_def ( ) else {
101163 span_bug ! ( tcx. def_span( unique_did) , "expected Box to contain Unique" )
102164 } ;
103165
104- let nonnull_did = nonnull_def. non_enum_variant ( ) . fields [ FieldIdx :: ZERO ] . did ;
166+ let nonnull_did = unique_def. non_enum_variant ( ) . fields [ FieldIdx :: ZERO ] . did ;
167+
168+ let Some ( nonnull_def) = tcx. type_of ( nonnull_did) . instantiate_identity ( ) . ty_adt_def ( ) else {
169+ span_bug ! ( tcx. def_span( nonnull_did) , "expected Unique to contain Nonnull" )
170+ } ;
105171
106172 let patch = MirPatch :: new ( body) ;
107173
108174 let local_decls = & mut body. local_decls ;
109175
110176 let mut visitor =
111- ElaborateBoxDerefVisitor { tcx, unique_did , nonnull_did , local_decls, patch } ;
177+ ElaborateBoxDerefVisitor { tcx, unique_def , nonnull_def , local_decls, patch } ;
112178
113179 for ( block, data) in body. basic_blocks . as_mut_preserves_cfg ( ) . iter_enumerated_mut ( ) {
114180 visitor. visit_basic_block_data ( block, data) ;
@@ -131,7 +197,7 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateBoxDerefs {
131197 new_projections. get_or_insert_with ( || base. projection . to_vec ( ) ) ;
132198
133199 let ( unique_ty, nonnull_ty, ptr_ty) =
134- build_ptr_tys ( tcx, boxed_ty, unique_did , nonnull_did ) ;
200+ build_ptr_tys ( tcx, boxed_ty, unique_def , nonnull_def ) ;
135201
136202 new_projections. extend_from_slice ( & build_projection ( unique_ty, nonnull_ty) ) ;
137203 // While we can't project into `NonNull<_>` in a basic block
0 commit comments