- 
                Notifications
    You must be signed in to change notification settings 
- Fork 13.9k
Fix an ICE encountered in clippy that will be possible to trigger in rustc in the future #61041
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
16911bd
              d38fb10
              b535090
              e849b83
              600d679
              27320e3
              b84ed30
              7fac3a1
              8ac4cb5
              fe2013c
              1d26fda
              b917c43
              5a8c9d3
              faa342f
              51e1343
              034939b
              685e0e5
              fdf5450
              3afcb1e
              f0a16c4
              3aa550a
              82db274
              70124ec
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -9,7 +9,7 @@ use rustc::mir; | |
| use rustc::ty::layout::{ | ||
| self, Size, Align, HasDataLayout, LayoutOf, TyLayout | ||
| }; | ||
| use rustc::ty::subst::{Subst, SubstsRef}; | ||
| use rustc::ty::subst::{SubstsRef, Subst}; | ||
| use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; | ||
| use rustc::ty::query::TyCtxtAt; | ||
| use rustc_data_structures::indexed_vec::IndexVec; | ||
|  | @@ -291,22 +291,38 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | |
| ty.is_freeze(*self.tcx, self.param_env, DUMMY_SP) | ||
| } | ||
|  | ||
| pub(super) fn subst_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>( | ||
| /// Call this whenever you have a value that you took from the current frame's `mir::Body`. | ||
| /// Not guaranteed to actually monomorphize the value. | ||
| /// If we are e.g. const propagating inside a generic function, some | ||
| /// things may depend on a generic parameter and thus can never be monomorphized. | ||
| pub(super) fn subst_and_normalize_erasing_regions_in_frame<T: TypeFoldable<'tcx>>( | ||
| &self, | ||
| substs: T, | ||
| value: T, | ||
| ) -> InterpResult<'tcx, T> { | ||
| match self.stack.last() { | ||
| Some(frame) => Ok(self.tcx.subst_and_normalize_erasing_regions( | ||
| frame.instance.substs, | ||
| self.param_env, | ||
| &substs, | ||
| )), | ||
| None => if substs.needs_subst() { | ||
| throw_inval!(TooGeneric) | ||
| } else { | ||
| Ok(substs) | ||
| }, | ||
| self.subst_and_normalize_erasing_regions(self.frame().instance.substs, value) | ||
| } | ||
|  | ||
| /// Same thing as `subst_and_normalize_erasing_regions_in_frame` but not taking its substs | ||
| /// from the top stack frame, but requiring you to pass specific substs. | ||
| /// | ||
| /// Only call this function if you want to apply the substs of a specific frame (that is | ||
| /// definitely not the frame currently being evaluated). You need to make sure to pass correct | ||
| /// substs. | ||
| fn subst_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>( | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function shouldn't be needed (as a separate thing). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's needed for layout_of_local There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd inline it there. | ||
| &self, | ||
| param_substs: SubstsRef<'tcx>, | ||
| value: T, | ||
| ) -> InterpResult<'tcx, T> { | ||
| let substituted = value.subst(self.tcx.tcx, param_substs); | ||
| // we duplicate the body of `TyCtxt::subst_and_normalize_erasing_regions` here, because | ||
| // we can't normalize values with generic parameters. The difference between this function | ||
| // and the `TyCtxt` version is this early abort | ||
| if substituted.needs_subst() { | ||
| // FIXME(oli-obk): This aborts evaluating `fn foo<T>() -> i32 { 42 }` inside an | ||
| // associated constant of a generic trait, even though that should be doable. | ||
| throw_inval!(TooGeneric); | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does anything break if you remove this? | ||
| } | ||
| Ok(self.tcx.normalize_erasing_regions(self.param_env, substituted)) | ||
| } | ||
|  | ||
| pub(super) fn resolve( | ||
|  | @@ -315,9 +331,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | |
| substs: SubstsRef<'tcx> | ||
| ) -> InterpResult<'tcx, ty::Instance<'tcx>> { | ||
| trace!("resolve: {:?}, {:#?}", def_id, substs); | ||
| trace!("param_env: {:#?}", self.param_env); | ||
| let substs = self.subst_and_normalize_erasing_regions(substs)?; | ||
| trace!("substs: {:#?}", substs); | ||
| ty::Instance::resolve( | ||
| *self.tcx, | ||
| self.param_env, | ||
|  | @@ -349,36 +362,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | |
| } | ||
| } | ||
|  | ||
| pub(super) fn monomorphize<T: TypeFoldable<'tcx> + Subst<'tcx>>( | ||
| &self, | ||
| t: T, | ||
| ) -> InterpResult<'tcx, T> { | ||
| match self.stack.last() { | ||
| Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)?), | ||
| None => if t.needs_subst() { | ||
| throw_inval!(TooGeneric) | ||
| } else { | ||
| Ok(t) | ||
| }, | ||
| } | ||
| } | ||
|  | ||
| fn monomorphize_with_substs<T: TypeFoldable<'tcx> + Subst<'tcx>>( | ||
| &self, | ||
| t: T, | ||
| substs: SubstsRef<'tcx> | ||
| ) -> InterpResult<'tcx, T> { | ||
| // miri doesn't care about lifetimes, and will choke on some crazy ones | ||
| // let's simply get rid of them | ||
| let substituted = t.subst(*self.tcx, substs); | ||
|  | ||
| if substituted.needs_subst() { | ||
| throw_inval!(TooGeneric) | ||
| } | ||
|  | ||
| Ok(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted)) | ||
| } | ||
|  | ||
| pub fn layout_of_local( | ||
| &self, | ||
| frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, | ||
|  | @@ -391,7 +374,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | |
| None => { | ||
| let layout = crate::interpret::operand::from_known_layout(layout, || { | ||
| let local_ty = frame.body.local_decls[local].ty; | ||
| let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs)?; | ||
| let local_ty = self.subst_and_normalize_erasing_regions( | ||
| frame.instance.substs, local_ty, | ||
| )?; | ||
| self.layout_of(local_ty) | ||
| })?; | ||
| if let Some(state) = frame.locals.get(local) { | ||
|  | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -3,7 +3,7 @@ | |
|  | ||
| use std::convert::TryInto; | ||
|  | ||
| use rustc::{mir, ty}; | ||
| use rustc::{mir, ty::{self, Ty}}; | ||
| use rustc::ty::layout::{ | ||
| self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt, VariantIdx, | ||
| }; | ||
|  | @@ -511,7 +511,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | |
| Move(ref place) => | ||
| self.eval_place_to_op(place, layout)?, | ||
|  | ||
| Constant(ref constant) => self.eval_const_to_op(constant.literal, layout)?, | ||
| Constant(ref constant) => { | ||
| let val = self.subst_and_normalize_erasing_regions_in_frame(constant.literal.val)?; | ||
| let ty = self.subst_and_normalize_erasing_regions_in_frame(constant.ty)?; | ||
| self.eval_const_to_op(val, ty, layout)? | ||
| }, | ||
| }; | ||
| trace!("{:?}: {:?}", mir_op, *op); | ||
| Ok(op) | ||
|  | @@ -531,18 +535,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | |
| // in patterns via the `const_eval` module | ||
| crate fn eval_const_to_op( | ||
| &self, | ||
| val: &'tcx ty::Const<'tcx>, | ||
| value: ConstValue<'tcx>, | ||
| ty: Ty<'tcx>, | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add a HACK/FIXME comment. Or even better, wait for #56137 to be fixed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is, rebase this on top of #63495. | ||
| layout: Option<TyLayout<'tcx>>, | ||
| ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { | ||
| let tag_scalar = |scalar| match scalar { | ||
| Scalar::Ptr(ptr) => Scalar::Ptr(self.tag_static_base_pointer(ptr)), | ||
| Scalar::Raw { data, size } => Scalar::Raw { data, size }, | ||
| }; | ||
| // Early-return cases. | ||
| match val.val { | ||
| ConstValue::Param(_) => | ||
| // FIXME(oli-obk): try to monomorphize | ||
| throw_inval!(TooGeneric), | ||
| match value { | ||
| ConstValue::Param(_) => throw_inval!(TooGeneric), | ||
| ConstValue::Unevaluated(def_id, substs) => { | ||
| let instance = self.resolve(def_id, substs)?; | ||
| return Ok(OpTy::from(self.const_eval_raw(GlobalId { | ||
|  | @@ -553,10 +556,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | |
| _ => {} | ||
| } | ||
| // Other cases need layout. | ||
| let layout = from_known_layout(layout, || { | ||
| self.layout_of(self.monomorphize(val.ty)?) | ||
| })?; | ||
| let op = match val.val { | ||
| let layout = from_known_layout(layout, || self.layout_of(ty))?; | ||
| let op = match value { | ||
| ConstValue::ByRef { alloc, offset } => { | ||
| let id = self.tcx.alloc_map.lock().create_memory_alloc(alloc); | ||
| // We rely on mutability being set correctly in that allocation to prevent writes | ||
|  | @@ -583,7 +584,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | |
| ConstValue::Infer(..) | | ||
| ConstValue::Placeholder(..) | | ||
| ConstValue::Unevaluated(..) => | ||
| bug!("eval_const_to_op: Unexpected ConstValue {:?}", val), | ||
| bug!("eval_const_to_op: Unexpected ConstValue {:?}", value), | ||
| }; | ||
| Ok(OpTy { op, layout }) | ||
| } | ||
|  | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| // revisions:cfail1 cfail2 | ||
| // check-pass | ||
| // compile-flags: --crate-type staticlib | ||
|  | ||
| #![deny(unused_attributes)] | ||
|  | ||
| #[no_mangle] | ||
| pub extern "C" fn rust_no_mangle() -> i32 { | ||
| 42 | ||
| } | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| pub struct Foo<A, B>(A, B); | ||
|  | ||
| impl<A, B> Foo<A, B> { | ||
| const HOST_SIZE: usize = std::mem::size_of::<B>(); | ||
|  | ||
| pub fn crash() -> bool { | ||
| [5; Self::HOST_SIZE] == [6; 0] //~ ERROR no associated item named `HOST_SIZE` | ||
| //~^ the size for values of type `A` cannot be known | ||
| //~| the size for values of type `B` cannot be known | ||
| } | ||
| } | ||
|  | ||
| fn main() {} | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| error[E0599]: no associated item named `HOST_SIZE` found for type `Foo<A, B>` in the current scope | ||
| --> $DIR/too_generic_eval_ice.rs:7:19 | ||
| | | ||
| LL | pub struct Foo<A, B>(A, B); | ||
| | --------------------------- associated item `HOST_SIZE` not found for this | ||
| ... | ||
| LL | [5; Self::HOST_SIZE] == [6; 0] | ||
| | ^^^^^^^^^ associated item not found in `Foo<A, B>` | ||
| | | ||
| = note: the method `HOST_SIZE` exists but the following trait bounds were not satisfied: | ||
| `A : std::marker::Sized` | ||
| `B : std::marker::Sized` | ||
|  | ||
| error[E0277]: the size for values of type `A` cannot be known at compilation time | ||
| --> $DIR/too_generic_eval_ice.rs:7:13 | ||
| | | ||
| LL | [5; Self::HOST_SIZE] == [6; 0] | ||
| | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | ||
| | | ||
| = help: the trait `std::marker::Sized` is not implemented for `A` | ||
| = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> | ||
| = help: consider adding a `where A: std::marker::Sized` bound | ||
| note: required by `Foo` | ||
| --> $DIR/too_generic_eval_ice.rs:1:1 | ||
| | | ||
| LL | pub struct Foo<A, B>(A, B); | ||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|  | ||
| error[E0277]: the size for values of type `B` cannot be known at compilation time | ||
| --> $DIR/too_generic_eval_ice.rs:7:13 | ||
| | | ||
| LL | [5; Self::HOST_SIZE] == [6; 0] | ||
| | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | ||
| | | ||
| = help: the trait `std::marker::Sized` is not implemented for `B` | ||
| = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> | ||
| = help: consider adding a `where B: std::marker::Sized` bound | ||
| note: required by `Foo` | ||
| --> $DIR/too_generic_eval_ice.rs:1:1 | ||
| | | ||
| LL | pub struct Foo<A, B>(A, B); | ||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|  | ||
| error: aborting due to 3 previous errors | ||
|  | ||
| Some errors have detailed explanations: E0277, E0599. | ||
| For more information about an error, try `rustc --explain E0277`. | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@RalfJung came up with
subst_from_frame_and_normalize_erasing_regions, I kinda like that more?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In particular this finally made it click for me in terms of: we need this when taking something from the current frame to move it into the
InterpCx"universe".Also see the comments I wrote for my own experiments here and here; I think it would be useful to carry those over.