1
1
use super :: eval_queries:: { mk_eval_cx, op_to_const} ;
2
2
use super :: machine:: CompileTimeEvalContext ;
3
3
use 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 ,
6
6
} ;
7
7
use rustc_middle:: mir:: interpret:: ConstAlloc ;
8
8
use rustc_middle:: ty:: { self , ScalarInt , Ty , TyCtxt } ;
9
9
use rustc_span:: source_map:: DUMMY_SP ;
10
- use rustc_target:: abi:: VariantIdx ;
10
+ use rustc_target:: abi:: { Align , VariantIdx } ;
11
11
12
12
use crate :: interpret:: MPlaceTy ;
13
13
use crate :: interpret:: Value ;
@@ -108,7 +108,9 @@ fn const_to_valtree_inner<'tcx>(
108
108
ty:: Tuple ( substs) => branches ( ecx, place, substs. len ( ) , None ) ,
109
109
110
110
ty:: Adt ( def, _) => {
111
- if def. variants ( ) . is_empty ( ) {
111
+ if def. is_union ( ) {
112
+ return None
113
+ } else if def. variants ( ) . is_empty ( ) {
112
114
bug ! ( "uninhabited types should have errored and never gotten converted to valtree" )
113
115
}
114
116
@@ -149,6 +151,41 @@ fn create_mplace_from_layout<'tcx>(
149
151
ecx. allocate ( layout, MemoryKind :: Stack ) . unwrap ( )
150
152
}
151
153
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
+
152
189
#[ instrument( skip( ecx) , level = "debug" ) ]
153
190
fn create_pointee_place < ' tcx > (
154
191
ecx : & mut CompileTimeEvalContext < ' tcx , ' tcx > ,
@@ -173,6 +210,33 @@ fn create_pointee_place<'tcx>(
173
210
174
211
place
175
212
}
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
+ }
176
240
_ => create_mplace_from_layout ( ecx, ty) ,
177
241
}
178
242
}
@@ -270,6 +334,13 @@ fn fill_place_recursively<'tcx>(
270
334
let ty = place. layout . ty ;
271
335
272
336
match ty. kind ( ) {
337
+ ty:: FnDef ( _, _) => {
338
+ ecx. write_immediate (
339
+ Immediate :: Scalar ( ScalarMaybeUninit :: Scalar ( Scalar :: ZST ) ) ,
340
+ & ( * place) . into ( ) ,
341
+ )
342
+ . unwrap ( ) ;
343
+ }
273
344
ty:: Bool | ty:: Int ( _) | ty:: Uint ( _) | ty:: Float ( _) | ty:: Char => {
274
345
let scalar_int = valtree. unwrap_leaf ( ) ;
275
346
debug ! ( "writing trivial valtree {:?} to place {:?}" , scalar_int, place) ;
@@ -306,6 +377,9 @@ fn fill_place_recursively<'tcx>(
306
377
ty:: Adt ( _, _) | ty:: Tuple ( _) | ty:: Array ( _, _) | ty:: Str => {
307
378
let branches = valtree. unwrap_branch ( ) ;
308
379
380
+ // Need to collect the length of the unsized field for meta info
381
+ let mut unsized_meta_info = None ;
382
+
309
383
// Need to downcast place for enums
310
384
let ( place_adjusted, branches, variant_idx) = match ty. kind ( ) {
311
385
ty:: Adt ( def, _) if def. is_enum ( ) => {
@@ -329,6 +403,35 @@ fn fill_place_recursively<'tcx>(
329
403
for ( i, inner_valtree) in branches. iter ( ) . enumerate ( ) {
330
404
debug ! ( ?i, ?inner_valtree) ;
331
405
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
+
332
435
let mut place_inner = match * ty. kind ( ) {
333
436
ty:: Adt ( _, _) | ty:: Tuple ( _) => ecx. mplace_field ( & place_adjusted, i) . unwrap ( ) ,
334
437
ty:: Array ( _, _) | ty:: Str => {
@@ -338,7 +441,6 @@ fn fill_place_recursively<'tcx>(
338
441
} ;
339
442
debug ! ( ?place_inner) ;
340
443
341
- // insert valtree corresponding to tuple element into place
342
444
fill_place_recursively ( ecx, & mut place_inner, * inner_valtree) ;
343
445
dump_place ( & ecx, place_inner. into ( ) ) ;
344
446
}
@@ -351,6 +453,12 @@ fn fill_place_recursively<'tcx>(
351
453
ecx. write_discriminant ( variant_idx, & ( * place) . into ( ) ) . unwrap ( ) ;
352
454
}
353
455
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
+
354
462
dump_place ( ecx, ( * place) . into ( ) ) ;
355
463
}
356
464
_ => bug ! ( "shouldn't have created a ValTree for {:?}" , ty) ,
0 commit comments