@@ -33,7 +33,7 @@ pub enum Immediate<Prov: Provenance = AllocId> {
3333 /// A pair of two scalar value (must have `ScalarPair` ABI where both fields are
3434 /// `Scalar::Initialized`).
3535 ScalarPair ( Scalar < Prov > , Scalar < Prov > ) ,
36- /// A value of fully uninitialized memory. Can have arbitrary size and layout.
36+ /// A value of fully uninitialized memory. Can have arbitrary size and layout, but must be sized .
3737 Uninit ,
3838}
3939
@@ -190,16 +190,19 @@ impl<'tcx, Prov: Provenance> From<ImmTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
190190impl < ' tcx , Prov : Provenance > ImmTy < ' tcx , Prov > {
191191 #[ inline]
192192 pub fn from_scalar ( val : Scalar < Prov > , layout : TyAndLayout < ' tcx > ) -> Self {
193+ debug_assert ! ( layout. abi. is_scalar( ) , "`ImmTy::from_scalar` on non-scalar layout" ) ;
193194 ImmTy { imm : val. into ( ) , layout }
194195 }
195196
196- #[ inline]
197+ #[ inline( always ) ]
197198 pub fn from_immediate ( imm : Immediate < Prov > , layout : TyAndLayout < ' tcx > ) -> Self {
199+ debug_assert ! ( layout. is_sized( ) , "immediates must be sized" ) ;
198200 ImmTy { imm, layout }
199201 }
200202
201203 #[ inline]
202204 pub fn uninit ( layout : TyAndLayout < ' tcx > ) -> Self {
205+ debug_assert ! ( layout. is_sized( ) , "immediates must be sized" ) ;
203206 ImmTy { imm : Immediate :: Uninit , layout }
204207 }
205208
@@ -322,15 +325,12 @@ impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for OpTy<'tcx, Pr
322325 self . layout
323326 }
324327
328+ #[ inline]
325329 fn meta ( & self ) -> InterpResult < ' tcx , MemPlaceMeta < Prov > > {
326330 Ok ( match self . as_mplace_or_imm ( ) {
327331 Left ( mplace) => mplace. meta ,
328332 Right ( _) => {
329- if self . layout . is_unsized ( ) {
330- // Unsized immediate OpTy cannot occur. We create a MemPlace for all unsized locals during argument passing.
331- // However, ConstProp doesn't do that, so we can run into this nonsense situation.
332- throw_inval ! ( ConstPropNonsense ) ;
333- }
333+ debug_assert ! ( self . layout. is_sized( ) , "unsized immediates are not a thing" ) ;
334334 MemPlaceMeta :: None
335335 }
336336 } )
@@ -346,9 +346,10 @@ impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for OpTy<'tcx, Pr
346346 match self . as_mplace_or_imm ( ) {
347347 Left ( mplace) => Ok ( mplace. offset_with_meta ( offset, meta, layout, ecx) ?. into ( ) ) ,
348348 Right ( imm) => {
349- assert ! ( !meta. has_meta( ) ) ; // no place to store metadata here
349+ debug_assert ! ( layout. is_sized( ) , "unsized immediates are not a thing" ) ;
350+ assert_matches ! ( meta, MemPlaceMeta :: None ) ; // no place to store metadata here
350351 // Every part of an uninit is uninit.
351- Ok ( imm. offset ( offset, layout, ecx) ? . into ( ) )
352+ Ok ( imm. offset_ ( offset, layout, ecx) . into ( ) )
352353 }
353354 }
354355 }
@@ -576,6 +577,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
576577 ) -> InterpResult < ' tcx , OpTy < ' tcx , M :: Provenance > > {
577578 let layout = self . layout_of_local ( frame, local, layout) ?;
578579 let op = * frame. locals [ local] . access ( ) ?;
580+ if matches ! ( op, Operand :: Immediate ( _) ) {
581+ if layout. is_unsized ( ) {
582+ // ConstProp marks *all* locals as `Immediate::Uninit` since it cannot
583+ // efficiently check whether they are sized. We have to catch that case here.
584+ throw_inval ! ( ConstPropNonsense ) ;
585+ }
586+ }
579587 Ok ( OpTy { op, layout, align : Some ( layout. align . abi ) } )
580588 }
581589
@@ -589,16 +597,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
589597 match place. as_mplace_or_local ( ) {
590598 Left ( mplace) => Ok ( mplace. into ( ) ) ,
591599 Right ( ( frame, local, offset) ) => {
600+ debug_assert ! ( place. layout. is_sized( ) ) ; // only sized locals can ever be `Place::Local`.
592601 let base = self . local_to_op ( & self . stack ( ) [ frame] , local, None ) ?;
593- let mut field = if let Some ( offset) = offset {
594- // This got offset. We can be sure that the field is sized.
595- base. offset ( offset, place. layout , self ) ?
596- } else {
597- assert_eq ! ( place. layout, base. layout) ;
598- // Unsized cases are possible here since an unsized local will be a
599- // `Place::Local` until the first projection calls `place_to_op` to extract the
600- // underlying mplace.
601- base
602+ let mut field = match offset {
603+ Some ( offset) => base. offset ( offset, place. layout , self ) ?,
604+ None => {
605+ // In the common case this hasn't been projected.
606+ debug_assert_eq ! ( place. layout, base. layout) ;
607+ base
608+ }
602609 } ;
603610 field. align = Some ( place. align ) ;
604611 Ok ( field)
0 commit comments