11use super :: eval_queries:: { mk_eval_cx, op_to_const} ;
22use super :: machine:: CompileTimeEvalContext ;
33use crate :: interpret:: {
4- intern_const_alloc_recursive, ConstValue , ImmTy , Immediate , InternKind , MemoryKind , PlaceTy ,
5- Scalar , ScalarMaybeUninit ,
4+ intern_const_alloc_recursive, ConstValue , ImmTy , Immediate , InternKind , MemPlaceMeta ,
5+ MemoryKind , PlaceTy , Scalar , ScalarMaybeUninit ,
66} ;
77use rustc_middle:: mir:: interpret:: ConstAlloc ;
88use rustc_middle:: ty:: { self , ScalarInt , Ty , TyCtxt } ;
99use rustc_span:: source_map:: DUMMY_SP ;
10- use rustc_target:: abi:: VariantIdx ;
10+ use rustc_target:: abi:: { Align , VariantIdx } ;
1111
1212use crate :: interpret:: MPlaceTy ;
1313use crate :: interpret:: Value ;
@@ -108,7 +108,9 @@ fn const_to_valtree_inner<'tcx>(
108108 ty:: Tuple ( substs) => branches ( ecx, place, substs. len ( ) , None ) ,
109109
110110 ty:: Adt ( def, _) => {
111- if def. variants ( ) . is_empty ( ) {
111+ if def. is_union ( ) {
112+ return None
113+ } else if def. variants ( ) . is_empty ( ) {
112114 bug ! ( "uninhabited types should have errored and never gotten converted to valtree" )
113115 }
114116
@@ -149,6 +151,41 @@ fn create_mplace_from_layout<'tcx>(
149151 ecx. allocate ( layout, MemoryKind :: Stack ) . unwrap ( )
150152}
151153
154+ // Walks custom DSTs and gets the type of the unsized field and the number of elements
155+ // in the unsized field.
156+ fn get_info_on_unsized_field < ' tcx > (
157+ ty : Ty < ' tcx > ,
158+ valtree : ty:: ValTree < ' tcx > ,
159+ tcx : TyCtxt < ' tcx > ,
160+ ) -> ( Ty < ' tcx > , usize ) {
161+ let mut last_valtree = valtree;
162+ let tail = tcx. struct_tail_with_normalize (
163+ ty,
164+ |ty| ty,
165+ || {
166+ let branches = last_valtree. unwrap_branch ( ) ;
167+ last_valtree = branches[ branches. len ( ) - 1 ] ;
168+ debug ! ( ?branches, ?last_valtree) ;
169+ } ,
170+ ) ;
171+ let unsized_inner_ty = match tail. kind ( ) {
172+ ty:: Slice ( t) => * t,
173+ ty:: Str => tail,
174+ _ => bug ! ( "expected Slice or Str" ) ,
175+ } ;
176+
177+ // Have to adjust type for ty::Str
178+ let unsized_inner_ty = match unsized_inner_ty. kind ( ) {
179+ ty:: Str => tcx. mk_ty ( ty:: Uint ( ty:: UintTy :: U8 ) ) ,
180+ _ => unsized_inner_ty,
181+ } ;
182+
183+ // Get the number of elements in the unsized field
184+ let num_elems = last_valtree. unwrap_branch ( ) . len ( ) ;
185+
186+ ( unsized_inner_ty, num_elems)
187+ }
188+
152189#[ instrument( skip( ecx) , level = "debug" ) ]
153190fn create_pointee_place < ' tcx > (
154191 ecx : & mut CompileTimeEvalContext < ' tcx , ' tcx > ,
@@ -173,6 +210,33 @@ fn create_pointee_place<'tcx>(
173210
174211 place
175212 }
213+ ty:: Adt ( _, _) if !ty. is_sized ( ecx. tcx , ty:: ParamEnv :: empty ( ) ) => {
214+ // We need to create `Allocation`s for custom DSTs
215+
216+ let layout = tcx. layout_of ( ty:: ParamEnv :: empty ( ) . and ( ty) ) . unwrap ( ) ;
217+ let sized_fields_size = layout. layout . size ( ) ;
218+ let ( unsized_inner_ty, num_elems) = get_info_on_unsized_field ( ty, valtree, tcx) ;
219+ let unsized_inner_ty_size =
220+ tcx. layout_of ( ty:: ParamEnv :: empty ( ) . and ( unsized_inner_ty) ) . unwrap ( ) . layout . size ( ) ;
221+ debug ! ( ?unsized_inner_ty, ?unsized_inner_ty_size, ?num_elems) ;
222+
223+ // Get the size of the array behind the DST
224+ let dst_size = unsized_inner_ty_size. checked_mul ( num_elems as u64 , & tcx) . unwrap ( ) ;
225+
226+ let ptr = ecx
227+ . allocate_ptr (
228+ sized_fields_size. checked_add ( dst_size, & tcx) . unwrap ( ) ,
229+ Align :: from_bytes ( 1 ) . unwrap ( ) ,
230+ MemoryKind :: Stack ,
231+ )
232+ . unwrap ( ) ;
233+ debug ! ( ?ptr) ;
234+
235+ let place = MPlaceTy :: from_aligned_ptr ( ptr. into ( ) , layout) ;
236+ debug ! ( ?place) ;
237+
238+ place
239+ }
176240 _ => create_mplace_from_layout ( ecx, ty) ,
177241 }
178242}
@@ -270,6 +334,13 @@ fn fill_place_recursively<'tcx>(
270334 let ty = place. layout . ty ;
271335
272336 match ty. kind ( ) {
337+ ty:: FnDef ( _, _) => {
338+ ecx. write_immediate (
339+ Immediate :: Scalar ( ScalarMaybeUninit :: Scalar ( Scalar :: ZST ) ) ,
340+ & ( * place) . into ( ) ,
341+ )
342+ . unwrap ( ) ;
343+ }
273344 ty:: Bool | ty:: Int ( _) | ty:: Uint ( _) | ty:: Float ( _) | ty:: Char => {
274345 let scalar_int = valtree. unwrap_leaf ( ) ;
275346 debug ! ( "writing trivial valtree {:?} to place {:?}" , scalar_int, place) ;
@@ -306,6 +377,9 @@ fn fill_place_recursively<'tcx>(
306377 ty:: Adt ( _, _) | ty:: Tuple ( _) | ty:: Array ( _, _) | ty:: Str => {
307378 let branches = valtree. unwrap_branch ( ) ;
308379
380+ // Need to collect the length of the unsized field for meta info
381+ let mut unsized_meta_info = None ;
382+
309383 // Need to downcast place for enums
310384 let ( place_adjusted, branches, variant_idx) = match ty. kind ( ) {
311385 ty:: Adt ( def, _) if def. is_enum ( ) => {
@@ -329,6 +403,35 @@ fn fill_place_recursively<'tcx>(
329403 for ( i, inner_valtree) in branches. iter ( ) . enumerate ( ) {
330404 debug ! ( ?i, ?inner_valtree) ;
331405
406+ if !ty. is_sized ( ecx. tcx , ty:: ParamEnv :: empty ( ) ) && i == branches. len ( ) - 1 {
407+ // Note: For custom DSTs we need to manually process the last unsized field.
408+ // We created a `Pointer` for the `Allocation` of the complete sized version of
409+ // the Adt in `create_pointee_place` and now we fill that `Allocation` with the
410+ // values in the ValTree. For the unsized field we have to additionally add the meta
411+ // data.
412+
413+ let offset = place. layout . fields . offset ( i) ;
414+ let ( unsized_inner_ty, num_elems) = get_info_on_unsized_field ( ty, valtree, tcx) ;
415+ unsized_meta_info = Some ( num_elems) ;
416+
417+ // We create an array type to allow the recursive call to fill the place
418+ // corresponding to the array
419+ let arr_ty = tcx. mk_array ( unsized_inner_ty, num_elems as u64 ) ;
420+ debug ! ( ?arr_ty) ;
421+ let arr_layout = tcx. layout_of ( ty:: ParamEnv :: empty ( ) . and ( arr_ty) ) . unwrap ( ) ;
422+ let mut place_arr =
423+ place. offset ( offset, MemPlaceMeta :: None , arr_layout, & tcx) . unwrap ( ) ;
424+ debug ! ( ?place_arr) ;
425+
426+ fill_place_recursively ( ecx, & mut place_arr, * inner_valtree) ;
427+ dump_place ( & ecx, place_arr. into ( ) ) ;
428+
429+ // Add the meta information for the unsized type
430+ place_arr. meta = MemPlaceMeta :: Meta ( Scalar :: from_u64 ( num_elems as u64 ) ) ;
431+
432+ break ;
433+ }
434+
332435 let mut place_inner = match * ty. kind ( ) {
333436 ty:: Adt ( _, _) | ty:: Tuple ( _) => ecx. mplace_field ( & place_adjusted, i) . unwrap ( ) ,
334437 ty:: Array ( _, _) | ty:: Str => {
@@ -338,7 +441,6 @@ fn fill_place_recursively<'tcx>(
338441 } ;
339442 debug ! ( ?place_inner) ;
340443
341- // insert valtree corresponding to tuple element into place
342444 fill_place_recursively ( ecx, & mut place_inner, * inner_valtree) ;
343445 dump_place ( & ecx, place_inner. into ( ) ) ;
344446 }
@@ -351,6 +453,12 @@ fn fill_place_recursively<'tcx>(
351453 ecx. write_discriminant ( variant_idx, & ( * place) . into ( ) ) . unwrap ( ) ;
352454 }
353455
456+ // add meta information for unsized type
457+ if !ty. is_sized ( ecx. tcx , ty:: ParamEnv :: empty ( ) ) {
458+ place. meta =
459+ MemPlaceMeta :: Meta ( Scalar :: from_u64 ( unsized_meta_info. unwrap ( ) as u64 ) ) ;
460+ }
461+
354462 dump_place ( ecx, ( * place) . into ( ) ) ;
355463 }
356464 _ => bug ! ( "shouldn't have created a ValTree for {:?}" , ty) ,
0 commit comments