@@ -826,8 +826,6 @@ where
826
826
src : OpTy < ' tcx , M :: PointerTag > ,
827
827
dest : PlaceTy < ' tcx , M :: PointerTag > ,
828
828
) -> EvalResult < ' tcx > {
829
- debug_assert ! ( !src. layout. is_unsized( ) && !dest. layout. is_unsized( ) ,
830
- "Cannot copy unsized data" ) ;
831
829
// We do NOT compare the types for equality, because well-typed code can
832
830
// actually "transmute" `&mut T` to `&T` in an assignment without a cast.
833
831
assert ! ( src. layout. details == dest. layout. details,
@@ -836,6 +834,7 @@ where
836
834
// Let us see if the layout is simple so we take a shortcut, avoid force_allocation.
837
835
let src = match self . try_read_immediate ( src) ? {
838
836
Ok ( src_val) => {
837
+ assert ! ( !src. layout. is_unsized( ) , "cannot have unsized immediates" ) ;
839
838
// Yay, we got a value that we can write directly.
840
839
// FIXME: Add a check to make sure that if `src` is indirect,
841
840
// it does not overlap with `dest`.
@@ -846,13 +845,19 @@ where
846
845
// Slow path, this does not fit into an immediate. Just memcpy.
847
846
trace ! ( "copy_op: {:?} <- {:?}: {}" , * dest, src, dest. layout. ty) ;
848
847
849
- let dest = self . force_allocation ( dest) ?;
850
- let ( src_ptr, src_align) = src. to_scalar_ptr_align ( ) ;
851
- let ( dest_ptr, dest_align) = dest. to_scalar_ptr_align ( ) ;
848
+ // This interprets `src.meta` with the `dest` local's layout, if an unsized local
849
+ // is being initialized!
850
+ let ( dest, size) = self . force_allocation_maybe_sized ( dest, src. meta ) ?;
851
+ let size = size. unwrap_or_else ( || {
852
+ assert ! ( !dest. layout. is_unsized( ) ,
853
+ "Cannot copy into already initialized unsized place" ) ;
854
+ dest. layout . size
855
+ } ) ;
856
+ assert_eq ! ( src. meta, dest. meta, "Can only copy between equally-sized instances" ) ;
852
857
self . memory . copy (
853
- src_ptr , src_align ,
854
- dest_ptr , dest_align ,
855
- dest . layout . size ,
858
+ src . ptr , src . align ,
859
+ dest . ptr , dest . align ,
860
+ size,
856
861
/*nonoverlapping*/ true ,
857
862
) ?;
858
863
@@ -870,11 +875,13 @@ where
870
875
// Fast path: Just use normal `copy_op`
871
876
return self . copy_op ( src, dest) ;
872
877
}
873
- // We still require the sizes to match
874
- debug_assert ! ( !src. layout. is_unsized( ) && !dest. layout. is_unsized( ) ,
875
- "Cannot copy unsized data" ) ;
878
+ // We still require the sizes to match.
876
879
assert ! ( src. layout. size == dest. layout. size,
877
880
"Size mismatch when transmuting!\n src: {:#?}\n dest: {:#?}" , src, dest) ;
881
+ // Unsized copies rely on interpreting `src.meta` with `dest.layout`, we want
882
+ // to avoid that here.
883
+ assert ! ( !src. layout. is_unsized( ) && !dest. layout. is_unsized( ) ,
884
+ "Cannot transmute unsized data" ) ;
878
885
879
886
// The hard case is `ScalarPair`. `src` is already read from memory in this case,
880
887
// using `src.layout` to figure out which bytes to use for the 1st and 2nd field.
@@ -902,11 +909,16 @@ where
902
909
/// If the place currently refers to a local that doesn't yet have a matching allocation,
903
910
/// create such an allocation.
904
911
/// This is essentially `force_to_memplace`.
905
- pub fn force_allocation (
912
+ ///
913
+ /// This supports unsized types and returnes the computed size to avoid some
914
+ /// redundant computation when copying; use `force_allocation` for a simpler, sized-only
915
+ /// version.
916
+ pub fn force_allocation_maybe_sized (
906
917
& mut self ,
907
918
place : PlaceTy < ' tcx , M :: PointerTag > ,
908
- ) -> EvalResult < ' tcx , MPlaceTy < ' tcx , M :: PointerTag > > {
909
- let mplace = match place. place {
919
+ meta : Option < Scalar < M :: PointerTag > > ,
920
+ ) -> EvalResult < ' tcx , ( MPlaceTy < ' tcx , M :: PointerTag > , Option < Size > ) > {
921
+ let ( mplace, size) = match place. place {
910
922
Place :: Local { frame, local } => {
911
923
match self . stack [ frame] . locals [ local] . access_mut ( ) ? {
912
924
Ok ( local_val) => {
@@ -926,44 +938,51 @@ where
926
938
// We need the layout of the local. We can NOT use the layout we got,
927
939
// that might e.g., be an inner field of a struct with `Scalar` layout,
928
940
// that has different alignment than the outer field.
941
+ // We also need to support unsized types, and hence cannot use `allocate`.
929
942
let local_layout = self . layout_of_local ( & self . stack [ frame] , local, None ) ?;
930
- let ptr = self . allocate ( local_layout, MemoryKind :: Stack ) ;
943
+ let ( size, align) = self . size_and_align_of ( meta, local_layout) ?
944
+ . expect ( "Cannot allocate for non-dyn-sized type" ) ;
945
+ let ptr = self . memory . allocate ( size, align, MemoryKind :: Stack ) ;
946
+ let ptr = M :: tag_new_allocation ( self , ptr, MemoryKind :: Stack ) ;
947
+ let mplace = MemPlace { ptr : ptr. into ( ) , align, meta } ;
931
948
if let Some ( value) = old_val {
932
949
// Preserve old value.
933
950
// We don't have to validate as we can assume the local
934
951
// was already valid for its type.
935
- self . write_immediate_to_mplace_no_validate ( value, ptr) ?;
952
+ let mplace = MPlaceTy { mplace, layout : local_layout } ;
953
+ self . write_immediate_to_mplace_no_validate ( value, mplace) ?;
936
954
}
937
- let mplace = ptr. mplace ;
938
955
// Now we can call `access_mut` again, asserting it goes well,
939
956
// and actually overwrite things.
940
957
* self . stack [ frame] . locals [ local] . access_mut ( ) . unwrap ( ) . unwrap ( ) =
941
958
LocalValue :: Live ( Operand :: Indirect ( mplace) ) ;
942
- mplace
959
+ ( mplace, Some ( size ) )
943
960
}
944
- Err ( mplace) => mplace, // this already was an indirect local
961
+ Err ( mplace) => ( mplace, None ) , // this already was an indirect local
945
962
}
946
963
}
947
- Place :: Ptr ( mplace) => mplace
964
+ Place :: Ptr ( mplace) => ( mplace, None )
948
965
} ;
949
966
// Return with the original layout, so that the caller can go on
950
- Ok ( MPlaceTy { mplace, layout : place. layout } )
967
+ Ok ( ( MPlaceTy { mplace, layout : place. layout } , size) )
968
+ }
969
+
970
+ #[ inline( always) ]
971
+ pub fn force_allocation (
972
+ & mut self ,
973
+ place : PlaceTy < ' tcx , M :: PointerTag > ,
974
+ ) -> EvalResult < ' tcx , MPlaceTy < ' tcx , M :: PointerTag > > {
975
+ Ok ( self . force_allocation_maybe_sized ( place, None ) ?. 0 )
951
976
}
952
977
953
978
pub fn allocate (
954
979
& mut self ,
955
980
layout : TyLayout < ' tcx > ,
956
981
kind : MemoryKind < M :: MemoryKinds > ,
957
982
) -> MPlaceTy < ' tcx , M :: PointerTag > {
958
- if layout. is_unsized ( ) {
959
- assert ! ( self . tcx. features( ) . unsized_locals, "cannot alloc memory for unsized type" ) ;
960
- // FIXME: What should we do here? We should definitely also tag!
961
- MPlaceTy :: dangling ( layout, self )
962
- } else {
963
- let ptr = self . memory . allocate ( layout. size , layout. align . abi , kind) ;
964
- let ptr = M :: tag_new_allocation ( self , ptr, kind) ;
965
- MPlaceTy :: from_aligned_ptr ( ptr, layout)
966
- }
983
+ let ptr = self . memory . allocate ( layout. size , layout. align . abi , kind) ;
984
+ let ptr = M :: tag_new_allocation ( self , ptr, kind) ;
985
+ MPlaceTy :: from_aligned_ptr ( ptr, layout)
967
986
}
968
987
969
988
pub fn write_discriminant_index (
0 commit comments