diff options
| author | Ralf Jung <post@ralfj.de> | 2022-07-03 22:55:25 -0400 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2022-07-03 22:55:25 -0400 |
| commit | d7edf66a5a92f66672bc9e84d58db170b3ea2d9a (patch) | |
| tree | fc6862db63204788e05ebd9481898acdc781b8f9 | |
| parent | 7fc77806d4f66819cf9d7ebd53a3338686c08b7d (diff) | |
| download | rust-d7edf66a5a92f66672bc9e84d58db170b3ea2d9a.tar.gz rust-d7edf66a5a92f66672bc9e84d58db170b3ea2d9a.zip | |
move Box mess handling into general visitor
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/validity.rs | 40 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/visitor.rs | 49 |
2 files changed, 55 insertions, 34 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 600d25548d4..0bf78446e37 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -593,38 +593,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' self.check_safe_pointer(value, "reference")?; Ok(true) } - ty::Adt(def, ..) if def.is_box() => { - // Box is special, very special. We carefully assert all the assumptions we make - // here; if this needs to be adjusted, remember to also adjust all the other - // visitors -- in particular the Stacked Borrows retagging visitor in Miri. - // Did I mention that this is a gross hack? Anyway... - - // `Box` has two fields: the pointer we care about, and the allocator. - assert_eq!(value.layout.fields.count(), 2, "`Box` must have exactly 2 fields"); - let (unique_ptr, alloc) = - (self.ecx.operand_field(value, 0)?, self.ecx.operand_field(value, 1)?); - // Unfortunately there is some type junk in the way here: `unique_ptr` is a `Unique`... - // (which means another 2 fields, the second of which is a `PhantomData`) - assert_eq!(unique_ptr.layout.fields.count(), 2); - let (nonnull_ptr, phantom) = ( - self.ecx.operand_field(&unique_ptr, 0)?, - self.ecx.operand_field(&unique_ptr, 1)?, - ); - assert!( - phantom.layout.ty.ty_adt_def().is_some_and(|adt| adt.is_phantom_data()), - "2nd field of `Unique` should be PhantomData but is {:?}", - phantom.layout.ty, - ); - // ... that contains a `NonNull`... (gladly, only a single field here) - assert_eq!(nonnull_ptr.layout.fields.count(), 1); - let raw_ptr = self.ecx.operand_field(&nonnull_ptr, 0)?; // the actual raw ptr - // ... whose only field finally is a raw ptr we can dereference. - self.check_safe_pointer(&raw_ptr, "box")?; - // The second `Box` field is the allocator, which we recursively check for validity - // like in regular structs. - self.walk_value(&alloc)?; - Ok(true) - } ty::FnPtr(_sig) => { let value = try_validation!( self.ecx.read_scalar(value).and_then(|v| v.check_init()), @@ -836,6 +804,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> } #[inline] + fn visit_box(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { + self.check_safe_pointer(op, "box")?; + Ok(()) + } + + #[inline] fn visit_value(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { trace!("visit_value: {:?}, {:?}", *op, op.layout); @@ -843,8 +817,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> if self.try_visit_primitive(op)? { return Ok(()); } - // Sanity check: `builtin_deref` does not know any pointers that are not primitive. - assert!(op.layout.ty.builtin_deref(true).is_none()); // Special check preventing `UnsafeCell` in the inner part of constants if let Some(def) = op.layout.ty.ty_adt_def() { diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index 2b77ed89893..ded4c6a557a 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -151,6 +151,14 @@ macro_rules! make_value_visitor { { Ok(()) } + /// Visits the given value as the pointer of a `Box`. There is nothing to recurse into. + /// The type of `v` will be a raw pointer, but this is a field of `Box<T>` and the + /// pointee type is the actual `T`. + #[inline(always)] + fn visit_box(&mut self, _v: &Self::V) -> InterpResult<'tcx> + { + Ok(()) + } /// Visits this value as an aggregate, you are getting an iterator yielding /// all the fields (still in an `InterpResult`, you have to do error handling yourself). /// Recurses into the fields. @@ -221,6 +229,47 @@ macro_rules! make_value_visitor { // Slices do not need special handling here: they have `Array` field // placement with length 0, so we enter the `Array` case below which // indirectly uses the metadata to determine the actual length. + + // However, `Box`... let's talk about `Box`. + ty::Adt(def, ..) if def.is_box() => { + // `Box` is a hybrid primitive-library-defined type that one the one hand is + // a dereferenceable pointer, on the other hand has *basically arbitrary + // user-defined layout* since the user controls the 'allocator' field. So it + // cannot be treated like a normal pointer, since it does not fit into an + // `Immediate`. Yeah, it is quite terrible. But many visitors want to do + // something with "all boxed pointers", so we handle this mess for them. + // + // When we hit a `Box`, we do not do the usual `visit_aggregate`; instead, + // we (a) call `visit_box` on the pointer value, and (b) recurse on the + // allocator field. We also assert tons of things to ensure we do not miss + // any other fields. + + // `Box` has two fields: the pointer we care about, and the allocator. + assert_eq!(v.layout().fields.count(), 2, "`Box` must have exactly 2 fields"); + let (unique_ptr, alloc) = + (v.project_field(self.ecx(), 0)?, v.project_field(self.ecx(), 1)?); + // Unfortunately there is some type junk in the way here: `unique_ptr` is a `Unique`... + // (which means another 2 fields, the second of which is a `PhantomData`) + assert_eq!(unique_ptr.layout().fields.count(), 2); + let (nonnull_ptr, phantom) = ( + unique_ptr.project_field(self.ecx(), 0)?, + unique_ptr.project_field(self.ecx(), 1)?, + ); + assert!( + phantom.layout().ty.ty_adt_def().is_some_and(|adt| adt.is_phantom_data()), + "2nd field of `Unique` should be PhantomData but is {:?}", + phantom.layout().ty, + ); + // ... that contains a `NonNull`... (gladly, only a single field here) + assert_eq!(nonnull_ptr.layout().fields.count(), 1); + let raw_ptr = nonnull_ptr.project_field(self.ecx(), 0)?; // the actual raw ptr + // ... whose only field finally is a raw ptr we can dereference. + self.visit_box(&raw_ptr)?; + + // The second `Box` field is the allocator, which we recursively check for validity + // like in regular structs. + self.visit_field(v, 1, &alloc)?; + } _ => {}, }; |
