You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Auto merge of #114011 - RalfJung:place-projection, r=oli-obk
interpret: Unify projections for MPlaceTy, PlaceTy, OpTy
For ~forever, we didn't really have proper shared code for handling projections into those three types. This is mostly because `PlaceTy` projections require `&mut self`: they might have to `force_allocate` to be able to represent a project part-way into a local.
This PR finally fixes that, by enhancing `Place::Local` with an `offset` so that such an optimized place can point into a part of a place without having requiring an in-memory representation. If we later write to that place, we will still do `force_allocate` -- for now we don't have an optimized path in `write_immediate` that would avoid allocation for partial overwrites of immediately stored locals. But in `write_immediate` we have `&mut self` so at least this no longer pollutes all our type signatures.
(Ironically, I seem to distantly remember that many years ago, `Place::Local` *did* have an `offset`, and I removed it to simplify things. I guess I didn't realize why it was so useful... I am also not sure if this was actually used to achieve place projection on `&self` back then.)
The `offset` had type `Option<Size>`, where `None` represent "no projection was applied". This is needed because locals *can* be unsized (when they are arguments) but `Place::Local` cannot store metadata: if the offset is `None`, this refers to the entire local, so we can use the metadata of the local itself (which must be indirect); if a projection gets applied, since the local is indirect, it will turn into a `Place::Ptr`. (Note that even for indirect locals we can have `Place::Local`: when the local appears in MIR, we always start with `Place::Local`, and only check `frame.locals` later. We could eagerly normalize to `Place::Ptr` but I don't think that would actually simplify things much.)
Having done all that, we can finally properly abstract projections: we have a new `Projectable` trait that has the basic methods required for projecting, and then all projection methods are implemented for anything that implements that trait. We can even implement it for `ImmTy`! (Not that we need that, but it seems neat.) The visitor can be greatly simplified; it doesn't need its own trait any more but it can use the `Projectable` trait. We also don't need the separate `Mut` visitor any more; that was required only to reflect that projections on `PlaceTy` needed `&mut self`.
It is possible that there are some more `&mut self` that can now become `&self`... I guess we'll notice that over time.
r? `@oli-obk`
The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
410
410
411
+
const_eval_uninhabited_enum_tag = {$front_matter}: encountered an uninhabited enum variant
412
+
const_eval_uninhabited_enum_variant_read =
413
+
read discriminant of an uninhabited enum variant
411
414
const_eval_uninhabited_enum_variant_written =
412
-
writing discriminant of an uninhabited enum
415
+
writing discriminant of an uninhabited enum variant
413
416
const_eval_uninhabited_val = {$front_matter}: encountered a value of uninhabited type `{$ty}`
// For consisteny with `write_discriminant`, and to make sure that `project_downcast` cannot fail due to strange layouts, we declare immediate UB for uninhabited variants.
240
+
if op.layout.for_variant(self, index).abi.is_uninhabited(){
241
+
throw_ub!(UninhabitedEnumVariantRead(index))
242
+
}
243
+
Ok(index)
244
+
}
245
+
246
+
pubfndiscriminant_for_variant(
247
+
&self,
248
+
layout:TyAndLayout<'tcx>,
249
+
variant:VariantIdx,
250
+
) -> InterpResult<'tcx,Scalar<M::Provenance>>{
251
+
let discr_layout = self.layout_of(layout.ty.discriminant_ty(*self.tcx))?;
0 commit comments