@@ -230,6 +230,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
230230 }
231231}
232232
233+ // These are defined here because they produce a place.
233234impl < ' tcx , Tag : :: std:: fmt:: Debug + Copy > OpTy < ' tcx , Tag > {
234235 #[ inline( always) ]
235236 pub fn try_as_mplace ( self ) -> Result < MPlaceTy < ' tcx , Tag > , ImmTy < ' tcx , Tag > > {
@@ -240,7 +241,7 @@ impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> {
240241 }
241242
242243 #[ inline( always) ]
243- pub fn to_mem_place ( self ) -> MPlaceTy < ' tcx , Tag > {
244+ pub fn assert_mem_place ( self ) -> MPlaceTy < ' tcx , Tag > {
244245 self . try_as_mplace ( ) . unwrap ( )
245246 }
246247}
@@ -263,29 +264,29 @@ impl<'tcx, Tag: ::std::fmt::Debug> Place<Tag> {
263264 }
264265
265266 #[ inline]
266- pub fn to_mem_place ( self ) -> MemPlace < Tag > {
267+ pub fn assert_mem_place ( self ) -> MemPlace < Tag > {
267268 match self {
268269 Place :: Ptr ( mplace) => mplace,
269- _ => bug ! ( "to_mem_place : expected Place::Ptr, got {:?}" , self ) ,
270+ _ => bug ! ( "assert_mem_place : expected Place::Ptr, got {:?}" , self ) ,
270271
271272 }
272273 }
273274
274275 #[ inline]
275276 pub fn to_scalar_ptr_align ( self ) -> ( Scalar < Tag > , Align ) {
276- self . to_mem_place ( ) . to_scalar_ptr_align ( )
277+ self . assert_mem_place ( ) . to_scalar_ptr_align ( )
277278 }
278279
279280 #[ inline]
280281 pub fn to_ptr ( self ) -> InterpResult < ' tcx , Pointer < Tag > > {
281- self . to_mem_place ( ) . to_ptr ( )
282+ self . assert_mem_place ( ) . to_ptr ( )
282283 }
283284}
284285
285286impl < ' tcx , Tag : :: std:: fmt:: Debug > PlaceTy < ' tcx , Tag > {
286287 #[ inline]
287- pub fn to_mem_place ( self ) -> MPlaceTy < ' tcx , Tag > {
288- MPlaceTy { mplace : self . place . to_mem_place ( ) , layout : self . layout }
288+ pub fn assert_mem_place ( self ) -> MPlaceTy < ' tcx , Tag > {
289+ MPlaceTy { mplace : self . place . assert_mem_place ( ) , layout : self . layout }
289290 }
290291}
291292
@@ -322,8 +323,8 @@ where
322323 Ok ( MPlaceTy { mplace, layout } )
323324 }
324325
325- // Take an operand, representing a pointer, and dereference it to a place -- that
326- // will always be a MemPlace. Lives in `place.rs` because it creates a place.
326+ /// Take an operand, representing a pointer, and dereference it to a place -- that
327+ /// will always be a MemPlace. Lives in `place.rs` because it creates a place.
327328 pub fn deref_operand (
328329 & self ,
329330 src : OpTy < ' tcx , M :: PointerTag > ,
@@ -333,6 +334,38 @@ where
333334 self . ref_to_mplace ( val)
334335 }
335336
337+ /// Check if the given place is good for memory access with the given
338+ /// size, falling back to the layout's size if `None` (in the latter case,
339+ /// this must be a statically sized type).
340+ ///
341+ /// On success, returns `None` for zero-sized accesses (where nothing else is
342+ /// left to do) and a `Pointer` to use for the actual access otherwise.
343+ #[ inline]
344+ pub fn check_mplace_access (
345+ & self ,
346+ place : MPlaceTy < ' tcx , M :: PointerTag > ,
347+ size : Option < Size > ,
348+ ) -> InterpResult < ' tcx , Option < Pointer < M :: PointerTag > > > {
349+ let size = size. unwrap_or_else ( || {
350+ assert ! ( !place. layout. is_unsized( ) ) ;
351+ assert ! ( place. meta. is_none( ) ) ;
352+ place. layout . size
353+ } ) ;
354+ self . memory . check_ptr_access ( place. ptr , size, place. align )
355+ }
356+
357+ /// Normalice `place.ptr` to a `Pointer` if this is not a ZST.
358+ /// Can be helpful to avoid lots of `force_ptr` calls later, if this place is used a lot.
359+ pub fn normalize_mplace_ptr (
360+ & self ,
361+ mut place : MPlaceTy < ' tcx , M :: PointerTag > ,
362+ ) -> InterpResult < ' tcx , MPlaceTy < ' tcx , M :: PointerTag > > {
363+ if !place. layout . is_zst ( ) {
364+ place. mplace . ptr = self . force_ptr ( place. mplace . ptr ) ?. into ( ) ;
365+ }
366+ Ok ( place)
367+ }
368+
336369 /// Offset a pointer to project to a field. Unlike `place_field`, this is always
337370 /// possible without allocating, so it can take `&self`. Also return the field's layout.
338371 /// This supports both struct and array fields.
@@ -741,14 +774,12 @@ where
741774 value : Immediate < M :: PointerTag > ,
742775 dest : MPlaceTy < ' tcx , M :: PointerTag > ,
743776 ) -> InterpResult < ' tcx > {
744- let ( ptr, ptr_align) = dest. to_scalar_ptr_align ( ) ;
745777 // Note that it is really important that the type here is the right one, and matches the
746778 // type things are read at. In case `src_val` is a `ScalarPair`, we don't do any magic here
747779 // to handle padding properly, which is only correct if we never look at this data with the
748780 // wrong type.
749- assert ! ( !dest. layout. is_unsized( ) ) ;
750781
751- let ptr = match self . memory . check_ptr_access ( ptr , dest. layout . size , ptr_align ) ? {
782+ let ptr = match self . check_mplace_access ( dest, None ) ? {
752783 Some ( ptr) => ptr,
753784 None => return Ok ( ( ) ) , // zero-sized access
754785 } ;
@@ -850,14 +881,21 @@ where
850881 dest. layout . size
851882 } ) ;
852883 assert_eq ! ( src. meta, dest. meta, "Can only copy between equally-sized instances" ) ;
884+
885+ let src = self . check_mplace_access ( src, Some ( size) ) ?;
886+ let dest = self . check_mplace_access ( dest, Some ( size) ) ?;
887+ let ( src_ptr, dest_ptr) = match ( src, dest) {
888+ ( Some ( src_ptr) , Some ( dest_ptr) ) => ( src_ptr, dest_ptr) ,
889+ ( None , None ) => return Ok ( ( ) ) , // zero-sized copy
890+ _ => bug ! ( "The pointers should both be Some or both None" ) ,
891+ } ;
892+
853893 self . memory . copy (
854- src . ptr , src . align ,
855- dest . ptr , dest . align ,
894+ src_ptr ,
895+ dest_ptr ,
856896 size,
857897 /*nonoverlapping*/ true ,
858- ) ?;
859-
860- Ok ( ( ) )
898+ )
861899 }
862900
863901 /// Copies the data from an operand to a place. The layouts may disagree, but they must
0 commit comments