@@ -34,7 +34,7 @@ use rustc::mir::interpret::{
3434use syntax:: source_map:: { self , Span } ;
3535
3636use super :: {
37- Value , Operand , MemPlace , MPlaceTy , Place , PlaceExtra ,
37+ Value , Operand , MemPlace , MPlaceTy , Place ,
3838 Memory , Machine
3939} ;
4040
@@ -462,90 +462,94 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
462462 }
463463
464464 /// Return the actual dynamic size and alignment of the place at the given type.
465- /// Note that the value does not matter if the type is sized. For unsized types,
466- /// the value has to be a fat pointer, and we only care about the "extra" data in it.
467- pub fn size_and_align_of_mplace (
465+ /// Only the "extra" (metadata) part of the place matters.
466+ pub ( super ) fn size_and_align_of (
468467 & self ,
469- mplace : MPlaceTy < ' tcx > ,
468+ metadata : Option < Scalar > ,
469+ layout : TyLayout < ' tcx > ,
470470 ) -> EvalResult < ' tcx , ( Size , Align ) > {
471- if let PlaceExtra :: None = mplace. extra {
472- assert ! ( !mplace. layout. is_unsized( ) ) ;
473- Ok ( mplace. layout . size_and_align ( ) )
474- } else {
475- let layout = mplace. layout ;
476- assert ! ( layout. is_unsized( ) ) ;
477- match layout. ty . sty {
478- ty:: Adt ( ..) | ty:: Tuple ( ..) => {
479- // First get the size of all statically known fields.
480- // Don't use type_of::sizing_type_of because that expects t to be sized,
481- // and it also rounds up to alignment, which we want to avoid,
482- // as the unsized field's alignment could be smaller.
483- assert ! ( !layout. ty. is_simd( ) ) ;
484- debug ! ( "DST layout: {:?}" , layout) ;
485-
486- let sized_size = layout. fields . offset ( layout. fields . count ( ) - 1 ) ;
487- let sized_align = layout. align ;
488- debug ! (
489- "DST {} statically sized prefix size: {:?} align: {:?}" ,
490- layout. ty,
491- sized_size,
492- sized_align
493- ) ;
494-
495- // Recurse to get the size of the dynamically sized field (must be
496- // the last field).
497- let field = self . mplace_field ( mplace, layout. fields . count ( ) as u64 - 1 ) ?;
498- let ( unsized_size, unsized_align) = self . size_and_align_of_mplace ( field) ?;
499-
500- // FIXME (#26403, #27023): We should be adding padding
501- // to `sized_size` (to accommodate the `unsized_align`
502- // required of the unsized field that follows) before
503- // summing it with `sized_size`. (Note that since #26403
504- // is unfixed, we do not yet add the necessary padding
505- // here. But this is where the add would go.)
506-
507- // Return the sum of sizes and max of aligns.
508- let size = sized_size + unsized_size;
509-
510- // Choose max of two known alignments (combined value must
511- // be aligned according to more restrictive of the two).
512- let align = sized_align. max ( unsized_align) ;
513-
514- // Issue #27023: must add any necessary padding to `size`
515- // (to make it a multiple of `align`) before returning it.
516- //
517- // Namely, the returned size should be, in C notation:
518- //
519- // `size + ((size & (align-1)) ? align : 0)`
520- //
521- // emulated via the semi-standard fast bit trick:
522- //
523- // `(size + (align-1)) & -align`
524-
525- Ok ( ( size. abi_align ( align) , align) )
526- }
527- ty:: Dynamic ( ..) => {
528- let vtable = match mplace. extra {
529- PlaceExtra :: Vtable ( vtable) => vtable,
530- _ => bug ! ( "Expected vtable" ) ,
531- } ;
532- // the second entry in the vtable is the dynamic size of the object.
533- self . read_size_and_align_from_vtable ( vtable)
534- }
535-
536- ty:: Slice ( _) | ty:: Str => {
537- let len = match mplace. extra {
538- PlaceExtra :: Length ( len) => len,
539- _ => bug ! ( "Expected length" ) ,
540- } ;
541- let ( elem_size, align) = layout. field ( self , 0 ) ?. size_and_align ( ) ;
542- Ok ( ( elem_size * len, align) )
543- }
471+ let metadata = match metadata {
472+ None => {
473+ assert ! ( !layout. is_unsized( ) ) ;
474+ return Ok ( layout. size_and_align ( ) )
475+ }
476+ Some ( metadata) => {
477+ assert ! ( layout. is_unsized( ) ) ;
478+ metadata
479+ }
480+ } ;
481+ match layout. ty . sty {
482+ ty:: Adt ( ..) | ty:: Tuple ( ..) => {
483+ // First get the size of all statically known fields.
484+ // Don't use type_of::sizing_type_of because that expects t to be sized,
485+ // and it also rounds up to alignment, which we want to avoid,
486+ // as the unsized field's alignment could be smaller.
487+ assert ! ( !layout. ty. is_simd( ) ) ;
488+ debug ! ( "DST layout: {:?}" , layout) ;
489+
490+ let sized_size = layout. fields . offset ( layout. fields . count ( ) - 1 ) ;
491+ let sized_align = layout. align ;
492+ debug ! (
493+ "DST {} statically sized prefix size: {:?} align: {:?}" ,
494+ layout. ty,
495+ sized_size,
496+ sized_align
497+ ) ;
498+
499+ // Recurse to get the size of the dynamically sized field (must be
500+ // the last field).
501+ let field = layout. field ( self , layout. fields . count ( ) - 1 ) ?;
502+ let ( unsized_size, unsized_align) = self . size_and_align_of ( Some ( metadata) , field) ?;
503+
504+ // FIXME (#26403, #27023): We should be adding padding
505+ // to `sized_size` (to accommodate the `unsized_align`
506+ // required of the unsized field that follows) before
507+ // summing it with `sized_size`. (Note that since #26403
508+ // is unfixed, we do not yet add the necessary padding
509+ // here. But this is where the add would go.)
510+
511+ // Return the sum of sizes and max of aligns.
512+ let size = sized_size + unsized_size;
513+
514+ // Choose max of two known alignments (combined value must
515+ // be aligned according to more restrictive of the two).
516+ let align = sized_align. max ( unsized_align) ;
517+
518+ // Issue #27023: must add any necessary padding to `size`
519+ // (to make it a multiple of `align`) before returning it.
520+ //
521+ // Namely, the returned size should be, in C notation:
522+ //
523+ // `size + ((size & (align-1)) ? align : 0)`
524+ //
525+ // emulated via the semi-standard fast bit trick:
526+ //
527+ // `(size + (align-1)) & -align`
528+
529+ Ok ( ( size. abi_align ( align) , align) )
530+ }
531+ ty:: Dynamic ( ..) => {
532+ let vtable = metadata. to_ptr ( ) ?;
533+ // the second entry in the vtable is the dynamic size of the object.
534+ self . read_size_and_align_from_vtable ( vtable)
535+ }
544536
545- _ => bug ! ( "size_of_val::<{:?}> not supported" , layout. ty) ,
537+ ty:: Slice ( _) | ty:: Str => {
538+ let len = metadata. to_usize ( self ) ?;
539+ let ( elem_size, align) = layout. field ( self , 0 ) ?. size_and_align ( ) ;
540+ Ok ( ( elem_size * len, align) )
546541 }
542+
543+ _ => bug ! ( "size_and_align_of::<{:?}> not supported" , layout. ty) ,
547544 }
548545 }
546+ #[ inline]
547+ pub fn size_and_align_of_mplace (
548+ & self ,
549+ mplace : MPlaceTy < ' tcx >
550+ ) -> EvalResult < ' tcx , ( Size , Align ) > {
551+ self . size_and_align_of ( mplace. extra , mplace. layout )
552+ }
549553
550554 pub fn push_stack_frame (
551555 & mut self ,
0 commit comments