@@ -386,43 +386,20 @@ where
386386 Ok ( place)
387387 }
388388
389- /// Offset a pointer to project to a field. Unlike `place_field`, this is always
390- /// possible without allocating, so it can take `&self`. Also return the field's layout.
389+ /// Offset a pointer to project to a field of a struct/union . Unlike `place_field`, this is
390+ /// always possible without allocating, so it can take `&self`. Also return the field's layout.
391391 /// This supports both struct and array fields.
392+ ///
393+ /// This also works for arrays, but then the `usize` index type is restricting.
394+ /// For indexing into arrays, use `mplace_index`.
392395 #[ inline( always) ]
393396 pub fn mplace_field (
394397 & self ,
395398 base : MPlaceTy < ' tcx , M :: PointerTag > ,
396- field : u64 ,
399+ field : usize ,
397400 ) -> InterpResult < ' tcx , MPlaceTy < ' tcx , M :: PointerTag > > {
398- // Not using the layout method because we want to compute on u64
399- let ( offset, field_layout) = match base. layout . fields {
400- layout:: FieldPlacement :: Arbitrary { ref offsets, .. } => {
401- let field = usize:: try_from ( field) . unwrap ( ) ;
402- ( offsets[ field] , base. layout . field ( self , field) ?)
403- }
404- layout:: FieldPlacement :: Array { stride, .. } => {
405- let len = base. len ( self ) ?;
406- if field >= len {
407- // This can only be reached in ConstProp and non-rustc-MIR.
408- throw_ub ! ( BoundsCheckFailed { len, index: field } ) ;
409- }
410- // All fields have the same layout.
411- ( Size :: mul ( stride, field) , base. layout . field ( self , 9 ) ?)
412- }
413- layout:: FieldPlacement :: Union ( count) => {
414- let field = usize:: try_from ( field) . unwrap ( ) ;
415- assert ! (
416- field < count,
417- "Tried to access field {} of union {:#?} with {} fields" ,
418- field,
419- base. layout,
420- count
421- ) ;
422- // Offset is always 0
423- ( Size :: from_bytes ( 0 ) , base. layout . field ( self , field) ?)
424- }
425- } ;
401+ let offset = base. layout . fields . offset ( field) ;
402+ let field_layout = base. layout . field ( self , field) ?;
426403
427404 // Offset may need adjustment for unsized fields.
428405 let ( meta, offset) = if field_layout. is_unsized ( ) {
@@ -452,6 +429,32 @@ where
452429 base. offset ( offset, meta, field_layout, self )
453430 }
454431
432+ /// Index into an array.
433+ #[ inline( always) ]
434+ pub fn mplace_index (
435+ & self ,
436+ base : MPlaceTy < ' tcx , M :: PointerTag > ,
437+ index : u64 ,
438+ ) -> InterpResult < ' tcx , MPlaceTy < ' tcx , M :: PointerTag > > {
439+ // Not using the layout method because we want to compute on u64
440+ match base. layout . fields {
441+ layout:: FieldPlacement :: Array { stride, .. } => {
442+ let len = base. len ( self ) ?;
443+ if index >= len {
444+ // This can only be reached in ConstProp and non-rustc-MIR.
445+ throw_ub ! ( BoundsCheckFailed { len, index } ) ;
446+ }
447+ let offset = Size :: mul ( stride, index) ;
448+ // All fields have the same layout.
449+ let field_layout = base. layout . field ( self , 0 ) ?;
450+
451+ assert ! ( !field_layout. is_unsized( ) ) ;
452+ base. offset ( offset, MemPlaceMeta :: None , field_layout, self )
453+ }
454+ _ => bug ! ( "`mplace_index` called on non-array type {:?}" , base. layout. ty) ,
455+ }
456+ }
457+
455458 // Iterates over all fields of an array. Much more efficient than doing the
456459 // same by repeatedly calling `mplace_array`.
457460 pub ( super ) fn mplace_array_fields (
@@ -528,16 +531,19 @@ where
528531 ) -> InterpResult < ' tcx , MPlaceTy < ' tcx , M :: PointerTag > > {
529532 use rustc:: mir:: ProjectionElem :: * ;
530533 Ok ( match * proj_elem {
531- Field ( field, _) => self . mplace_field ( base, u64 :: try_from ( field. index ( ) ) . unwrap ( ) ) ?,
534+ Field ( field, _) => self . mplace_field ( base, field. index ( ) ) ?,
532535 Downcast ( _, variant) => self . mplace_downcast ( base, variant) ?,
533536 Deref => self . deref_operand ( base. into ( ) ) ?,
534537
535538 Index ( local) => {
536539 let layout = self . layout_of ( self . tcx . types . usize ) ?;
537540 let n = self . access_local ( self . frame ( ) , local, Some ( layout) ) ?;
538541 let n = self . read_scalar ( n) ?;
539- let n = self . force_bits ( n. not_undef ( ) ?, self . tcx . data_layout . pointer_size ) ?;
540- self . mplace_field ( base, u64:: try_from ( n) . unwrap ( ) ) ?
542+ let n = u64:: try_from (
543+ self . force_bits ( n. not_undef ( ) ?, self . tcx . data_layout . pointer_size ) ?,
544+ )
545+ . unwrap ( ) ;
546+ self . mplace_index ( base, n) ?
541547 }
542548
543549 ConstantIndex { offset, min_length, from_end } => {
@@ -555,7 +561,7 @@ where
555561 u64:: from ( offset)
556562 } ;
557563
558- self . mplace_field ( base, index) ?
564+ self . mplace_index ( base, index) ?
559565 }
560566
561567 Subslice { from, to, from_end } => {
@@ -571,14 +577,23 @@ where
571577 pub fn place_field (
572578 & mut self ,
573579 base : PlaceTy < ' tcx , M :: PointerTag > ,
574- field : u64 ,
580+ field : usize ,
575581 ) -> InterpResult < ' tcx , PlaceTy < ' tcx , M :: PointerTag > > {
576582 // FIXME: We could try to be smarter and avoid allocation for fields that span the
577583 // entire place.
578584 let mplace = self . force_allocation ( base) ?;
579585 Ok ( self . mplace_field ( mplace, field) ?. into ( ) )
580586 }
581587
588+ pub fn place_index (
589+ & mut self ,
590+ base : PlaceTy < ' tcx , M :: PointerTag > ,
591+ index : u64 ,
592+ ) -> InterpResult < ' tcx , PlaceTy < ' tcx , M :: PointerTag > > {
593+ let mplace = self . force_allocation ( base) ?;
594+ Ok ( self . mplace_index ( mplace, index) ?. into ( ) )
595+ }
596+
582597 pub fn place_downcast (
583598 & self ,
584599 base : PlaceTy < ' tcx , M :: PointerTag > ,
@@ -604,7 +619,7 @@ where
604619 ) -> InterpResult < ' tcx , PlaceTy < ' tcx , M :: PointerTag > > {
605620 use rustc:: mir:: ProjectionElem :: * ;
606621 Ok ( match * proj_elem {
607- Field ( field, _) => self . place_field ( base, u64 :: try_from ( field. index ( ) ) . unwrap ( ) ) ?,
622+ Field ( field, _) => self . place_field ( base, field. index ( ) ) ?,
608623 Downcast ( _, variant) => self . place_downcast ( base, variant) ?,
609624 Deref => self . deref_operand ( self . place_to_op ( base) ?) ?. into ( ) ,
610625 // For the other variants, we have to force an allocation.
@@ -1073,7 +1088,7 @@ where
10731088 let size = discr_layout. value . size ( self ) ;
10741089 let discr_val = truncate ( discr_val, size) ;
10751090
1076- let discr_dest = self . place_field ( dest, u64 :: try_from ( discr_index) . unwrap ( ) ) ?;
1091+ let discr_dest = self . place_field ( dest, discr_index) ?;
10771092 self . write_scalar ( Scalar :: from_uint ( discr_val, size) , discr_dest) ?;
10781093 }
10791094 layout:: Variants :: Multiple {
@@ -1104,7 +1119,7 @@ where
11041119 niche_start_val,
11051120 ) ?;
11061121 // Write result.
1107- let niche_dest = self . place_field ( dest, u64 :: try_from ( discr_index) . unwrap ( ) ) ?;
1122+ let niche_dest = self . place_field ( dest, discr_index) ?;
11081123 self . write_immediate ( * discr_val, niche_dest) ?;
11091124 }
11101125 }
0 commit comments