@@ -33,7 +33,7 @@ pub enum Immediate<Prov: Provenance = AllocId> {
33
33
/// A pair of two scalar value (must have `ScalarPair` ABI where both fields are
34
34
/// `Scalar::Initialized`).
35
35
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 .
37
37
Uninit ,
38
38
}
39
39
@@ -190,16 +190,19 @@ impl<'tcx, Prov: Provenance> From<ImmTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
190
190
impl < ' tcx , Prov : Provenance > ImmTy < ' tcx , Prov > {
191
191
#[ inline]
192
192
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" ) ;
193
194
ImmTy { imm : val. into ( ) , layout }
194
195
}
195
196
196
- #[ inline]
197
+ #[ inline( always ) ]
197
198
pub fn from_immediate ( imm : Immediate < Prov > , layout : TyAndLayout < ' tcx > ) -> Self {
199
+ debug_assert ! ( layout. is_sized( ) , "immediates must be sized" ) ;
198
200
ImmTy { imm, layout }
199
201
}
200
202
201
203
#[ inline]
202
204
pub fn uninit ( layout : TyAndLayout < ' tcx > ) -> Self {
205
+ debug_assert ! ( layout. is_sized( ) , "immediates must be sized" ) ;
203
206
ImmTy { imm : Immediate :: Uninit , layout }
204
207
}
205
208
@@ -322,15 +325,12 @@ impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for OpTy<'tcx, Pr
322
325
self . layout
323
326
}
324
327
328
+ #[ inline]
325
329
fn meta ( & self ) -> InterpResult < ' tcx , MemPlaceMeta < Prov > > {
326
330
Ok ( match self . as_mplace_or_imm ( ) {
327
331
Left ( mplace) => mplace. meta ,
328
332
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" ) ;
334
334
MemPlaceMeta :: None
335
335
}
336
336
} )
@@ -346,9 +346,10 @@ impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for OpTy<'tcx, Pr
346
346
match self . as_mplace_or_imm ( ) {
347
347
Left ( mplace) => Ok ( mplace. offset_with_meta ( offset, meta, layout, ecx) ?. into ( ) ) ,
348
348
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
350
351
// Every part of an uninit is uninit.
351
- Ok ( imm. offset ( offset, layout, ecx) ? . into ( ) )
352
+ Ok ( imm. offset_ ( offset, layout, ecx) . into ( ) )
352
353
}
353
354
}
354
355
}
@@ -576,6 +577,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
576
577
) -> InterpResult < ' tcx , OpTy < ' tcx , M :: Provenance > > {
577
578
let layout = self . layout_of_local ( frame, local, layout) ?;
578
579
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
+ }
579
587
Ok ( OpTy { op, layout, align : Some ( layout. align . abi ) } )
580
588
}
581
589
@@ -589,16 +597,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
589
597
match place. as_mplace_or_local ( ) {
590
598
Left ( mplace) => Ok ( mplace. into ( ) ) ,
591
599
Right ( ( frame, local, offset) ) => {
600
+ debug_assert ! ( place. layout. is_sized( ) ) ; // only sized locals can ever be `Place::Local`.
592
601
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
+ }
602
609
} ;
603
610
field. align = Some ( place. align ) ;
604
611
Ok ( field)
0 commit comments