11//! This pass transforms derefs of Box into a deref of the pointer inside Box.
22//!
33//! Box is not actually a pointer so it is incorrect to dereference it directly.
4+ //!
5+ //! `ShallowInitBox` being a device for drop elaboration to understand deferred assignment to box
6+ //! contents, we do not need this any more on runtime MIR.
47
5- use rustc_abi:: FieldIdx ;
6- use rustc_hir :: def_id :: DefId ;
8+ use rustc_abi:: { FieldIdx , VariantIdx } ;
9+ use rustc_index :: { IndexVec , indexvec } ;
710use rustc_middle:: mir:: visit:: MutVisitor ;
811use rustc_middle:: mir:: * ;
912use rustc_middle:: span_bug;
10- use rustc_middle:: ty:: { Ty , TyCtxt } ;
13+ use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
1114
1215use crate :: patch:: MirPatch ;
1316
1417/// Constructs the types used when accessing a Box's pointer
1518fn build_ptr_tys < ' tcx > (
1619 tcx : TyCtxt < ' tcx > ,
1720 pointee : Ty < ' tcx > ,
18- unique_did : DefId ,
19- nonnull_did : DefId ,
21+ unique_def : ty :: AdtDef < ' tcx > ,
22+ nonnull_def : ty :: AdtDef < ' tcx > ,
2023) -> ( Ty < ' tcx > , Ty < ' tcx > , Ty < ' tcx > ) {
2124 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) ;
25+ let unique_ty = Ty :: new_adt ( tcx, unique_def , args) ;
26+ let nonnull_ty = Ty :: new_adt ( tcx, nonnull_def , args) ;
2427 let ptr_ty = Ty :: new_imm_ptr ( tcx, pointee) ;
2528
2629 ( unique_ty, nonnull_ty, ptr_ty)
@@ -36,8 +39,8 @@ pub(super) fn build_projection<'tcx>(
3639
3740struct ElaborateBoxDerefVisitor < ' a , ' tcx > {
3841 tcx : TyCtxt < ' tcx > ,
39- unique_did : DefId ,
40- nonnull_did : DefId ,
42+ unique_def : ty :: AdtDef < ' tcx > ,
43+ nonnull_def : ty :: AdtDef < ' tcx > ,
4144 local_decls : & ' a mut LocalDecls < ' tcx > ,
4245 patch : MirPatch < ' tcx > ,
4346}
@@ -64,7 +67,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'a, 'tcx> {
6467 let source_info = self . local_decls [ place. local ] . source_info ;
6568
6669 let ( unique_ty, nonnull_ty, ptr_ty) =
67- build_ptr_tys ( tcx, boxed_ty, self . unique_did , self . nonnull_did ) ;
70+ build_ptr_tys ( tcx, boxed_ty, self . unique_def , self . nonnull_def ) ;
6871
6972 let ptr_local = self . patch . new_temp ( ptr_ty, source_info. span ) ;
7073
@@ -86,6 +89,68 @@ impl<'a, 'tcx> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'a, 'tcx> {
8689
8790 self . super_place ( place, context, location) ;
8891 }
92+
93+ fn visit_statement ( & mut self , stmt : & mut Statement < ' tcx > , location : Location ) {
94+ self . super_statement ( stmt, location) ;
95+
96+ let tcx = self . tcx ;
97+ let source_info = stmt. source_info ;
98+
99+ if let StatementKind :: Assign ( box ( _, ref mut rvalue) ) = stmt. kind
100+ && let Rvalue :: ShallowInitBox ( ref mut mutptr_to_u8, pointee) = * rvalue
101+ && let ty:: Adt ( box_adt, box_args) = Ty :: new_box ( tcx, pointee) . kind ( )
102+ {
103+ let args = tcx. mk_args ( & [ pointee. into ( ) ] ) ;
104+ let ( unique_ty, nonnull_ty, ptr_ty) =
105+ build_ptr_tys ( tcx, pointee, self . unique_def , self . nonnull_def ) ;
106+ let adt_kind = |def : ty:: AdtDef < ' tcx > , args| {
107+ Box :: new ( AggregateKind :: Adt ( def. did ( ) , VariantIdx :: ZERO , args, None , None ) )
108+ } ;
109+ let zst = |ty| {
110+ Operand :: Constant ( Box :: new ( ConstOperand {
111+ span : source_info. span ,
112+ user_ty : None ,
113+ const_ : Const :: zero_sized ( ty) ,
114+ } ) )
115+ } ;
116+
117+ let constptr = self . patch . new_temp ( ptr_ty, source_info. span ) ;
118+ self . patch . add_assign (
119+ location,
120+ constptr. into ( ) ,
121+ Rvalue :: Cast ( CastKind :: Transmute , mutptr_to_u8. clone ( ) , ptr_ty) ,
122+ ) ;
123+
124+ let nonnull = self . patch . new_temp ( nonnull_ty, source_info. span ) ;
125+ self . patch . add_assign (
126+ location,
127+ nonnull. into ( ) ,
128+ Rvalue :: Aggregate (
129+ adt_kind ( self . nonnull_def , args) ,
130+ indexvec ! [ Operand :: Move ( constptr. into( ) ) ] ,
131+ ) ,
132+ ) ;
133+
134+ let unique = self . patch . new_temp ( unique_ty, source_info. span ) ;
135+ let phantomdata_ty =
136+ self . unique_def . non_enum_variant ( ) . fields [ FieldIdx :: ONE ] . ty ( tcx, args) ;
137+ self . patch . add_assign (
138+ location,
139+ unique. into ( ) ,
140+ Rvalue :: Aggregate (
141+ adt_kind ( self . unique_def , args) ,
142+ indexvec ! [ Operand :: Move ( nonnull. into( ) ) , zst( phantomdata_ty) ] ,
143+ ) ,
144+ ) ;
145+
146+ let global_alloc_ty =
147+ box_adt. non_enum_variant ( ) . fields [ FieldIdx :: ONE ] . ty ( tcx, box_args) ;
148+ * rvalue = Rvalue :: Aggregate (
149+ adt_kind ( * box_adt, box_args) ,
150+ indexvec ! [ Operand :: Move ( unique. into( ) ) , zst( global_alloc_ty) ] ,
151+ ) ;
152+ }
153+ }
89154}
90155
91156pub ( super ) struct ElaborateBoxDerefs ;
@@ -97,18 +162,22 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateBoxDerefs {
97162
98163 let unique_did = tcx. adt_def ( def_id) . non_enum_variant ( ) . fields [ FieldIdx :: ZERO ] . did ;
99164
100- let Some ( nonnull_def ) = tcx. type_of ( unique_did) . instantiate_identity ( ) . ty_adt_def ( ) else {
165+ let Some ( unique_def ) = tcx. type_of ( unique_did) . instantiate_identity ( ) . ty_adt_def ( ) else {
101166 span_bug ! ( tcx. def_span( unique_did) , "expected Box to contain Unique" )
102167 } ;
103168
104- let nonnull_did = nonnull_def. non_enum_variant ( ) . fields [ FieldIdx :: ZERO ] . did ;
169+ let nonnull_did = unique_def. non_enum_variant ( ) . fields [ FieldIdx :: ZERO ] . did ;
170+
171+ let Some ( nonnull_def) = tcx. type_of ( nonnull_did) . instantiate_identity ( ) . ty_adt_def ( ) else {
172+ span_bug ! ( tcx. def_span( nonnull_did) , "expected Unique to contain Nonnull" )
173+ } ;
105174
106175 let patch = MirPatch :: new ( body) ;
107176
108177 let local_decls = & mut body. local_decls ;
109178
110179 let mut visitor =
111- ElaborateBoxDerefVisitor { tcx, unique_did , nonnull_did , local_decls, patch } ;
180+ ElaborateBoxDerefVisitor { tcx, unique_def , nonnull_def , local_decls, patch } ;
112181
113182 for ( block, data) in body. basic_blocks . as_mut_preserves_cfg ( ) . iter_enumerated_mut ( ) {
114183 visitor. visit_basic_block_data ( block, data) ;
@@ -131,7 +200,7 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateBoxDerefs {
131200 new_projections. get_or_insert_with ( || base. projection . to_vec ( ) ) ;
132201
133202 let ( unique_ty, nonnull_ty, ptr_ty) =
134- build_ptr_tys ( tcx, boxed_ty, unique_did , nonnull_did ) ;
203+ build_ptr_tys ( tcx, boxed_ty, unique_def , nonnull_def ) ;
135204
136205 new_projections. extend_from_slice ( & build_projection ( unique_ty, nonnull_ty) ) ;
137206 // While we can't project into `NonNull<_>` in a basic block
0 commit comments