diff --git a/src/librustc/mir/interpret/queries.rs b/src/librustc/mir/interpret/queries.rs index 161c9a3fcc1f7..ed57f81e78216 100644 --- a/src/librustc/mir/interpret/queries.rs +++ b/src/librustc/mir/interpret/queries.rs @@ -36,11 +36,16 @@ impl<'tcx> TyCtxt<'tcx> { param_env: ty::ParamEnv<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>, + promoted: Option, span: Option, ) -> ConstEvalResult<'tcx> { let instance = ty::Instance::resolve(self, param_env, def_id, substs); if let Some(instance) = instance { - self.const_eval_instance(param_env, instance, span) + if let Some(promoted) = promoted { + self.const_eval_promoted(param_env, instance, promoted) + } else { + self.const_eval_instance(param_env, instance, span) + } } else { Err(ErrorHandled::TooGeneric) } @@ -63,11 +68,11 @@ impl<'tcx> TyCtxt<'tcx> { /// Evaluate a promoted constant. pub fn const_eval_promoted( self, + param_env: ty::ParamEnv<'tcx>, instance: ty::Instance<'tcx>, promoted: mir::Promoted, ) -> ConstEvalResult<'tcx> { let cid = GlobalId { instance, promoted: Some(promoted) }; - let param_env = ty::ParamEnv::reveal_all(); self.const_eval_validated(param_env.and(cid)) } } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index ff64302b1e506..281cf46bdc2dc 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -166,6 +166,16 @@ pub struct Body<'tcx> { /// A span representing this MIR, for error reporting. pub span: Span, + + /// The user may be writing e.g. &[(SOME_CELL, 42)][i].1 and this would get promoted, because + /// we'd statically know that no thing with interior mutability will ever be available to the + /// user without some serious unsafe code. Now this means that our promoted is actually + /// &[(SOME_CELL, 42)] and the MIR using it will do the &promoted[i].1 projection because the + /// index may be a runtime value. Such a promoted value is illegal because it has reachable + /// interior mutability. This flag just makes this situation very obvious where the previous + /// implementation without the flag hid this situation silently. + /// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components. + pub ignore_interior_mut_in_const_validation: bool, } impl<'tcx> Body<'tcx> { @@ -202,6 +212,7 @@ impl<'tcx> Body<'tcx> { spread_arg: None, var_debug_info, span, + ignore_interior_mut_in_const_validation: false, control_flow_destroyed, } } @@ -1642,9 +1653,9 @@ impl Debug for Statement<'_> { /// A path to a value; something that can be evaluated without /// changing or disturbing program state. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, HashStable)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, HashStable)] pub struct Place<'tcx> { - pub base: PlaceBase<'tcx>, + pub local: Local, /// projection out of a place (access a field, deref a pointer, etc) pub projection: &'tcx List>, @@ -1652,58 +1663,6 @@ pub struct Place<'tcx> { impl<'tcx> rustc_serialize::UseSpecializedDecodable for Place<'tcx> {} -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable)] -pub enum PlaceBase<'tcx> { - /// local variable - Local(Local), - - /// static or static mut variable - Static(Box>), -} - -/// We store the normalized type to avoid requiring normalization when reading MIR -#[derive( - Clone, - Debug, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - RustcEncodable, - RustcDecodable, - HashStable -)] -pub struct Static<'tcx> { - pub ty: Ty<'tcx>, - pub kind: StaticKind<'tcx>, - /// The `DefId` of the item this static was declared in. For promoted values, usually, this is - /// the same as the `DefId` of the `mir::Body` containing the `Place` this promoted appears in. - /// However, after inlining, that might no longer be the case as inlined `Place`s are copied - /// into the calling frame. - pub def_id: DefId, -} - -#[derive( - Clone, - Debug, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - HashStable, - RustcEncodable, - RustcDecodable -)] -pub enum StaticKind<'tcx> { - /// Promoted references consist of an id (`Promoted`) and the substs necessary to monomorphize - /// it. Usually, these substs are just the identity substs for the item. However, the inliner - /// will adjust these substs when it inlines a function based on the substs at the callsite. - Promoted(Promoted, SubstsRef<'tcx>), - Static, -} - #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(RustcEncodable, RustcDecodable, HashStable)] pub enum ProjectionElem { @@ -1791,14 +1750,14 @@ rustc_index::newtype_index! { #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct PlaceRef<'a, 'tcx> { - pub base: &'a PlaceBase<'tcx>, + pub local: &'a Local, pub projection: &'a [PlaceElem<'tcx>], } impl<'tcx> Place<'tcx> { // FIXME change this to a const fn by also making List::empty a const fn. pub fn return_place() -> Place<'tcx> { - Place { base: PlaceBase::Local(RETURN_PLACE), projection: List::empty() } + Place { local: RETURN_PLACE, projection: List::empty() } } /// Returns `true` if this `Place` contains a `Deref` projection. @@ -1815,10 +1774,8 @@ impl<'tcx> Place<'tcx> { // FIXME: can we safely swap the semantics of `fn base_local` below in here instead? pub fn local_or_deref_local(&self) -> Option { match self.as_ref() { - PlaceRef { base: &PlaceBase::Local(local), projection: &[] } - | PlaceRef { base: &PlaceBase::Local(local), projection: &[ProjectionElem::Deref] } => { - Some(local) - } + PlaceRef { local, projection: &[] } + | PlaceRef { local, projection: &[ProjectionElem::Deref] } => Some(*local), _ => None, } } @@ -1830,19 +1787,13 @@ impl<'tcx> Place<'tcx> { } pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> { - PlaceRef { base: &self.base, projection: &self.projection } + PlaceRef { local: &self.local, projection: &self.projection } } } impl From for Place<'_> { fn from(local: Local) -> Self { - Place { base: local.into(), projection: List::empty() } - } -} - -impl From for PlaceBase<'_> { - fn from(local: Local) -> Self { - PlaceBase::Local(local) + Place { local, projection: List::empty() } } } @@ -1853,10 +1804,8 @@ impl<'a, 'tcx> PlaceRef<'a, 'tcx> { // FIXME: can we safely swap the semantics of `fn base_local` below in here instead? pub fn local_or_deref_local(&self) -> Option { match self { - PlaceRef { base: PlaceBase::Local(local), projection: [] } - | PlaceRef { base: PlaceBase::Local(local), projection: [ProjectionElem::Deref] } => { - Some(*local) - } + PlaceRef { local, projection: [] } + | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(**local), _ => None, } } @@ -1865,7 +1814,7 @@ impl<'a, 'tcx> PlaceRef<'a, 'tcx> { /// projections, return `Some(_X)`. pub fn as_local(&self) -> Option { match self { - PlaceRef { base: PlaceBase::Local(l), projection: [] } => Some(*l), + PlaceRef { local, projection: [] } => Some(**local), _ => None, } } @@ -1887,7 +1836,7 @@ impl Debug for Place<'_> { } } - write!(fmt, "{:?}", self.base)?; + write!(fmt, "{:?}", self.local)?; for elem in self.projection.iter() { match elem { @@ -1931,22 +1880,6 @@ impl Debug for Place<'_> { } } -impl Debug for PlaceBase<'_> { - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - match *self { - PlaceBase::Local(id) => write!(fmt, "{:?}", id), - PlaceBase::Static(box self::Static { ty, kind: StaticKind::Static, def_id }) => { - write!(fmt, "({}: {:?})", ty::tls::with(|tcx| tcx.def_path_str(def_id)), ty) - } - PlaceBase::Static(box self::Static { - ty, - kind: StaticKind::Promoted(promoted, _), - def_id: _, - }) => write!(fmt, "({:?}: {:?})", promoted, ty), - } - } -} - /////////////////////////////////////////////////////////////////////////// // Scopes @@ -3007,27 +2940,11 @@ impl<'tcx> TypeFoldable<'tcx> for GeneratorKind { impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { - Place { base: self.base.fold_with(folder), projection: self.projection.fold_with(folder) } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.base.visit_with(visitor) || self.projection.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for PlaceBase<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - match self { - PlaceBase::Local(local) => PlaceBase::Local(local.fold_with(folder)), - PlaceBase::Static(static_) => PlaceBase::Static(static_.fold_with(folder)), - } + Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - match self { - PlaceBase::Local(local) => local.visit_with(visitor), - PlaceBase::Static(static_) => (**static_).visit_with(visitor), - } + self.local.visit_with(visitor) || self.projection.visit_with(visitor) } } @@ -3042,42 +2959,6 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { } } -impl<'tcx> TypeFoldable<'tcx> for Static<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - Static { - ty: self.ty.fold_with(folder), - kind: self.kind.fold_with(folder), - def_id: self.def_id, - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - let Static { ty, kind, def_id: _ } = self; - - ty.visit_with(visitor) || kind.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for StaticKind<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - match self { - StaticKind::Promoted(promoted, substs) => { - StaticKind::Promoted(promoted.fold_with(folder), substs.fold_with(folder)) - } - StaticKind::Static => StaticKind::Static, - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match self { - StaticKind::Promoted(promoted, substs) => { - promoted.visit_with(visitor) || substs.visit_with(visitor) - } - StaticKind::Static => false, - } - } -} - impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { use crate::mir::Rvalue::*; diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 77f3ff47ff247..e2aac562cc4cc 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -114,7 +114,7 @@ impl<'tcx> PlaceTy<'tcx> { impl<'tcx> Place<'tcx> { pub fn ty_from( - base: &PlaceBase<'tcx>, + local: &Local, projection: &[PlaceElem<'tcx>], local_decls: &D, tcx: TyCtxt<'tcx>, @@ -124,26 +124,16 @@ impl<'tcx> Place<'tcx> { { projection .iter() - .fold(base.ty(local_decls), |place_ty, elem| place_ty.projection_ty(tcx, elem)) + .fold(PlaceTy::from_ty(local_decls.local_decls()[*local].ty), |place_ty, elem| { + place_ty.projection_ty(tcx, elem) + }) } pub fn ty(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> where D: HasLocalDecls<'tcx>, { - Place::ty_from(&self.base, &self.projection, local_decls, tcx) - } -} - -impl<'tcx> PlaceBase<'tcx> { - pub fn ty(&self, local_decls: &D) -> PlaceTy<'tcx> - where - D: HasLocalDecls<'tcx>, - { - match self { - PlaceBase::Local(index) => PlaceTy::from_ty(local_decls.local_decls()[*index].ty), - PlaceBase::Static(data) => PlaceTy::from_ty(data.ty), - } + Place::ty_from(&self.local, &self.projection, local_decls, tcx) } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 9173c32800641..4c5db1b07d225 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -164,10 +164,10 @@ macro_rules! make_mir_visitor { } fn visit_place_base(&mut self, - base: & $($mutability)? PlaceBase<'tcx>, + local: & $($mutability)? Local, context: PlaceContext, location: Location) { - self.super_place_base(base, context, location); + self.super_place_base(local, context, location); } visit_place_fns!($($mutability)?); @@ -705,17 +705,10 @@ macro_rules! make_mir_visitor { } fn super_place_base(&mut self, - place_base: & $($mutability)? PlaceBase<'tcx>, + local: & $($mutability)? Local, context: PlaceContext, location: Location) { - match place_base { - PlaceBase::Local(local) => { - self.visit_local(local, context, location); - } - PlaceBase::Static(box Static { kind: _, ty, def_id: _ }) => { - self.visit_ty(& $($mutability)? *ty, TyContext::Location(location)); - } - } + self.visit_local(local, context, location); } fn super_local_decl(&mut self, @@ -848,7 +841,7 @@ macro_rules! visit_place_fns { context: PlaceContext, location: Location, ) { - self.visit_place_base(&mut place.base, context, location); + self.visit_place_base(&mut place.local, context, location); if let Some(new_projection) = self.process_projection(&place.projection) { place.projection = self.tcx().intern_place_elems(&new_projection); @@ -889,23 +882,23 @@ macro_rules! visit_place_fns { () => ( fn visit_projection( &mut self, - base: &PlaceBase<'tcx>, + local: &Local, projection: &[PlaceElem<'tcx>], context: PlaceContext, location: Location, ) { - self.super_projection(base, projection, context, location); + self.super_projection(local, projection, context, location); } fn visit_projection_elem( &mut self, - base: &PlaceBase<'tcx>, + local: &Local, proj_base: &[PlaceElem<'tcx>], elem: &PlaceElem<'tcx>, context: PlaceContext, location: Location, ) { - self.super_projection_elem(base, proj_base, elem, context, location); + self.super_projection_elem(local, proj_base, elem, context, location); } fn super_place( @@ -924,9 +917,9 @@ macro_rules! visit_place_fns { }; } - self.visit_place_base(&place.base, context, location); + self.visit_place_base(&place.local, context, location); - self.visit_projection(&place.base, + self.visit_projection(&place.local, &place.projection, context, location); @@ -934,7 +927,7 @@ macro_rules! visit_place_fns { fn super_projection( &mut self, - base: &PlaceBase<'tcx>, + local: &Local, projection: &[PlaceElem<'tcx>], context: PlaceContext, location: Location, @@ -942,13 +935,13 @@ macro_rules! visit_place_fns { let mut cursor = projection; while let [proj_base @ .., elem] = cursor { cursor = proj_base; - self.visit_projection_elem(base, cursor, elem, context, location); + self.visit_projection_elem(local, cursor, elem, context, location); } } fn super_projection_elem( &mut self, - _base: &PlaceBase<'tcx>, + _local: &Local, _proj_base: &[PlaceElem<'tcx>], elem: &PlaceElem<'tcx>, _context: PlaceContext, diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index b0b6994945c5f..46ece6fc40593 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -515,6 +515,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { obligation.param_env, def_id, substs, + None, Some(obligation.cause.span), ) { Ok(_) => ProcessResult::Changed(vec![]), diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 8b66f4926e0c8..e96697cc7e09d 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -802,8 +802,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Predicate::ConstEvaluatable(def_id, substs) => { if !(obligation.param_env, substs).has_local_value() { - match self.tcx().const_eval_resolve(obligation.param_env, def_id, substs, None) - { + match self.tcx().const_eval_resolve( + obligation.param_env, + def_id, + substs, + None, + None, + ) { Ok(_) => Ok(EvaluatedToOk), Err(_) => Ok(EvaluatedToErr), } diff --git a/src/librustc/traits/wf.rs b/src/librustc/traits/wf.rs index 551f8fde12b18..2301395f557f1 100644 --- a/src/librustc/traits/wf.rs +++ b/src/librustc/traits/wf.rs @@ -359,7 +359,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { /// Pushes the obligations required for an array length to be WF /// into `self.out`. fn compute_array_len(&mut self, constant: ty::Const<'tcx>) { - if let ty::ConstKind::Unevaluated(def_id, substs) = constant.val { + if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.val { + assert!(promoted.is_none()); + let obligations = self.nominal_obligations(def_id, substs); self.out.extend(obligations); diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs index 9b2714082f1e1..df1602b2ac46d 100644 --- a/src/librustc/ty/codec.rs +++ b/src/librustc/ty/codec.rs @@ -226,11 +226,11 @@ pub fn decode_place(decoder: &mut D) -> Result, D::Error> where D: TyDecoder<'tcx>, { - let base: mir::PlaceBase<'tcx> = Decodable::decode(decoder)?; + let local: mir::Local = Decodable::decode(decoder)?; let len = decoder.read_usize()?; let projection: &'tcx List> = decoder.tcx().mk_place_elems((0..len).map(|_| Decodable::decode(decoder)))?; - Ok(mir::Place { base, projection }) + Ok(mir::Place { local, projection }) } #[inline] diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 1b0b5fc4d078d..af079736db544 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -2434,7 +2434,7 @@ impl<'tcx> TyCtxt<'tcx> { let mut projection = place.projection.to_vec(); projection.push(elem); - Place { base: place.base, projection: self.intern_place_elems(&projection) } + Place { local: place.local, projection: self.intern_place_elems(&projection) } } pub fn intern_existential_predicates( diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index b9aa12b466589..4a4280ba7dc4d 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -219,7 +219,7 @@ impl FlagComputation { fn add_const(&mut self, c: &ty::Const<'_>) { self.add_ty(c.ty); match c.val { - ty::ConstKind::Unevaluated(_, substs) => { + ty::ConstKind::Unevaluated(_, substs, _) => { self.add_substs(substs); self.add_flags(TypeFlags::HAS_PROJECTION); } diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 16d8934359687..8b1b2bb586597 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -841,23 +841,31 @@ pub trait PrettyPrinter<'tcx>: match (ct.val, &ct.ty.kind) { (_, ty::FnDef(did, substs)) => p!(print_value_path(*did, substs)), - (ty::ConstKind::Unevaluated(did, substs), _) => match self.tcx().def_kind(did) { - Some(DefKind::Static) | Some(DefKind::Const) | Some(DefKind::AssocConst) => { - p!(print_value_path(did, substs)) - } - _ => { - if did.is_local() { - let span = self.tcx().def_span(did); - if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) { - p!(write("{}", snip)) - } else { - p!(write("_: "), print(ct.ty)) + (ty::ConstKind::Unevaluated(did, substs, promoted), _) => { + if let Some(promoted) = promoted { + p!(print_value_path(did, substs)); + p!(write("::{:?}", promoted)); + } else { + match self.tcx().def_kind(did) { + Some(DefKind::Static) + | Some(DefKind::Const) + | Some(DefKind::AssocConst) => p!(print_value_path(did, substs)), + _ => { + if did.is_local() { + let span = self.tcx().def_span(did); + if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) + { + p!(write("{}", snip)) + } else { + p!(write("_: "), print(ct.ty)) + } + } else { + p!(write("_: "), print(ct.ty)) + } } - } else { - p!(write("_: "), print(ct.ty)) } } - }, + } (ty::ConstKind::Infer(..), _) => p!(write("_: "), print(ct.ty)), (ty::ConstKind::Param(ParamConst { name, .. }), _) => p!(write("{}", name)), (ty::ConstKind::Value(value), _) => return self.pretty_print_const_value(value, ct.ty), diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 9472281b56fec..3b9df72266f09 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -568,12 +568,12 @@ pub fn super_relate_consts>( // FIXME(const_generics): this is wrong, as it is a projection ( - ty::ConstKind::Unevaluated(a_def_id, a_substs), - ty::ConstKind::Unevaluated(b_def_id, b_substs), - ) if a_def_id == b_def_id => { + ty::ConstKind::Unevaluated(a_def_id, a_substs, a_promoted), + ty::ConstKind::Unevaluated(b_def_id, b_substs, b_promoted), + ) if a_def_id == b_def_id && a_promoted == b_promoted => { let substs = relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?; - Ok(ty::ConstKind::Unevaluated(a_def_id, &substs)) + Ok(ty::ConstKind::Unevaluated(a_def_id, &substs, a_promoted)) } _ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))), }; diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 5e24c843025bf..62e895af7f355 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -1037,8 +1037,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { match *self { ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)), ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)), - ty::ConstKind::Unevaluated(did, substs) => { - ty::ConstKind::Unevaluated(did, substs.fold_with(folder)) + ty::ConstKind::Unevaluated(did, substs, promoted) => { + ty::ConstKind::Unevaluated(did, substs.fold_with(folder), promoted) } ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(..) => { *self @@ -1050,7 +1050,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { match *self { ty::ConstKind::Infer(ic) => ic.visit_with(visitor), ty::ConstKind::Param(p) => p.visit_with(visitor), - ty::ConstKind::Unevaluated(_, substs) => substs.visit_with(visitor), + ty::ConstKind::Unevaluated(_, substs, _) => substs.visit_with(visitor), ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => { false } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index c89d045cebb73..842361284823d 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -9,6 +9,7 @@ use crate::infer::canonical::Canonical; use crate::middle::region; use crate::mir::interpret::ConstValue; use crate::mir::interpret::Scalar; +use crate::mir::Promoted; use crate::ty::layout::VariantIdx; use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef}; use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable}; @@ -2375,7 +2376,7 @@ impl<'tcx> Const<'tcx> { #[inline] pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> { - let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs| { + let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs, promoted| { let param_env_and_substs = param_env.with_reveal_all().and(substs); // Avoid querying `tcx.const_eval(...)` with any e.g. inference vars. @@ -2387,11 +2388,11 @@ impl<'tcx> Const<'tcx> { // try to resolve e.g. associated constants to their definition on an impl, and then // evaluate the const. - tcx.const_eval_resolve(param_env, did, substs, None).ok() + tcx.const_eval_resolve(param_env, did, substs, promoted, None).ok() }; match self.val { - ConstKind::Unevaluated(did, substs) => { + ConstKind::Unevaluated(did, substs, promoted) => { // HACK(eddyb) when substs contain e.g. inference variables, // attempt using identity substs instead, that will succeed // when the expression doesn't depend on any parameters. @@ -2401,12 +2402,12 @@ impl<'tcx> Const<'tcx> { let identity_substs = InternalSubsts::identity_for_item(tcx, did); // The `ParamEnv` needs to match the `identity_substs`. let identity_param_env = tcx.param_env(did); - match try_const_eval(did, identity_param_env, identity_substs) { + match try_const_eval(did, identity_param_env, identity_substs, promoted) { Some(ct) => ct.subst(tcx, substs), None => self, } } else { - try_const_eval(did, param_env, substs).unwrap_or(self) + try_const_eval(did, param_env, substs, promoted).unwrap_or(self) } } _ => self, @@ -2470,7 +2471,7 @@ pub enum ConstKind<'tcx> { /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other /// variants when the code is monomorphic enough for that. - Unevaluated(DefId, SubstsRef<'tcx>), + Unevaluated(DefId, SubstsRef<'tcx>, Option), /// Used to hold computed value. Value(ConstValue<'tcx>), diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 9e0dd8e067a20..da08fbcf14432 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -81,7 +81,8 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { | ty::Bound(..) | ty::Foreign(..) => {} ty::Array(ty, len) => { - if let ty::ConstKind::Unevaluated(_, substs) = len.val { + if let ty::ConstKind::Unevaluated(_, substs, promoted) = len.val { + assert!(promoted.is_none()); stack.extend(substs.types().rev()); } stack.push(len.ty); diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 8d8e86de4d464..d1f70ad43bd28 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -1286,9 +1286,9 @@ fn generator_layout_and_saved_local_names( let generator_layout = body.generator_layout.as_ref().unwrap(); let mut generator_saved_local_names = IndexVec::from_elem(None, &generator_layout.field_tys); - let state_arg = mir::PlaceBase::Local(mir::Local::new(1)); + let state_arg = mir::Local::new(1); for var in &body.var_debug_info { - if var.place.base != state_arg { + if var.place.local != state_arg { continue; } match var.place.projection[..] { diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index 0ceb44d019b64..c3affd233f8e3 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -14,7 +14,6 @@ use rustc::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_data_structures::graph::dominators::Dominators; use rustc_index::bit_set::BitSet; use rustc_index::vec::{Idx, IndexVec}; -use rustc_span::DUMMY_SP; pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( fx: &FunctionCx<'a, 'tcx, Bx>, @@ -129,17 +128,13 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { }; if is_consume { let base_ty = - mir::Place::ty_from(place_ref.base, proj_base, *self.fx.mir, cx.tcx()); + mir::Place::ty_from(place_ref.local, proj_base, *self.fx.mir, cx.tcx()); let base_ty = self.fx.monomorphize(&base_ty); // ZSTs don't require any actual memory access. let elem_ty = base_ty.projection_ty(cx.tcx(), elem).ty; let elem_ty = self.fx.monomorphize(&elem_ty); - let span = if let mir::PlaceBase::Local(index) = place_ref.base { - self.fx.mir.local_decls[*index].source_info.span - } else { - DUMMY_SP - }; + let span = self.fx.mir.local_decls[*place_ref.local].source_info.span; if cx.spanned_layout_of(elem_ty, span).is_zst() { return; } @@ -179,9 +174,7 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { // We use `NonUseContext::VarDebugInfo` for the base, // which might not force the base local to memory, // so we have to do it manually. - if let mir::PlaceBase::Local(local) = place_ref.base { - self.visit_local(&local, context, location); - } + self.visit_local(place_ref.local, context, location); } } @@ -192,7 +185,7 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { } self.process_place( - &mir::PlaceRef { base: place_ref.base, projection: proj_base }, + &mir::PlaceRef { local: place_ref.local, projection: proj_base }, base_context, location, ); @@ -219,8 +212,8 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { }; } - self.visit_place_base(place_ref.base, context, location); - self.visit_projection(place_ref.base, place_ref.projection, context, location); + self.visit_place_base(place_ref.local, context, location); + self.visit_projection(place_ref.local, place_ref.projection, context, location); } } } diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index a1d4c0c820bc6..9169010da8801 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -10,8 +10,8 @@ use crate::traits::*; use crate::MemFlags; use rustc::middle::lang_items; +use rustc::mir; use rustc::mir::interpret::PanicInfo; -use rustc::mir::{self, PlaceBase, Static, StaticKind}; use rustc::ty::layout::{self, FnAbiExt, HasTyCtxt, LayoutOf}; use rustc::ty::{self, Instance, Ty, TypeFoldable}; use rustc_index::vec::Idx; @@ -609,53 +609,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // checked by const-qualification, which also // promotes any complex rvalues to constants. if i == 2 && intrinsic.unwrap().starts_with("simd_shuffle") { - match arg { - // The shuffle array argument is usually not an explicit constant, - // but specified directly in the code. This means it gets promoted - // and we can then extract the value by evaluating the promoted. - mir::Operand::Copy(place) | mir::Operand::Move(place) => { - if let mir::PlaceRef { - base: - &PlaceBase::Static(box Static { - kind: StaticKind::Promoted(promoted, substs), - ty, - def_id, - }), - projection: &[], - } = place.as_ref() - { - let c = bx.tcx().const_eval_promoted( - Instance::new(def_id, self.monomorphize(&substs)), - promoted, - ); - let (llval, ty) = self.simd_shuffle_indices( - &bx, - terminator.source_info.span, - ty, - c, - ); - return OperandRef { - val: Immediate(llval), - layout: bx.layout_of(ty), - }; - } else { - span_bug!(span, "shuffle indices must be constant"); - } - } - - mir::Operand::Constant(constant) => { - let c = self.eval_mir_constant(constant); - let (llval, ty) = self.simd_shuffle_indices( - &bx, - constant.span, - constant.literal.ty, - c, - ); - return OperandRef { - val: Immediate(llval), - layout: bx.layout_of(ty), - }; - } + if let mir::Operand::Constant(constant) = arg { + let c = self.eval_mir_constant(constant); + let (llval, ty) = self.simd_shuffle_indices( + &bx, + constant.span, + constant.literal.ty, + c, + ); + return OperandRef { val: Immediate(llval), layout: bx.layout_of(ty) }; + } else { + span_bug!(span, "shuffle indices must be constant"); } } @@ -1147,7 +1111,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } else { self.codegen_place( bx, - &mir::PlaceRef { base: &dest.base, projection: &dest.projection }, + &mir::PlaceRef { local: &dest.local, projection: &dest.projection }, ) }; if fn_ret.is_indirect() { diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index f508ed90de42d..3ce916d781279 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -20,7 +20,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // use `get_static` to get at their id. // FIXME(oli-obk): can we unify this somehow, maybe by making const eval of statics // always produce `&STATIC`. This may also simplify how const eval works with statics. - ty::ConstKind::Unevaluated(def_id, substs) if self.cx.tcx().is_static(def_id) => { + ty::ConstKind::Unevaluated(def_id, substs, None) if self.cx.tcx().is_static(def_id) => { assert!(substs.is_empty(), "we don't support generic statics yet"); let static_ = bx.get_static(def_id); // we treat operands referring to statics as if they were `&STATIC` instead @@ -40,16 +40,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { constant: &mir::Constant<'tcx>, ) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> { match constant.literal.val { - ty::ConstKind::Unevaluated(def_id, substs) => { + ty::ConstKind::Unevaluated(def_id, substs, promoted) => { let substs = self.monomorphize(&substs); self.cx .tcx() - .const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, None) + .const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, promoted, None) .map_err(|err| { - self.cx - .tcx() - .sess - .span_err(constant.span, "erroneous constant encountered"); + if promoted.is_none() { + self.cx + .tcx() + .sess + .span_err(constant.span, "erroneous constant encountered"); + } err }) } diff --git a/src/librustc_codegen_ssa/mir/debuginfo.rs b/src/librustc_codegen_ssa/mir/debuginfo.rs index 6c17a01eb9133..e0aec5d6dd512 100644 --- a/src/librustc_codegen_ssa/mir/debuginfo.rs +++ b/src/librustc_codegen_ssa/mir/debuginfo.rs @@ -258,9 +258,7 @@ pub fn per_local_var_debug_info( if tcx.sess.opts.debuginfo == DebugInfo::Full || !tcx.sess.fewer_names() { let mut per_local = IndexVec::from_elem(vec![], &body.local_decls); for var in &body.var_debug_info { - if let mir::PlaceBase::Local(local) = var.place.base { - per_local[local].push(var); - } + per_local[var.place.local].push(var); } Some(per_local) } else { diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs index d530696543720..a155a6e78f7c3 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/src/librustc_codegen_ssa/mir/operand.rs @@ -373,44 +373,40 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> Option> { debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref); - if let mir::PlaceBase::Local(index) = place_ref.base { - match self.locals[*index] { - LocalRef::Operand(Some(mut o)) => { - // Moves out of scalar and scalar pair fields are trivial. - for elem in place_ref.projection.iter() { - match elem { - mir::ProjectionElem::Field(ref f, _) => { - o = o.extract_field(bx, f.index()); - } - mir::ProjectionElem::Index(_) - | mir::ProjectionElem::ConstantIndex { .. } => { - // ZSTs don't require any actual memory access. - // FIXME(eddyb) deduplicate this with the identical - // checks in `codegen_consume` and `extract_field`. - let elem = o.layout.field(bx.cx(), 0); - if elem.is_zst() { - o = OperandRef::new_zst(bx, elem); - } else { - return None; - } + match self.locals[*place_ref.local] { + LocalRef::Operand(Some(mut o)) => { + // Moves out of scalar and scalar pair fields are trivial. + for elem in place_ref.projection.iter() { + match elem { + mir::ProjectionElem::Field(ref f, _) => { + o = o.extract_field(bx, f.index()); + } + mir::ProjectionElem::Index(_) + | mir::ProjectionElem::ConstantIndex { .. } => { + // ZSTs don't require any actual memory access. + // FIXME(eddyb) deduplicate this with the identical + // checks in `codegen_consume` and `extract_field`. + let elem = o.layout.field(bx.cx(), 0); + if elem.is_zst() { + o = OperandRef::new_zst(bx, elem); + } else { + return None; } - _ => return None, } + _ => return None, } - - Some(o) - } - LocalRef::Operand(None) => { - bug!("use of {:?} before def", place_ref); - } - LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => { - // watch out for locals that do not have an - // alloca; they are handled somewhat differently - None } + + Some(o) + } + LocalRef::Operand(None) => { + bug!("use of {:?} before def", place_ref); + } + LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => { + // watch out for locals that do not have an + // alloca; they are handled somewhat differently + None } - } else { - None } } diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index 7399db1f2b950..5e03a35b8a6fd 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -9,7 +9,7 @@ use crate::MemFlags; use rustc::mir; use rustc::mir::tcx::PlaceTy; use rustc::ty::layout::{self, Align, HasTyCtxt, LayoutOf, TyLayout, VariantIdx}; -use rustc::ty::{self, Instance, Ty}; +use rustc::ty::{self, Ty}; #[derive(Copy, Clone, Debug)] pub struct PlaceRef<'tcx, V> { @@ -37,15 +37,6 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { PlaceRef { llval, llextra: None, layout, align } } - fn new_thin_place>( - bx: &mut Bx, - llval: V, - layout: TyLayout<'tcx>, - ) -> PlaceRef<'tcx, V> { - assert!(!bx.cx().type_has_metadata(layout.ty)); - PlaceRef { llval, llextra: None, layout, align: layout.align.abi } - } - // FIXME(eddyb) pass something else for the name so no work is done // unless LLVM IR names are turned on (e.g. for `--emit=llvm-ir`). pub fn alloca>( @@ -424,76 +415,26 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let tcx = self.cx.tcx(); let result = match place_ref { - mir::PlaceRef { base: mir::PlaceBase::Local(index), projection: [] } => { - match self.locals[*index] { - LocalRef::Place(place) => { - return place; - } - LocalRef::UnsizedPlace(place) => { - return bx.load_operand(place).deref(cx); - } - LocalRef::Operand(..) => { - bug!("using operand local {:?} as place", place_ref); - } + mir::PlaceRef { local, projection: [] } => match self.locals[**local] { + LocalRef::Place(place) => { + return place; } - } - mir::PlaceRef { - base: - mir::PlaceBase::Static(box mir::Static { - ty, - kind: mir::StaticKind::Promoted(promoted, substs), - def_id, - }), - projection: [], - } => { - let instance = Instance::new(*def_id, self.monomorphize(substs)); - let layout = cx.layout_of(self.monomorphize(&ty)); - match bx.tcx().const_eval_promoted(instance, *promoted) { - Ok(val) => match val.val { - ty::ConstKind::Value(mir::interpret::ConstValue::ByRef { - alloc, - offset, - }) => bx.cx().from_const_alloc(layout, alloc, offset), - _ => bug!("promoteds should have an allocation: {:?}", val), - }, - Err(_) => { - // This is unreachable as long as runtime - // and compile-time agree perfectly. - // With floats that won't always be true, - // so we generate a (safe) abort. - bx.abort(); - // We still have to return a place but it doesn't matter, - // this code is unreachable. - let llval = - bx.cx().const_undef(bx.cx().type_ptr_to(bx.cx().backend_type(layout))); - PlaceRef::new_sized(llval, layout) - } + LocalRef::UnsizedPlace(place) => { + return bx.load_operand(place).deref(cx); } - } - mir::PlaceRef { - base: - mir::PlaceBase::Static(box mir::Static { - ty, - kind: mir::StaticKind::Static, - def_id, - }), - projection: [], - } => { - // NB: The layout of a static may be unsized as is the case when working - // with a static that is an extern_type. - let layout = cx.layout_of(self.monomorphize(&ty)); - let static_ = bx.get_static(*def_id); - PlaceRef::new_thin_place(bx, static_, layout) - } - mir::PlaceRef { base, projection: [proj_base @ .., mir::ProjectionElem::Deref] } => { + LocalRef::Operand(..) => { + bug!("using operand local {:?} as place", place_ref); + } + }, + mir::PlaceRef { local, projection: [proj_base @ .., mir::ProjectionElem::Deref] } => { // Load the pointer from its location. - self.codegen_consume(bx, &mir::PlaceRef { base, projection: proj_base }) + self.codegen_consume(bx, &mir::PlaceRef { local, projection: proj_base }) .deref(bx.cx()) } - mir::PlaceRef { base, projection: [proj_base @ .., elem] } => { + mir::PlaceRef { local, projection: [proj_base @ .., elem] } => { // FIXME turn this recursion into iteration let cg_base = - self.codegen_place(bx, &mir::PlaceRef { base, projection: proj_base }); + self.codegen_place(bx, &mir::PlaceRef { local, projection: proj_base }); match elem { mir::ProjectionElem::Deref => bug!(), @@ -558,7 +499,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn monomorphized_place_ty(&self, place_ref: &mir::PlaceRef<'_, 'tcx>) -> Ty<'tcx> { let tcx = self.cx.tcx(); - let place_ty = mir::Place::ty_from(place_ref.base, place_ref.projection, *self.mir, tcx); + let place_ty = mir::Place::ty_from(place_ref.local, place_ref.projection, *self.mir, tcx); self.monomorphize(&place_ty.ty) } } diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index b66b2e4b1f7f5..f2a44986cc4d4 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -208,9 +208,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> { self.insert_as_pending_if_two_phase(location, &assigned_place, kind, idx); - if let mir::PlaceBase::Local(local) = borrowed_place.base { - self.local_map.entry(local).or_default().insert(idx); - } + self.local_map.entry(borrowed_place.local).or_default().insert(idx); } self.super_assign(assigned_place, rvalue, location) diff --git a/src/librustc_mir/borrow_check/constraint_generation.rs b/src/librustc_mir/borrow_check/constraint_generation.rs index 97de201faba01..0f6a360c7933b 100644 --- a/src/librustc_mir/borrow_check/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/constraint_generation.rs @@ -2,8 +2,8 @@ use rustc::infer::InferCtxt; use rustc::mir::visit::TyContext; use rustc::mir::visit::Visitor; use rustc::mir::{ - BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, PlaceRef, ProjectionElem, - Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection, + BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue, + SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection, }; use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::SubstsRef; @@ -16,7 +16,6 @@ use crate::borrow_check::{ pub(super) fn generate_constraints<'cx, 'tcx>( infcx: &InferCtxt<'cx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, liveness_constraints: &mut LivenessValues, all_facts: &mut Option, location_table: &LocationTable, @@ -30,7 +29,6 @@ pub(super) fn generate_constraints<'cx, 'tcx>( location_table, all_facts, body, - param_env, }; for (bb, data) in body.basic_blocks().iter_enumerated() { @@ -41,7 +39,6 @@ pub(super) fn generate_constraints<'cx, 'tcx>( /// 'cg = the duration of the constraint generation process itself. struct ConstraintGeneration<'cg, 'cx, 'tcx> { infcx: &'cg InferCtxt<'cx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, all_facts: &'cg mut Option, location_table: &'cg LocationTable, liveness_constraints: &'cg mut LivenessValues, @@ -191,11 +188,8 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> { // of the borrows are killed: the ones whose `borrowed_place` // conflicts with the `place`. match place.as_ref() { - PlaceRef { base: &PlaceBase::Local(local), projection: &[] } - | PlaceRef { - base: &PlaceBase::Local(local), - projection: &[ProjectionElem::Deref], - } => { + PlaceRef { local, projection: &[] } + | PlaceRef { local, projection: &[ProjectionElem::Deref] } => { debug!( "Recording `killed` facts for borrows of local={:?} at location={:?}", local, location @@ -205,16 +199,12 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> { all_facts, self.borrow_set, self.location_table, - &local, + local, location, ); } - PlaceRef { base: &PlaceBase::Static(_), .. } => { - // Ignore kills of static or static mut variables. - } - - PlaceRef { base: &PlaceBase::Local(local), projection: &[.., _] } => { + PlaceRef { local, projection: &[.., _] } => { // Kill conflicting borrows of the innermost local. debug!( "Recording `killed` facts for borrows of \ @@ -222,11 +212,10 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> { local, location ); - if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) { + if let Some(borrow_indices) = self.borrow_set.local_map.get(local) { for &borrow_index in borrow_indices { let places_conflict = places_conflict::places_conflict( self.infcx.tcx, - self.param_env, self.body, &self.borrow_set.borrows[borrow_index].borrowed_place, place, diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs index 7e251560a6c51..08333ae423da7 100644 --- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs @@ -1,7 +1,7 @@ use rustc::mir::{ self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, - FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceBase, - PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm, + FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, + ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm, }; use rustc::traits::error_reporting::suggest_constraining_type_param; use rustc::ty::{self, Ty}; @@ -186,7 +186,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } let ty = - Place::ty_from(used_place.base, used_place.projection, *self.body, self.infcx.tcx) + Place::ty_from(used_place.local, used_place.projection, *self.body, self.infcx.tcx) .ty; let needs_note = match ty.kind { ty::Closure(id, _) => { @@ -597,15 +597,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // field access to a union. If we find that, then we will keep the place of the // union being accessed and the field that was being accessed so we can check the // second borrowed place for the same union and a access to a different field. - let Place { base, projection } = first_borrowed_place; + let Place { local, projection } = first_borrowed_place; let mut cursor = projection.as_ref(); while let [proj_base @ .., elem] = cursor { cursor = proj_base; match elem { - ProjectionElem::Field(field, _) if union_ty(base, proj_base).is_some() => { - return Some((PlaceRef { base: base, projection: proj_base }, field)); + ProjectionElem::Field(field, _) if union_ty(local, proj_base).is_some() => { + return Some((PlaceRef { local, projection: proj_base }, field)); } _ => {} } @@ -615,21 +615,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .and_then(|(target_base, target_field)| { // With the place of a union and a field access into it, we traverse the second // borrowed place and look for a access to a different field of the same union. - let Place { base, projection } = second_borrowed_place; + let Place { local, projection } = second_borrowed_place; let mut cursor = projection.as_ref(); while let [proj_base @ .., elem] = cursor { cursor = proj_base; if let ProjectionElem::Field(field, _) = elem { - if let Some(union_ty) = union_ty(base, proj_base) { + if let Some(union_ty) = union_ty(local, proj_base) { if field != target_field - && base == target_base.base + && local == target_base.local && proj_base == target_base.projection { // FIXME when we avoid clone reuse describe_place closure let describe_base_place = self - .describe_place(PlaceRef { base: base, projection: proj_base }) + .describe_place(PlaceRef { local, projection: proj_base }) .unwrap_or_else(|| "_".to_owned()); return Some(( @@ -686,15 +686,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let borrow_span = borrow_spans.var_or_use(); assert!(root_place.projection.is_empty()); - let proper_span = match root_place.base { - PlaceBase::Local(local) => self.body.local_decls[*local].source_info.span, - _ => drop_span, - }; + let proper_span = self.body.local_decls[*root_place.local].source_info.span; let root_place_projection = self.infcx.tcx.intern_place_elems(root_place.projection); if self.access_place_error_reported.contains(&( - Place { base: root_place.base.clone(), projection: root_place_projection }, + Place { local: root_place.local.clone(), projection: root_place_projection }, borrow_span, )) { debug!( @@ -705,18 +702,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } self.access_place_error_reported.insert(( - Place { base: root_place.base.clone(), projection: root_place_projection }, + Place { local: root_place.local.clone(), projection: root_place_projection }, borrow_span, )); - if let PlaceBase::Local(local) = borrow.borrowed_place.base { - if self.body.local_decls[local].is_ref_to_thread_local() { - let err = self - .report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span); - err.buffer(&mut self.errors_buffer); - return; - } - }; + let borrowed_local = borrow.borrowed_place.local; + if self.body.local_decls[borrowed_local].is_ref_to_thread_local() { + let err = + self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span); + err.buffer(&mut self.errors_buffer); + return; + } if let StorageDeadOrDrop::Destructor(dropped_ty) = self.classify_drop_access_kind(borrow.borrowed_place.as_ref()) @@ -1142,12 +1138,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } else { let root_place = self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap(); - let local = - if let PlaceRef { base: PlaceBase::Local(local), projection: [] } = root_place { - local - } else { - bug!("try_report_cannot_return_reference_to_local: not a local") - }; + let local = root_place.local; match self.body.local_kind(*local) { LocalKind::ReturnPointer | LocalKind::Temp => { ("temporary value".to_string(), "temporary value created here".to_string()) @@ -1514,7 +1505,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { [proj_base @ .., elem] => { // FIXME(spastorino) make this iterate let base_access = self.classify_drop_access_kind(PlaceRef { - base: place.base, + local: place.local, projection: proj_base, }); match elem { @@ -1522,7 +1513,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { StorageDeadOrDrop::LocalStorageDead | StorageDeadOrDrop::BoxedStorageDead => { assert!( - Place::ty_from(&place.base, proj_base, *self.body, tcx).ty.is_box(), + Place::ty_from(&place.local, proj_base, *self.body, tcx) + .ty + .is_box(), "Drop of value behind a reference or raw pointer" ); StorageDeadOrDrop::BoxedStorageDead @@ -1530,7 +1523,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { StorageDeadOrDrop::Destructor(_) => base_access, }, ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { - let base_ty = Place::ty_from(&place.base, proj_base, *self.body, tcx).ty; + let base_ty = Place::ty_from(&place.local, proj_base, *self.body, tcx).ty; match base_ty.kind { ty::Adt(def, _) if def.has_dtor(tcx) => { // Report the outermost adt with a destructor diff --git a/src/librustc_mir/borrow_check/diagnostics/mod.rs b/src/librustc_mir/borrow_check/diagnostics/mod.rs index c8a59331f31af..3f3bdb9d36c76 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mod.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mod.rs @@ -2,8 +2,7 @@ use rustc::mir::{ AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand, Place, - PlaceBase, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Static, StaticKind, - Terminator, TerminatorKind, + PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; use rustc::ty::layout::VariantIdx; use rustc::ty::print::Print; @@ -169,42 +168,30 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { including_downcast: &IncludingDowncast, ) -> Result<(), ()> { match place { - PlaceRef { base: PlaceBase::Local(local), projection: [] } => { + PlaceRef { local, projection: [] } => { self.append_local_to_string(*local, buf)?; } - PlaceRef { - base: PlaceBase::Static(box Static { kind: StaticKind::Promoted(..), .. }), - projection: [], - } => { - buf.push_str("promoted"); - } - PlaceRef { - base: PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }), - projection: [], - } => { - buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string()); - } - PlaceRef { base: &PlaceBase::Local(local), projection: [ProjectionElem::Deref] } - if self.body.local_decls[local].is_ref_for_guard() => + PlaceRef { local, projection: [ProjectionElem::Deref] } + if self.body.local_decls[*local].is_ref_for_guard() => { self.append_place_to_string( - PlaceRef { base: &PlaceBase::Local(local), projection: &[] }, + PlaceRef { local: local, projection: &[] }, buf, autoderef, &including_downcast, )?; } - PlaceRef { base: &PlaceBase::Local(local), projection: [ProjectionElem::Deref] } - if self.body.local_decls[local].is_ref_to_static() => + PlaceRef { local, projection: [ProjectionElem::Deref] } + if self.body.local_decls[*local].is_ref_to_static() => { - let local_info = &self.body.local_decls[local].local_info; + let local_info = &self.body.local_decls[*local].local_info; if let LocalInfo::StaticRef { def_id, .. } = *local_info { buf.push_str(&self.infcx.tcx.item_name(def_id).as_str()); } else { unreachable!(); } } - PlaceRef { base, projection: [proj_base @ .., elem] } => { + PlaceRef { local, projection: [proj_base @ .., elem] } => { match elem { ProjectionElem::Deref => { let upvar_field_projection = self.is_upvar_field_projection(place); @@ -220,29 +207,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if autoderef { // FIXME turn this recursion into iteration self.append_place_to_string( - PlaceRef { base, projection: proj_base }, + PlaceRef { local, projection: proj_base }, buf, autoderef, &including_downcast, )?; } else { - match (proj_base, base) { - _ => { - buf.push_str(&"*"); - self.append_place_to_string( - PlaceRef { base, projection: proj_base }, - buf, - autoderef, - &including_downcast, - )?; - } - } + buf.push_str(&"*"); + self.append_place_to_string( + PlaceRef { local, projection: proj_base }, + buf, + autoderef, + &including_downcast, + )?; } } } ProjectionElem::Downcast(..) => { self.append_place_to_string( - PlaceRef { base, projection: proj_base }, + PlaceRef { local, projection: proj_base }, buf, autoderef, &including_downcast, @@ -261,9 +244,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { buf.push_str(&name); } else { let field_name = self - .describe_field(PlaceRef { base, projection: proj_base }, *field); + .describe_field(PlaceRef { local, projection: proj_base }, *field); self.append_place_to_string( - PlaceRef { base, projection: proj_base }, + PlaceRef { local, projection: proj_base }, buf, autoderef, &including_downcast, @@ -275,7 +258,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { autoderef = true; self.append_place_to_string( - PlaceRef { base, projection: proj_base }, + PlaceRef { local, projection: proj_base }, buf, autoderef, &including_downcast, @@ -292,7 +275,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // then use another while the borrow is held, don't output indices details // to avoid confusing the end-user self.append_place_to_string( - PlaceRef { base, projection: proj_base }, + PlaceRef { local, projection: proj_base }, buf, autoderef, &including_downcast, @@ -323,20 +306,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn describe_field(&self, place: PlaceRef<'cx, 'tcx>, field: Field) -> String { // FIXME Place2 Make this work iteratively match place { - PlaceRef { base: PlaceBase::Local(local), projection: [] } => { + PlaceRef { local, projection: [] } => { let local = &self.body.local_decls[*local]; self.describe_field_from_ty(&local.ty, field, None) } - PlaceRef { base: PlaceBase::Static(static_), projection: [] } => { - self.describe_field_from_ty(&static_.ty, field, None) - } - PlaceRef { base, projection: [proj_base @ .., elem] } => match elem { + PlaceRef { local, projection: [proj_base @ .., elem] } => match elem { ProjectionElem::Deref => { - self.describe_field(PlaceRef { base, projection: proj_base }, field) + self.describe_field(PlaceRef { local, projection: proj_base }, field) } ProjectionElem::Downcast(_, variant_index) => { let base_ty = - Place::ty_from(place.base, place.projection, *self.body, self.infcx.tcx).ty; + Place::ty_from(place.local, place.projection, *self.body, self.infcx.tcx) + .ty; self.describe_field_from_ty(&base_ty, field, Some(*variant_index)) } ProjectionElem::Field(_, field_type) => { @@ -345,7 +326,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { - self.describe_field(PlaceRef { base, projection: proj_base }, field) + self.describe_field(PlaceRef { local, projection: proj_base }, field) } }, } @@ -466,7 +447,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // If we didn't find an overloaded deref or index, then assume it's a // built in deref and check the type of the base. - let base_ty = Place::ty_from(deref_base.base, deref_base.projection, *self.body, tcx).ty; + let base_ty = Place::ty_from(deref_base.local, deref_base.projection, *self.body, tcx).ty; if base_ty.is_unsafe_ptr() { BorrowedContentSource::DerefRawPointer } else if base_ty.is_mutable_ptr() { diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs index 3f4204bc12f6a..eb6db7c145c3c 100644 --- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs @@ -243,9 +243,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ); ( match kind { - IllegalMoveOriginKind::Static => { - unreachable!(); - } IllegalMoveOriginKind::BorrowedContent { target_place } => self .report_cannot_move_from_borrowed_content( original_path, @@ -276,7 +273,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let description = if place.projection.len() == 1 { format!("static item `{}`", self.describe_place(place.as_ref()).unwrap()) } else { - let base_static = PlaceRef { base: &place.base, projection: &[ProjectionElem::Deref] }; + let base_static = + PlaceRef { local: &place.local, projection: &[ProjectionElem::Deref] }; format!( "`{:?}` as `{:?}` is a static item", @@ -305,12 +303,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let deref_base = match deref_target_place.projection.as_ref() { &[ref proj_base @ .., ProjectionElem::Deref] => { - PlaceRef { base: &deref_target_place.base, projection: &proj_base } + PlaceRef { local: &deref_target_place.local, projection: &proj_base } } _ => bug!("deref_target_place is not a deref projection"), }; - if let PlaceRef { base: PlaceBase::Local(local), projection: [] } = deref_base { + if let PlaceRef { local, projection: [] } = deref_base { let decl = &self.body.local_decls[*local]; if decl.is_ref_for_guard() { let mut err = self.cannot_move_out_of( diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs index 595acec2f74d7..ae468e83ae253 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs @@ -1,5 +1,5 @@ use rustc::mir::{self, ClearCrossCrate, Local, LocalInfo, Location, ReadOnlyBodyAndCache}; -use rustc::mir::{Mutability, Place, PlaceBase, PlaceRef, ProjectionElem}; +use rustc::mir::{Mutability, Place, PlaceRef, ProjectionElem}; use rustc::ty::{self, Ty, TyCtxt}; use rustc_hir as hir; use rustc_hir::Node; @@ -42,7 +42,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { debug!("report_mutability_error: access_place_desc={:?}", access_place_desc); match the_place_err { - PlaceRef { base: PlaceBase::Local(local), projection: [] } => { + PlaceRef { local, projection: [] } => { item_msg = format!("`{}`", access_place_desc.unwrap()); if access_place.as_local().is_some() { reason = ", as it is not declared as mutable".to_string(); @@ -53,11 +53,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } PlaceRef { - base: _, + local, projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)], } => { debug_assert!(is_closure_or_generator( - Place::ty_from(&the_place_err.base, proj_base, *self.body, self.infcx.tcx).ty + Place::ty_from(local, proj_base, *self.body, self.infcx.tcx).ty )); item_msg = format!("`{}`", access_place_desc.unwrap()); @@ -69,21 +69,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - PlaceRef { base: &PlaceBase::Local(local), projection: [ProjectionElem::Deref] } - if self.body.local_decls[local].is_ref_for_guard() => + PlaceRef { local, projection: [ProjectionElem::Deref] } + if self.body.local_decls[*local].is_ref_for_guard() => { item_msg = format!("`{}`", access_place_desc.unwrap()); reason = ", as it is immutable for the pattern guard".to_string(); } - PlaceRef { base: &PlaceBase::Local(local), projection: [ProjectionElem::Deref] } - if self.body.local_decls[local].is_ref_to_static() => + PlaceRef { local, projection: [ProjectionElem::Deref] } + if self.body.local_decls[*local].is_ref_to_static() => { if access_place.projection.len() == 1 { item_msg = format!("immutable static item `{}`", access_place_desc.unwrap()); reason = String::new(); } else { item_msg = format!("`{}`", access_place_desc.unwrap()); - let local_info = &self.body.local_decls[local].local_info; + let local_info = &self.body.local_decls[*local].local_info; if let LocalInfo::StaticRef { def_id, .. } = *local_info { let static_name = &self.infcx.tcx.item_name(def_id); reason = format!(", as `{}` is an immutable static item", static_name); @@ -92,8 +92,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } } - PlaceRef { base: _, projection: [proj_base @ .., ProjectionElem::Deref] } => { - if the_place_err.base == &PlaceBase::Local(Local::new(1)) + PlaceRef { local: _, projection: [proj_base @ .., ProjectionElem::Deref] } => { + if *the_place_err.local == Local::new(1) && proj_base.is_empty() && !self.upvars.is_empty() { @@ -101,7 +101,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr()); debug_assert!(is_closure_or_generator( Place::ty_from( - the_place_err.base, + the_place_err.local, the_place_err.projection, *self.body, self.infcx.tcx @@ -116,7 +116,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } else { let source = self.borrowed_content_source(PlaceRef { - base: the_place_err.base, + local: the_place_err.local, projection: proj_base, }); let pointer_type = source.describe_for_immutable_place(); @@ -136,11 +136,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - PlaceRef { base: PlaceBase::Static(_), .. } - | PlaceRef { base: _, projection: [.., ProjectionElem::Index(_)] } - | PlaceRef { base: _, projection: [.., ProjectionElem::ConstantIndex { .. }] } - | PlaceRef { base: _, projection: [.., ProjectionElem::Subslice { .. }] } - | PlaceRef { base: _, projection: [.., ProjectionElem::Downcast(..)] } => { + PlaceRef { local: _, projection: [.., ProjectionElem::Index(_)] } + | PlaceRef { local: _, projection: [.., ProjectionElem::ConstantIndex { .. }] } + | PlaceRef { local: _, projection: [.., ProjectionElem::Subslice { .. }] } + | PlaceRef { local: _, projection: [.., ProjectionElem::Downcast(..)] } => { bug!("Unexpected immutable place.") } } @@ -188,7 +187,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // struct we've got a field access of (it must be a reference since there's a deref // after the field access). PlaceRef { - base, + local, projection: [proj_base @ .., ProjectionElem::Deref, ProjectionElem::Field(field, _), ProjectionElem::Deref], } => { @@ -196,7 +195,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let Some((span, message)) = annotate_struct_field( self.infcx.tcx, - Place::ty_from(base, proj_base, *self.body, self.infcx.tcx).ty, + Place::ty_from(local, proj_base, *self.body, self.infcx.tcx).ty, field, ) { err.span_suggestion( @@ -209,7 +208,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } // Suggest removing a `&mut` from the use of a mutable reference. - PlaceRef { base: PlaceBase::Local(local), projection: [] } + PlaceRef { local, projection: [] } if { self.body .local_decls @@ -247,7 +246,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // We want to suggest users use `let mut` for local (user // variable) mutations... - PlaceRef { base: PlaceBase::Local(local), projection: [] } + PlaceRef { local, projection: [] } if self.body.local_decls[*local].can_be_made_mutable() => { // ... but it doesn't make sense to suggest it on @@ -268,11 +267,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // Also suggest adding mut for upvars PlaceRef { - base, + local, projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)], } => { debug_assert!(is_closure_or_generator( - Place::ty_from(base, proj_base, *self.body, self.infcx.tcx).ty + Place::ty_from(local, proj_base, *self.body, self.infcx.tcx).ty )); err.span_label(span, format!("cannot {ACT}", ACT = act)); @@ -299,7 +298,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // complete hack to approximate old AST-borrowck // diagnostic: if the span starts with a mutable borrow of // a local variable, then just suggest the user remove it. - PlaceRef { base: PlaceBase::Local(_), projection: [] } + PlaceRef { local: _, projection: [] } if { if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { snippet.starts_with("&mut ") @@ -312,7 +311,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err.span_label(span, "try removing `&mut` here"); } - PlaceRef { base: PlaceBase::Local(local), projection: [ProjectionElem::Deref] } + PlaceRef { local, projection: [ProjectionElem::Deref] } if self.body.local_decls[*local].is_ref_for_guard() => { err.span_label(span, format!("cannot {ACT}", ACT = act)); @@ -326,7 +325,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // // FIXME: can this case be generalized to work for an // arbitrary base for the projection? - PlaceRef { base: PlaceBase::Local(local), projection: [ProjectionElem::Deref] } + PlaceRef { local, projection: [ProjectionElem::Deref] } if self.body.local_decls[*local].is_user_variable() => { let local_decl = &self.body.local_decls[*local]; @@ -409,10 +408,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } PlaceRef { - base, + local, projection: [ProjectionElem::Deref], // FIXME document what is this 1 magic number about - } if *base == PlaceBase::Local(Local::new(1)) && !self.upvars.is_empty() => { + } if *local == Local::new(1) && !self.upvars.is_empty() => { err.span_label(span, format!("cannot {ACT}", ACT = act)); err.span_help( self.body.span, @@ -420,7 +419,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ); } - PlaceRef { base: _, projection: [.., ProjectionElem::Deref] } => { + PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => { err.span_label(span, format!("cannot {ACT}", ACT = act)); match opt_source { diff --git a/src/librustc_mir/borrow_check/invalidation.rs b/src/librustc_mir/borrow_check/invalidation.rs index f9ffa2138ba40..bb56c11872a29 100644 --- a/src/librustc_mir/borrow_check/invalidation.rs +++ b/src/librustc_mir/borrow_check/invalidation.rs @@ -3,7 +3,7 @@ use rustc::mir::TerminatorKind; use rustc::mir::{BasicBlock, Body, Location, Place, ReadOnlyBodyAndCache, Rvalue}; use rustc::mir::{BorrowKind, Mutability, Operand}; use rustc::mir::{Statement, StatementKind}; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::TyCtxt; use rustc_data_structures::graph::dominators::Dominators; use crate::dataflow::indexes::BorrowIndex; @@ -16,7 +16,6 @@ use crate::borrow_check::{ pub(super) fn generate_invalidates<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, all_facts: &mut Option, location_table: &LocationTable, body: ReadOnlyBodyAndCache<'_, 'tcx>, @@ -33,7 +32,6 @@ pub(super) fn generate_invalidates<'tcx>( let mut ig = InvalidationGenerator { all_facts, borrow_set, - param_env, tcx, location_table, body: &body, @@ -45,7 +43,6 @@ pub(super) fn generate_invalidates<'tcx>( struct InvalidationGenerator<'cx, 'tcx> { tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, all_facts: &'cx mut AllFacts, location_table: &'cx LocationTable, body: &'cx Body<'tcx>, @@ -337,13 +334,11 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { ); let tcx = self.tcx; let body = self.body; - let param_env = self.param_env; let borrow_set = self.borrow_set.clone(); let indices = self.borrow_set.borrows.indices(); each_borrow_involving_path( self, tcx, - param_env, body, location, (sd, place), diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index fff6f036da082..7b0a103fd0038 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -5,7 +5,7 @@ use rustc::lint::builtin::MUTABLE_BORROW_RESERVATION_CONFLICT; use rustc::lint::builtin::UNUSED_MUT; use rustc::mir::{ read_only, Body, BodyAndCache, ClearCrossCrate, Local, Location, Mutability, Operand, Place, - PlaceBase, PlaceElem, PlaceRef, ReadOnlyBodyAndCache, Static, StaticKind, + PlaceElem, PlaceRef, ReadOnlyBodyAndCache, }; use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; use rustc::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; @@ -239,7 +239,7 @@ fn do_mir_borrowck<'a, 'tcx>( def_id, &attributes, &dead_unwinds, - Borrows::new(tcx, &body, param_env, regioncx.clone(), &borrow_set), + Borrows::new(tcx, &body, regioncx.clone(), &borrow_set), |rs, i| DebugFormatted::new(&rs.location(i)), )); let flow_uninits = FlowAtLocation::new(do_dataflow( @@ -275,7 +275,6 @@ fn do_mir_borrowck<'a, 'tcx>( infcx, body, mir_def_id: def_id, - param_env, move_data: &mdpe.move_data, location_table, movable_generator, @@ -418,7 +417,6 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> { crate infcx: &'cx InferCtxt<'cx, 'tcx>, body: ReadOnlyBodyAndCache<'cx, 'tcx>, mir_def_id: DefId, - param_env: ty::ParamEnv<'tcx>, move_data: &'cx MoveData<'tcx>, /// Map from MIR `Location` to `LocationIndex`; created @@ -817,7 +815,7 @@ enum InitializationRequiringAction { } struct RootPlace<'d, 'tcx> { - place_base: &'d PlaceBase<'tcx>, + place_local: &'d Local, place_projection: &'d [PlaceElem<'tcx>], is_local_mutation_allowed: LocalMutationIsAllowed, } @@ -926,13 +924,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let tcx = self.infcx.tcx; let body = self.body; let body: &Body<'_> = &body; - let param_env = self.param_env; let location_table = self.location_table.start_index(location); let borrow_set = self.borrow_set.clone(); each_borrow_involving_path( self, tcx, - param_env, body, location, (sd, place_span.0), @@ -1255,8 +1251,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let Some(field) = this.is_upvar_field_projection(place.as_ref()) { this.used_mut_upvars.push(field); } - } else if let PlaceBase::Local(local) = place.base { - this.used_mut.insert(local); + } else { + this.used_mut.insert(place.local); } }; @@ -1380,7 +1376,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("check_for_invalidation_at_exit({:?})", borrow); let place = &borrow.borrowed_place; let deref = [ProjectionElem::Deref]; - let mut root_place = PlaceRef { base: &place.base, projection: &[] }; + let mut root_place = PlaceRef { local: &place.local, projection: &[] }; // FIXME(nll-rfc#40): do more precise destructor tracking here. For now // we just know that all locals are dropped at function exit (otherwise @@ -1388,20 +1384,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // // FIXME: allow thread-locals to borrow other thread locals? - let (might_be_alive, will_be_dropped) = match root_place.base { - PlaceBase::Static(_) => (true, false), - PlaceBase::Local(local) => { - if self.body.local_decls[*local].is_ref_to_thread_local() { - // Thread-locals might be dropped after the function exits - // We have to dereference the outer reference because - // borrows don't conflict behind shared references. - root_place.projection = &deref; - (true, true) - } else { - (false, self.locals_are_invalidated_at_exit) - } - } - }; + let (might_be_alive, will_be_dropped) = + if self.body.local_decls[*root_place.local].is_ref_to_thread_local() { + // Thread-locals might be dropped after the function exits + // We have to dereference the outer reference because + // borrows don't conflict behind shared references. + root_place.projection = &deref; + (true, true) + } else { + (false, self.locals_are_invalidated_at_exit) + }; if !will_be_dropped { debug!("place_is_invalidated_at_exit({:?}) - won't be dropped", place); @@ -1412,7 +1404,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if places_conflict::borrow_conflicts_with_place( self.infcx.tcx, - self.param_env, &self.body, place, borrow.kind, @@ -1654,26 +1645,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // This code covers scenarios 1, 2, and 3. debug!("check_if_full_path_is_moved place: {:?}", place_span.0); - match self.move_path_closest_to(place_span.0) { - Ok((prefix, mpi)) => { - if maybe_uninits.contains(mpi) { - self.report_use_of_moved_or_uninitialized( - location, - desired_action, - (prefix, place_span.0, place_span.1), - mpi, - ); - } - } - Err(NoMovePathFound::ReachedStatic) => { - // Okay: we do not build MoveData for static variables - } // Only query longest prefix with a MovePath, not further - // ancestors; dataflow recurs on children when parents - // move (to support partial (re)inits). - // - // (I.e., querying parents breaks scenario 7; but may want - // to do such a query based on partial-init feature-gate.) - } + let (prefix, mpi) = self.move_path_closest_to(place_span.0); + if maybe_uninits.contains(mpi) { + self.report_use_of_moved_or_uninitialized( + location, + desired_action, + (prefix, place_span.0, place_span.1), + mpi, + ); + } // Only query longest prefix with a MovePath, not further + // ancestors; dataflow recurs on children when parents + // move (to support partial (re)inits). + // + // (I.e., querying parents breaks scenario 7; but may want + // to do such a query based on partial-init feature-gate.) } /// Subslices correspond to multiple move paths, so we iterate through the @@ -1746,9 +1731,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { place_span.0.projection { let place_ty = - Place::ty_from(place_span.0.base, base_proj, self.body(), self.infcx.tcx); + Place::ty_from(place_span.0.local, base_proj, self.body(), self.infcx.tcx); if let ty::Array(..) = place_ty.ty.kind { - let array_place = PlaceRef { base: place_span.0.base, projection: base_proj }; + let array_place = PlaceRef { local: place_span.0.local, projection: base_proj }; self.check_if_subslice_element_is_moved( location, desired_action, @@ -1797,12 +1782,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn move_path_closest_to( &mut self, place: PlaceRef<'_, 'tcx>, - ) -> Result<(PlaceRef<'cx, 'tcx>, MovePathIndex), NoMovePathFound> { + ) -> (PlaceRef<'cx, 'tcx>, MovePathIndex) { match self.move_data.rev_lookup.find(place) { LookupResult::Parent(Some(mpi)) | LookupResult::Exact(mpi) => { - Ok((self.move_data.move_paths[mpi].place.as_ref(), mpi)) + (self.move_data.move_paths[mpi].place.as_ref(), mpi) } - LookupResult::Parent(None) => Err(NoMovePathFound::ReachedStatic), + LookupResult::Parent(None) => panic!("should have move path for every Local"), } } @@ -1845,7 +1830,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.check_if_full_path_is_moved( location, InitializationRequiringAction::Use, (PlaceRef { - base: &place.base, + local: &place.local, projection: proj_base, }, span), flow_state); // (base initialized; no need to @@ -1863,13 +1848,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // assigning to `P.f` requires `P` itself // be already initialized let tcx = self.infcx.tcx; - let base_ty = Place::ty_from(&place.base, proj_base, self.body(), tcx).ty; + let base_ty = Place::ty_from(&place.local, proj_base, self.body(), tcx).ty; match base_ty.kind { ty::Adt(def, _) if def.has_dtor(tcx) => { self.check_if_path_or_subpath_is_moved( location, InitializationRequiringAction::Assignment, (PlaceRef { - base: &place.base, + local: &place.local, projection: proj_base, }, span), flow_state); @@ -1882,21 +1867,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // is allowed, remove this match arm. ty::Adt(..) | ty::Tuple(..) => { check_parent_of_field(self, location, PlaceRef { - base: &place.base, + local: &place.local, projection: proj_base, }, span, flow_state); - if let PlaceBase::Local(local) = place.base { - // rust-lang/rust#21232, - // #54499, #54986: during - // period where we reject - // partial initialization, do - // not complain about - // unnecessary `mut` on an - // attempt to do a partial - // initialization. - self.used_mut.insert(local); - } + // rust-lang/rust#21232, #54499, #54986: during period where we reject + // partial initialization, do not complain about unnecessary `mut` on + // an attempt to do a partial initialization. + self.used_mut.insert(place.local); } _ => {} @@ -1974,7 +1952,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // of the union - we should error in that case. let tcx = this.infcx.tcx; if let ty::Adt(def, _) = - Place::ty_from(base.base, base.projection, this.body(), tcx).ty.kind + Place::ty_from(base.local, base.projection, this.body(), tcx).ty.kind { if def.is_union() { if this.move_data.path_map[mpi].iter().any(|moi| { @@ -2093,11 +2071,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // partial initialization, do not complain about mutability // errors except for actual mutation (as opposed to an attempt // to do a partial initialization). - let previously_initialized = if let PlaceBase::Local(local) = place.base { - self.is_local_ever_initialized(local, flow_state).is_some() - } else { - true - }; + let previously_initialized = + self.is_local_ever_initialized(place.local, flow_state).is_some(); // at this point, we have set up the error reporting state. if previously_initialized { @@ -2126,11 +2101,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Adds the place into the used mutable variables set fn add_used_mut<'d>(&mut self, root_place: RootPlace<'d, 'tcx>, flow_state: &Flows<'cx, 'tcx>) { match root_place { - RootPlace { - place_base: PlaceBase::Local(local), - place_projection: [], - is_local_mutation_allowed, - } => { + RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => { // If the local may have been initialized, and it is now currently being // mutated, then it is justified to be annotated with the `mut` // keyword, since the mutation may be a possible reassignment. @@ -2141,27 +2112,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } RootPlace { - place_base: _, + place_local: _, place_projection: _, is_local_mutation_allowed: LocalMutationIsAllowed::Yes, } => {} RootPlace { - place_base, + place_local, place_projection: place_projection @ [.., _], is_local_mutation_allowed: _, } => { if let Some(field) = self.is_upvar_field_projection(PlaceRef { - base: &place_base, - projection: &place_projection, + local: place_local, + projection: place_projection, }) { self.used_mut_upvars.push(field); } } - RootPlace { - place_base: PlaceBase::Static(..), - place_projection: [], - is_local_mutation_allowed: _, - } => {} } } @@ -2173,58 +2139,34 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { is_local_mutation_allowed: LocalMutationIsAllowed, ) -> Result, PlaceRef<'d, 'tcx>> { match place { - PlaceRef { base: PlaceBase::Local(local), projection: [] } => { + PlaceRef { local, projection: [] } => { let local = &self.body.local_decls[*local]; match local.mutability { Mutability::Not => match is_local_mutation_allowed { LocalMutationIsAllowed::Yes => Ok(RootPlace { - place_base: place.base, + place_local: place.local, place_projection: place.projection, is_local_mutation_allowed: LocalMutationIsAllowed::Yes, }), LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace { - place_base: place.base, + place_local: place.local, place_projection: place.projection, is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars, }), LocalMutationIsAllowed::No => Err(place), }, Mutability::Mut => Ok(RootPlace { - place_base: place.base, + place_local: place.local, place_projection: place.projection, is_local_mutation_allowed, }), } } - // The rules for promotion are made by `qualify_consts`, there wouldn't even be a - // `Place::Promoted` if the promotion weren't 100% legal. So we just forward this - PlaceRef { - base: PlaceBase::Static(box Static { kind: StaticKind::Promoted(..), .. }), - projection: [], - } => Ok(RootPlace { - place_base: place.base, - place_projection: place.projection, - is_local_mutation_allowed, - }), - PlaceRef { - base: PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }), - projection: [], - } => { - if !self.infcx.tcx.is_mutable_static(*def_id) { - Err(place) - } else { - Ok(RootPlace { - place_base: place.base, - place_projection: place.projection, - is_local_mutation_allowed, - }) - } - } - PlaceRef { base: _, projection: [proj_base @ .., elem] } => { + PlaceRef { local: _, projection: [proj_base @ .., elem] } => { match elem { ProjectionElem::Deref => { let base_ty = - Place::ty_from(place.base, proj_base, self.body(), self.infcx.tcx).ty; + Place::ty_from(place.local, proj_base, self.body(), self.infcx.tcx).ty; // Check the kind of deref to decide match base_ty.kind { @@ -2243,7 +2185,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }; self.is_mutable( - PlaceRef { base: place.base, projection: proj_base }, + PlaceRef { local: place.local, projection: proj_base }, mode, ) } @@ -2256,7 +2198,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // `*mut` raw pointers are always mutable, regardless of // context. The users have to check by themselves. hir::Mutability::Mut => Ok(RootPlace { - place_base: place.base, + place_local: place.local, place_projection: place.projection, is_local_mutation_allowed, }), @@ -2264,7 +2206,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } // `Box` owns its content, so mutable if its location is mutable _ if base_ty.is_box() => self.is_mutable( - PlaceRef { base: place.base, projection: proj_base }, + PlaceRef { local: place.local, projection: proj_base }, is_local_mutation_allowed, ), // Deref should only be for reference, pointers or boxes @@ -2320,11 +2262,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // } // ``` let _ = self.is_mutable( - PlaceRef { base: place.base, projection: proj_base }, + PlaceRef { local: place.local, projection: proj_base }, is_local_mutation_allowed, )?; Ok(RootPlace { - place_base: place.base, + place_local: place.local, place_projection: place.projection, is_local_mutation_allowed, }) @@ -2332,7 +2274,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } else { self.is_mutable( - PlaceRef { base: place.base, projection: proj_base }, + PlaceRef { local: place.local, projection: proj_base }, is_local_mutation_allowed, ) } @@ -2358,7 +2300,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { match place_projection { [base @ .., ProjectionElem::Field(field, _ty)] => { let tcx = self.infcx.tcx; - let base_ty = Place::ty_from(place_ref.base, base, self.body(), tcx).ty; + let base_ty = Place::ty_from(place_ref.local, base, self.body(), tcx).ty; if (base_ty.is_closure() || base_ty.is_generator()) && (!by_ref || self.upvars[field.index()].by_ref) @@ -2374,11 +2316,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum NoMovePathFound { - ReachedStatic, -} - /// The degree of overlap between 2 places for borrow-checking. enum Overlap { /// The places might partially overlap - in this case, we give diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs index a4c2299b3eaac..151a2c4c19a7d 100644 --- a/src/librustc_mir/borrow_check/nll.rs +++ b/src/librustc_mir/borrow_check/nll.rs @@ -231,7 +231,6 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( constraint_generation::generate_constraints( infcx, - param_env, &mut liveness_constraints, &mut all_facts, location_table, @@ -253,14 +252,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( ); // Generate various additional constraints. - invalidation::generate_invalidates( - infcx.tcx, - param_env, - &mut all_facts, - location_table, - body, - borrow_set, - ); + invalidation::generate_invalidates(infcx.tcx, &mut all_facts, location_table, body, borrow_set); // Dump facts if requested. let polonius_output = all_facts.and_then(|all_facts| { diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs index 23b4799643a6c..deec6f386ffb3 100644 --- a/src/librustc_mir/borrow_check/path_utils.rs +++ b/src/librustc_mir/borrow_check/path_utils.rs @@ -3,8 +3,8 @@ use crate::borrow_check::places_conflict; use crate::borrow_check::AccessDepth; use crate::dataflow::indexes::BorrowIndex; use rustc::mir::BorrowKind; -use rustc::mir::{BasicBlock, Body, Location, Place, PlaceBase}; -use rustc::ty::{self, TyCtxt}; +use rustc::mir::{BasicBlock, Body, Location, Place}; +use rustc::ty::TyCtxt; use rustc_data_structures::graph::dominators::Dominators; /// Returns `true` if the borrow represented by `kind` is @@ -25,7 +25,6 @@ pub(super) enum Control { pub(super) fn each_borrow_involving_path<'tcx, F, I, S>( s: &mut S, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, _location: Location, access_place: (AccessDepth, &Place<'tcx>), @@ -48,7 +47,6 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>( if places_conflict::borrow_conflicts_with_place( tcx, - param_env, body, &borrowed.borrowed_place, borrowed.kind, @@ -133,11 +131,7 @@ pub(super) fn is_active<'tcx>( /// Determines if a given borrow is borrowing local data /// This is called for all Yield expressions on movable generators pub(super) fn borrow_of_local_data(place: &Place<'_>) -> bool { - match place.base { - PlaceBase::Static(_) => false, - - // Reborrow of already borrowed data is ignored - // Any errors will be caught on the initial borrow - PlaceBase::Local(_) => !place.is_indirect(), - } + // Reborrow of already borrowed data is ignored + // Any errors will be caught on the initial borrow + !place.is_indirect() } diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs index 91ab314e2b910..ac02da2661586 100644 --- a/src/librustc_mir/borrow_check/place_ext.rs +++ b/src/librustc_mir/borrow_check/place_ext.rs @@ -1,6 +1,6 @@ use crate::borrow_check::borrow_set::LocalsStateAtExit; use rustc::mir::ProjectionElem; -use rustc::mir::{Body, Mutability, Place, PlaceBase}; +use rustc::mir::{Body, Mutability, Place}; use rustc::ty::{self, TyCtxt}; use rustc_hir as hir; @@ -25,41 +25,35 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { body: &Body<'tcx>, locals_state_at_exit: &LocalsStateAtExit, ) -> bool { - let local = match self.base { - // If a local variable is immutable, then we only need to track borrows to guard - // against two kinds of errors: - // * The variable being dropped while still borrowed (e.g., because the fn returns - // a reference to a local variable) - // * The variable being moved while still borrowed - // - // In particular, the variable cannot be mutated -- the "access checks" will fail -- - // so we don't have to worry about mutation while borrowed. - PlaceBase::Local(local) => match locals_state_at_exit { - LocalsStateAtExit::AllAreInvalidated => local, - LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => { - let ignore = !has_storage_dead_or_moved.contains(local) - && body.local_decls[local].mutability == Mutability::Not; - debug!("ignore_borrow: local {:?} => {:?}", local, ignore); - if ignore { - return true; - } else { - local - } - } - }, - PlaceBase::Static(_) => return true, - }; + // If a local variable is immutable, then we only need to track borrows to guard + // against two kinds of errors: + // * The variable being dropped while still borrowed (e.g., because the fn returns + // a reference to a local variable) + // * The variable being moved while still borrowed + // + // In particular, the variable cannot be mutated -- the "access checks" will fail -- + // so we don't have to worry about mutation while borrowed. + if let LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } = + locals_state_at_exit + { + let ignore = !has_storage_dead_or_moved.contains(self.local) + && body.local_decls[self.local].mutability == Mutability::Not; + debug!("ignore_borrow: local {:?} => {:?}", self.local, ignore); + if ignore { + return true; + } + } for (i, elem) in self.projection.iter().enumerate() { let proj_base = &self.projection[..i]; if *elem == ProjectionElem::Deref { - let ty = Place::ty_from(&self.base, proj_base, body, tcx).ty; + let ty = Place::ty_from(&self.local, proj_base, body, tcx).ty; match ty.kind { ty::Ref(_, _, hir::Mutability::Not) if i == 0 => { // For references to thread-local statics, we do need // to track the borrow. - if body.local_decls[local].is_ref_to_thread_local() { + if body.local_decls[self.local].is_ref_to_thread_local() { continue; } return true; diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 64103719fe925..b95d1af11ad1d 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -1,9 +1,7 @@ use crate::borrow_check::ArtificialField; use crate::borrow_check::Overlap; use crate::borrow_check::{AccessDepth, Deep, Shallow}; -use rustc::mir::{ - Body, BorrowKind, Place, PlaceBase, PlaceElem, PlaceRef, ProjectionElem, StaticKind, -}; +use rustc::mir::{Body, BorrowKind, Local, Place, PlaceElem, PlaceRef, ProjectionElem}; use rustc::ty::{self, TyCtxt}; use rustc_hir as hir; use std::cmp::max; @@ -25,7 +23,6 @@ crate enum PlaceConflictBias { /// dataflow). crate fn places_conflict<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, borrow_place: &Place<'tcx>, access_place: &Place<'tcx>, @@ -33,7 +30,6 @@ crate fn places_conflict<'tcx>( ) -> bool { borrow_conflicts_with_place( tcx, - param_env, body, borrow_place, BorrowKind::Mut { allow_two_phase_borrow: true }, @@ -49,7 +45,6 @@ crate fn places_conflict<'tcx>( /// order to make the conservative choice and preserve soundness. pub(super) fn borrow_conflicts_with_place<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, borrow_place: &Place<'tcx>, borrow_kind: BorrowKind, @@ -70,21 +65,11 @@ pub(super) fn borrow_conflicts_with_place<'tcx>( } } - place_components_conflict( - tcx, - param_env, - body, - borrow_place, - borrow_kind, - access_place, - access, - bias, - ) + place_components_conflict(tcx, body, borrow_place, borrow_kind, access_place, access, bias) } fn place_components_conflict<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, borrow_place: &Place<'tcx>, borrow_kind: BorrowKind, @@ -134,10 +119,10 @@ fn place_components_conflict<'tcx>( // and either equal or disjoint. // - If we did run out of access, the borrow can access a part of it. - let borrow_base = &borrow_place.base; - let access_base = access_place.base; + let borrow_local = &borrow_place.local; + let access_local = access_place.local; - match place_base_conflict(tcx, param_env, borrow_base, access_base) { + match place_base_conflict(borrow_local, access_local) { Overlap::Arbitrary => { bug!("Two base can't return Arbitrary"); } @@ -176,7 +161,7 @@ fn place_components_conflict<'tcx>( match place_projection_conflict( tcx, body, - borrow_base, + borrow_local, borrow_proj_base, borrow_c, access_c, @@ -223,7 +208,7 @@ fn place_components_conflict<'tcx>( // access cares about. let proj_base = &borrow_place.projection[..access_place.projection.len() + i]; - let base_ty = Place::ty_from(borrow_base, proj_base, body, tcx).ty; + let base_ty = Place::ty_from(borrow_local, proj_base, body, tcx).ty; match (elem, &base_ty.kind, access) { (_, _, Shallow(Some(ArtificialField::ArrayLength))) @@ -308,68 +293,15 @@ fn place_components_conflict<'tcx>( // Given that the bases of `elem1` and `elem2` are always either equal // or disjoint (and have the same type!), return the overlap situation // between `elem1` and `elem2`. -fn place_base_conflict<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - elem1: &PlaceBase<'tcx>, - elem2: &PlaceBase<'tcx>, -) -> Overlap { - match (elem1, elem2) { - (PlaceBase::Local(l1), PlaceBase::Local(l2)) => { - if l1 == l2 { - // the same local - base case, equal - debug!("place_element_conflict: DISJOINT-OR-EQ-LOCAL"); - Overlap::EqualOrDisjoint - } else { - // different locals - base case, disjoint - debug!("place_element_conflict: DISJOINT-LOCAL"); - Overlap::Disjoint - } - } - (PlaceBase::Static(s1), PlaceBase::Static(s2)) => { - match (&s1.kind, &s2.kind) { - (StaticKind::Static, StaticKind::Static) => { - if s1.def_id != s2.def_id { - debug!("place_element_conflict: DISJOINT-STATIC"); - Overlap::Disjoint - } else if tcx.is_mutable_static(s1.def_id) { - // We ignore mutable statics - they can only be unsafe code. - debug!("place_element_conflict: IGNORE-STATIC-MUT"); - Overlap::Disjoint - } else { - debug!("place_element_conflict: DISJOINT-OR-EQ-STATIC"); - Overlap::EqualOrDisjoint - } - } - (StaticKind::Promoted(promoted_1, _), StaticKind::Promoted(promoted_2, _)) => { - if promoted_1 == promoted_2 { - if let ty::Array(_, len) = s1.ty.kind { - if let Some(0) = len.try_eval_usize(tcx, param_env) { - // Ignore conflicts with promoted [T; 0]. - debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED"); - return Overlap::Disjoint; - } - } - // the same promoted - base case, equal - debug!("place_element_conflict: DISJOINT-OR-EQ-PROMOTED"); - Overlap::EqualOrDisjoint - } else { - // different promoteds - base case, disjoint - debug!("place_element_conflict: DISJOINT-PROMOTED"); - Overlap::Disjoint - } - } - (_, _) => { - debug!("place_element_conflict: DISJOINT-STATIC-PROMOTED"); - Overlap::Disjoint - } - } - } - (PlaceBase::Local(_), PlaceBase::Static(_)) - | (PlaceBase::Static(_), PlaceBase::Local(_)) => { - debug!("place_element_conflict: DISJOINT-STATIC-LOCAL-PROMOTED"); - Overlap::Disjoint - } +fn place_base_conflict(l1: &Local, l2: &Local) -> Overlap { + if l1 == l2 { + // the same local - base case, equal + debug!("place_element_conflict: DISJOINT-OR-EQ-LOCAL"); + Overlap::EqualOrDisjoint + } else { + // different locals - base case, disjoint + debug!("place_element_conflict: DISJOINT-LOCAL"); + Overlap::Disjoint } } @@ -379,7 +311,7 @@ fn place_base_conflict<'tcx>( fn place_projection_conflict<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - pi1_base: &PlaceBase<'tcx>, + pi1_local: &Local, pi1_proj_base: &[PlaceElem<'tcx>], pi1_elem: &PlaceElem<'tcx>, pi2_elem: &PlaceElem<'tcx>, @@ -397,7 +329,7 @@ fn place_projection_conflict<'tcx>( debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); Overlap::EqualOrDisjoint } else { - let ty = Place::ty_from(pi1_base, pi1_proj_base, body, tcx).ty; + let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty; match ty.kind { ty::Adt(def, _) if def.is_union() => { // Different fields of a union, we are basically stuck. diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs index 1e88f696f2315..31bee460fa011 100644 --- a/src/librustc_mir/borrow_check/prefixes.rs +++ b/src/librustc_mir/borrow_check/prefixes.rs @@ -9,7 +9,7 @@ use super::MirBorrowckCtxt; -use rustc::mir::{Place, PlaceBase, PlaceRef, ProjectionElem, ReadOnlyBodyAndCache}; +use rustc::mir::{Place, PlaceRef, ProjectionElem, ReadOnlyBodyAndCache}; use rustc::ty::{self, TyCtxt}; use rustc_hir as hir; @@ -19,7 +19,7 @@ pub trait IsPrefixOf<'cx, 'tcx> { impl<'cx, 'tcx> IsPrefixOf<'cx, 'tcx> for PlaceRef<'cx, 'tcx> { fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool { - self.base == other.base + self.local == other.local && self.projection.len() <= other.projection.len() && self.projection == &other.projection[..self.projection.len()] } @@ -69,39 +69,23 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { 'cursor: loop { match &cursor { - PlaceRef { - base: PlaceBase::Local(_), - projection: [], - } - | // search yielded this leaf - PlaceRef { - base: PlaceBase::Static(_), - projection: [], - } => { + PlaceRef { local: _, projection: [] } => { self.next = None; return Some(cursor); } - PlaceRef { - base: _, - projection: [proj_base @ .., elem], - } => { + PlaceRef { local: _, projection: [proj_base @ .., elem] } => { match elem { ProjectionElem::Field(_ /*field*/, _ /*ty*/) => { // FIXME: add union handling - self.next = Some(PlaceRef { - base: cursor.base, - projection: proj_base, - }); + self.next = + Some(PlaceRef { local: cursor.local, projection: proj_base }); return Some(cursor); } - ProjectionElem::Downcast(..) | - ProjectionElem::Subslice { .. } | - ProjectionElem::ConstantIndex { .. } | - ProjectionElem::Index(_) => { - cursor = PlaceRef { - base: cursor.base, - projection: proj_base, - }; + ProjectionElem::Downcast(..) + | ProjectionElem::Subslice { .. } + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Index(_) => { + cursor = PlaceRef { local: cursor.local, projection: proj_base }; continue 'cursor; } ProjectionElem::Deref => { @@ -122,10 +106,8 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { PrefixSet::All => { // All prefixes: just blindly enqueue the base // of the projection. - self.next = Some(PlaceRef { - base: cursor.base, - projection: proj_base, - }); + self.next = + Some(PlaceRef { local: cursor.local, projection: proj_base }); return Some(cursor); } PrefixSet::Supporting => { @@ -138,37 +120,24 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { // derefs, except we stop at the deref of a shared // reference. - let ty = Place::ty_from(cursor.base, proj_base, *self.body, self.tcx).ty; + let ty = Place::ty_from(cursor.local, proj_base, *self.body, self.tcx).ty; match ty.kind { - ty::RawPtr(_) | - ty::Ref( - _, /*rgn*/ - _, /*ty*/ - hir::Mutability::Not - ) => { + ty::RawPtr(_) | ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Not) => { // don't continue traversing over derefs of raw pointers or shared // borrows. self.next = None; return Some(cursor); } - ty::Ref( - _, /*rgn*/ - _, /*ty*/ - hir::Mutability::Mut, - ) => { - self.next = Some(PlaceRef { - base: cursor.base, - projection: proj_base, - }); + ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Mut) => { + self.next = + Some(PlaceRef { local: cursor.local, projection: proj_base }); return Some(cursor); } ty::Adt(..) if ty.is_box() => { - self.next = Some(PlaceRef { - base: cursor.base, - projection: proj_base, - }); + self.next = + Some(PlaceRef { local: cursor.local, projection: proj_base }); return Some(cursor); } diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index b1df198406d3b..947bbef4379f5 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -310,17 +310,54 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { ); } } else { - if let ty::ConstKind::Unevaluated(def_id, substs) = constant.literal.val { - if let Err(terr) = self.cx.fully_perform_op( - location.to_locations(), - ConstraintCategory::Boring, - self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( - constant.literal.ty, - def_id, - UserSubsts { substs, user_self_ty: None }, - )), - ) { - span_mirbug!(self, constant, "bad constant type {:?} ({:?})", constant, terr); + if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.literal.val { + if let Some(promoted) = promoted { + let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, + promoted: &ReadOnlyBodyAndCache<'_, 'tcx>, + ty, + san_ty| { + if let Err(terr) = verifier.cx.eq_types( + san_ty, + ty, + location.to_locations(), + ConstraintCategory::Boring, + ) { + span_mirbug!( + verifier, + promoted, + "bad promoted type ({:?}: {:?}): {:?}", + ty, + san_ty, + terr + ); + }; + }; + + if !self.errors_reported { + let promoted_body = self.promoted[promoted]; + self.sanitize_promoted(promoted_body, location); + + let promoted_ty = promoted_body.return_ty(); + check_err(self, &promoted_body, ty, promoted_ty); + } + } else { + if let Err(terr) = self.cx.fully_perform_op( + location.to_locations(), + ConstraintCategory::Boring, + self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( + constant.literal.ty, + def_id, + UserSubsts { substs, user_self_ty: None }, + )), + ) { + span_mirbug!( + self, + constant, + "bad constant type {:?} ({:?})", + constant, + terr + ); + } } } if let ty::FnDef(def_id, substs) = constant.literal.ty.kind { @@ -428,83 +465,32 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { ) -> PlaceTy<'tcx> { debug!("sanitize_place: {:?}", place); - let mut place_ty = match &place.base { - PlaceBase::Local(index) => PlaceTy::from_ty(self.body.local_decls[*index].ty), - PlaceBase::Static(box Static { kind, ty, def_id }) => { - let san_ty = self.sanitize_type(place, ty); - let check_err = - |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, place: &Place<'tcx>, ty, san_ty| { - if let Err(terr) = verifier.cx.eq_types( - san_ty, - ty, - location.to_locations(), - ConstraintCategory::Boring, - ) { - span_mirbug!( - verifier, - place, - "bad promoted type ({:?}: {:?}): {:?}", - ty, - san_ty, - terr - ); - }; - }; - match kind { - StaticKind::Promoted(promoted, _) => { - if !self.errors_reported { - let promoted_body_cache = self.promoted[*promoted]; - self.sanitize_promoted(promoted_body_cache, location); - - let promoted_ty = promoted_body_cache.return_ty(); - check_err(self, place, promoted_ty, san_ty); - } - } - StaticKind::Static => { - let ty = self.tcx().type_of(*def_id); - let ty = self.cx.normalize(ty, location); - - check_err(self, place, ty, san_ty); - } - } - PlaceTy::from_ty(san_ty) - } - }; + let mut place_ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty); if place.projection.is_empty() { if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { - let is_promoted = match place.as_ref() { - PlaceRef { - base: &PlaceBase::Static(box Static { kind: StaticKind::Promoted(..), .. }), - projection: &[], - } => true, - _ => false, + let tcx = self.tcx(); + let trait_ref = ty::TraitRef { + def_id: tcx.lang_items().copy_trait().unwrap(), + substs: tcx.mk_substs_trait(place_ty.ty, &[]), }; - if !is_promoted { - let tcx = self.tcx(); - let trait_ref = ty::TraitRef { - def_id: tcx.lang_items().copy_trait().unwrap(), - substs: tcx.mk_substs_trait(place_ty.ty, &[]), - }; - - // To have a `Copy` operand, the type `T` of the - // value must be `Copy`. Note that we prove that `T: Copy`, - // rather than using the `is_copy_modulo_regions` - // test. This is important because - // `is_copy_modulo_regions` ignores the resulting region - // obligations and assumes they pass. This can result in - // bounds from `Copy` impls being unsoundly ignored (e.g., - // #29149). Note that we decide to use `Copy` before knowing - // whether the bounds fully apply: in effect, the rule is - // that if a value of some type could implement `Copy`, then - // it must. - self.cx.prove_trait_ref( - trait_ref, - location.to_locations(), - ConstraintCategory::CopyBound, - ); - } + // To have a `Copy` operand, the type `T` of the + // value must be `Copy`. Note that we prove that `T: Copy`, + // rather than using the `is_copy_modulo_regions` + // test. This is important because + // `is_copy_modulo_regions` ignores the resulting region + // obligations and assumes they pass. This can result in + // bounds from `Copy` impls being unsoundly ignored (e.g., + // #29149). Note that we decide to use `Copy` before knowing + // whether the bounds fully apply: in effect, the rule is + // that if a value of some type could implement `Copy`, then + // it must. + self.cx.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::CopyBound, + ); } } @@ -2401,7 +2387,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { match elem { ProjectionElem::Deref => { let tcx = self.infcx.tcx; - let base_ty = Place::ty_from(&borrowed_place.base, proj_base, body, tcx).ty; + let base_ty = Place::ty_from(&borrowed_place.local, proj_base, body, tcx).ty; debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); match base_ty.kind { diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs index 608a2436bf3d3..5e4eebb771f21 100644 --- a/src/librustc_mir/borrow_check/used_muts.rs +++ b/src/librustc_mir/borrow_check/used_muts.rs @@ -1,5 +1,5 @@ use rustc::mir::visit::{PlaceContext, Visitor}; -use rustc::mir::{Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind}; +use rustc::mir::{Local, Location, Place, Statement, StatementKind, TerminatorKind}; use rustc_data_structures::fx::FxHashSet; @@ -57,9 +57,7 @@ impl GatherUsedMutsVisitor<'_, '_, '_> { // be those that were never initialized - we will consider those as being used as // they will either have been removed by unreachable code optimizations; or linted // as unused variables. - if let PlaceBase::Local(local) = into.base { - let _ = self.never_initialized_mut_locals.remove(&local); - } + self.never_initialized_mut_locals.remove(&into.local); } } @@ -80,13 +78,11 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc fn visit_statement(&mut self, statement: &Statement<'tcx>, _location: Location) { match &statement.kind { StatementKind::Assign(box (into, _)) => { - if let PlaceBase::Local(local) = into.base { - debug!( - "visit_statement: statement={:?} local={:?} \ - never_initialized_mut_locals={:?}", - statement, local, self.never_initialized_mut_locals - ); - } + debug!( + "visit_statement: statement={:?} local={:?} \ + never_initialized_mut_locals={:?}", + statement, into.local, self.never_initialized_mut_locals + ); self.remove_never_initialized_mut_locals(into); } _ => {} diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 29eac5e4b3f54..eb2e87f4a2d41 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -20,13 +20,13 @@ use rustc_index::vec::Idx; /// and `c` can be progressively pushed onto the place builder that is created when converting `a`. #[derive(Clone)] struct PlaceBuilder<'tcx> { - base: PlaceBase<'tcx>, + local: Local, projection: Vec>, } impl PlaceBuilder<'tcx> { fn into_place(self, tcx: TyCtxt<'tcx>) -> Place<'tcx> { - Place { base: self.base, projection: tcx.intern_place_elems(&self.projection) } + Place { local: self.local, projection: tcx.intern_place_elems(&self.projection) } } fn field(self, f: Field, ty: Ty<'tcx>) -> Self { @@ -49,13 +49,7 @@ impl PlaceBuilder<'tcx> { impl From for PlaceBuilder<'tcx> { fn from(local: Local) -> Self { - Self { base: local.into(), projection: Vec::new() } - } -} - -impl From> for PlaceBuilder<'tcx> { - fn from(base: PlaceBase<'tcx>) -> Self { - Self { base, projection: Vec::new() } + Self { local, projection: Vec::new() } } } @@ -370,7 +364,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) { let tcx = self.hir.tcx(); let place_ty = - Place::ty_from(&base_place.base, &base_place.projection, &self.local_decls, tcx); + Place::ty_from(&base_place.local, &base_place.projection, &self.local_decls, tcx); if let ty::Slice(_) = place_ty.ty.kind { // We need to create fake borrows to ensure that the bounds // check that we just did stays valid. Since we can't assign to @@ -380,7 +374,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match elem { ProjectionElem::Deref => { let fake_borrow_deref_ty = Place::ty_from( - &base_place.base, + &base_place.local, &base_place.projection[..idx], &self.local_decls, tcx, @@ -398,14 +392,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Rvalue::Ref( tcx.lifetimes.re_erased, BorrowKind::Shallow, - Place { base: base_place.base.clone(), projection }, + Place { local: base_place.local.clone(), projection }, ), ); fake_borrow_temps.push(fake_borrow_temp); } ProjectionElem::Index(_) => { let index_ty = Place::ty_from( - &base_place.base, + &base_place.local, &base_place.projection[..idx], &self.local_decls, tcx, diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 34b0cbf3b25cd..6f7b7258b5a1a 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -393,26 +393,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let arg_place = unpack!(block = this.as_place(block, arg)); let mutability = match arg_place.as_ref() { - PlaceRef { base: &PlaceBase::Local(local), projection: &[] } => { - this.local_decls[local].mutability - } - PlaceRef { base: &PlaceBase::Local(local), projection: &[ProjectionElem::Deref] } => { + PlaceRef { local, projection: &[] } => this.local_decls[*local].mutability, + PlaceRef { local, projection: &[ProjectionElem::Deref] } => { debug_assert!( - this.local_decls[local].is_ref_for_guard(), + this.local_decls[*local].is_ref_for_guard(), "Unexpected capture place", ); - this.local_decls[local].mutability + this.local_decls[*local].mutability } PlaceRef { - ref base, + ref local, projection: &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _)], } | PlaceRef { - ref base, + ref local, projection: &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _), ProjectionElem::Deref], } => { - let place = PlaceRef { base, projection: proj_base }; + let place = PlaceRef { local, projection: proj_base }; // Not projected from the implicit `self` in a closure. debug_assert!( diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 7eea90befb008..1dcd29d923244 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -890,7 +890,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let proj_base = &source.projection[..i]; fake_borrows.insert(Place { - base: source.base.clone(), + local: source.local.clone(), projection: self.hir.tcx().intern_place_elems(proj_base), }); } @@ -1241,7 +1241,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Insert a shallow borrow after a deref. For other // projections the borrow of prefix_cursor will // conflict with any mutation of base. - all_fake_borrows.push(PlaceRef { base: &place.base, projection: proj_base }); + all_fake_borrows.push(PlaceRef { local: &place.local, projection: proj_base }); } } @@ -1258,7 +1258,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .into_iter() .map(|matched_place_ref| { let matched_place = Place { - base: matched_place_ref.base.clone(), + local: matched_place_ref.local.clone(), projection: tcx.intern_place_elems(matched_place_ref.projection), }; let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty; diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index d6d22db9ff24b..d4813d8ab68ca 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -834,7 +834,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span: tcx_hir.span(var_id), }, place: Place { - base: closure_env_arg.into(), + local: closure_env_arg.into(), projection: tcx.intern_place_elems(&projs), }, }); diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 7b2ce7f9ac7be..eb89553b77036 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -52,7 +52,7 @@ pub(crate) fn const_caller_location<'tcx>( let loc_ty = tcx.caller_location_ty(); let loc_place = ecx.alloc_caller_location(file, line, col); - intern_const_alloc_recursive(&mut ecx, None, loc_place).unwrap(); + intern_const_alloc_recursive(&mut ecx, None, loc_place, false).unwrap(); let loc_const = ty::Const { ty: loc_ty, val: ty::ConstKind::Value(ConstValue::Scalar(loc_place.ptr.into())), diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index 53f3b539bdaa0..d260a6808d120 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -56,7 +56,12 @@ fn eval_body_using_ecx<'mir, 'tcx>( ecx.run()?; // Intern the result - intern_const_alloc_recursive(ecx, tcx.static_mutability(cid.instance.def_id()), ret)?; + intern_const_alloc_recursive( + ecx, + tcx.static_mutability(cid.instance.def_id()), + ret, + body.ignore_interior_mut_in_const_validation, + )?; debug!("eval_body_using_ecx done: {:?}", *ret); Ok(ret) @@ -171,9 +176,14 @@ fn validate_and_turn_into_const<'tcx>( let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, is_static); let val = (|| { let mplace = ecx.raw_const_to_mplace(constant)?; - let mut ref_tracking = RefTracking::new(mplace); - while let Some((mplace, path)) = ref_tracking.todo.pop() { - ecx.validate_operand(mplace.into(), path, Some(&mut ref_tracking))?; + + // FIXME do not validate promoteds until a decision on + // https://github.com/rust-lang/rust/issues/67465 is made + if cid.promoted.is_none() { + let mut ref_tracking = RefTracking::new(mplace); + while let Some((mplace, path)) = ref_tracking.todo.pop() { + ecx.validate_operand(mplace.into(), path, Some(&mut ref_tracking))?; + } } // Now that we validated, turn this into a proper constant. // Statics/promoteds are always `ByRef`, for the rest `op_to_const` decides diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs index 65976908f597e..63834d0ecda00 100644 --- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs +++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs @@ -86,10 +86,7 @@ struct BorrowedLocalsVisitor<'gk> { } fn find_local(place: &Place<'_>) -> Option { - match place.base { - PlaceBase::Local(local) if !place.is_indirect() => Some(local), - _ => None, - } + if !place.is_indirect() { Some(place.local) } else { None } } impl<'tcx> Visitor<'tcx> for BorrowedLocalsVisitor<'_> { diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 8d51cb2391234..f94ee67f2bea7 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -1,6 +1,6 @@ -use rustc::mir::{self, Body, Location, Place, PlaceBase}; +use rustc::mir::{self, Body, Location, Place}; use rustc::ty::RegionVid; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::TyCtxt; use rustc_data_structures::fx::FxHashMap; use rustc_index::bit_set::BitSet; @@ -30,7 +30,6 @@ rustc_index::newtype_index! { pub struct Borrows<'a, 'tcx> { tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, - param_env: ty::ParamEnv<'tcx>, borrow_set: Rc>, borrows_out_of_scope_at_location: FxHashMap>, @@ -134,7 +133,6 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { crate fn new( tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, - param_env: ty::ParamEnv<'tcx>, nonlexical_regioncx: Rc>, borrow_set: &Rc>, ) -> Self { @@ -156,7 +154,6 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { Borrows { tcx, body, - param_env, borrow_set: borrow_set.clone(), borrows_out_of_scope_at_location, _nonlexical_regioncx: nonlexical_regioncx, @@ -198,37 +195,34 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { fn kill_borrows_on_place(&self, trans: &mut GenKillSet, place: &Place<'tcx>) { debug!("kill_borrows_on_place: place={:?}", place); - if let PlaceBase::Local(local) = place.base { - let other_borrows_of_local = - self.borrow_set.local_map.get(&local).into_iter().flat_map(|bs| bs.into_iter()); + let other_borrows_of_local = + self.borrow_set.local_map.get(&place.local).into_iter().flat_map(|bs| bs.into_iter()); - // If the borrowed place is a local with no projections, all other borrows of this - // local must conflict. This is purely an optimization so we don't have to call - // `places_conflict` for every borrow. - if place.projection.is_empty() { - if !self.body.local_decls[local].is_ref_to_static() { - trans.kill_all(other_borrows_of_local); - } - return; + // If the borrowed place is a local with no projections, all other borrows of this + // local must conflict. This is purely an optimization so we don't have to call + // `places_conflict` for every borrow. + if place.projection.is_empty() { + if !self.body.local_decls[place.local].is_ref_to_static() { + trans.kill_all(other_borrows_of_local); } - - // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given - // pair of array indices are unequal, so that when `places_conflict` returns true, we - // will be assured that two places being compared definitely denotes the same sets of - // locations. - let definitely_conflicting_borrows = other_borrows_of_local.filter(|&&i| { - places_conflict( - self.tcx, - self.param_env, - self.body, - &self.borrow_set.borrows[i].borrowed_place, - place, - PlaceConflictBias::NoOverlap, - ) - }); - - trans.kill_all(definitely_conflicting_borrows); + return; } + + // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given + // pair of array indices are unequal, so that when `places_conflict` returns true, we + // will be assured that two places being compared definitely denotes the same sets of + // locations. + let definitely_conflicting_borrows = other_borrows_of_local.filter(|&&i| { + places_conflict( + self.tcx, + self.body, + &self.borrow_set.borrows[i].borrowed_place, + place, + PlaceConflictBias::NoOverlap, + ) + }); + + trans.kill_all(definitely_conflicting_borrows); } } diff --git a/src/librustc_mir/dataflow/impls/indirect_mutation.rs b/src/librustc_mir/dataflow/impls/indirect_mutation.rs index 38401b42b48a8..85bf342c8a39a 100644 --- a/src/librustc_mir/dataflow/impls/indirect_mutation.rs +++ b/src/librustc_mir/dataflow/impls/indirect_mutation.rs @@ -111,12 +111,8 @@ impl<'tcx> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx> { fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { if let mir::Rvalue::Ref(_, kind, ref borrowed_place) = *rvalue { if self.borrow_allows_mutation(kind, borrowed_place) { - match borrowed_place.base { - mir::PlaceBase::Local(borrowed_local) if !borrowed_place.is_indirect() => { - self.trans.gen(borrowed_local) - } - - _ => (), + if !borrowed_place.is_indirect() { + self.trans.gen(borrowed_place.local); } } } diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs index 17f71e83cfd21..6a48d1e98032c 100644 --- a/src/librustc_mir/dataflow/impls/storage_liveness.rs +++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs @@ -116,15 +116,11 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> { StatementKind::StorageDead(l) => sets.kill(l), StatementKind::Assign(box (ref place, _)) | StatementKind::SetDiscriminant { box ref place, .. } => { - if let PlaceBase::Local(local) = place.base { - sets.gen(local); - } + sets.gen(place.local); } StatementKind::InlineAsm(box InlineAsm { ref outputs, .. }) => { - for p in &**outputs { - if let PlaceBase::Local(local) = p.base { - sets.gen(local); - } + for place in &**outputs { + sets.gen(place.local); } } _ => (), @@ -140,10 +136,8 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> { fn before_terminator_effect(&self, sets: &mut GenKillSet, loc: Location) { self.check_for_borrow(sets, loc); - if let TerminatorKind::Call { - destination: Some((Place { base: PlaceBase::Local(local), .. }, _)), - .. - } = self.body[loc.block].terminator().kind + if let TerminatorKind::Call { destination: Some((Place { local, .. }, _)), .. } = + self.body[loc.block].terminator().kind { sets.gen(local); } @@ -171,9 +165,7 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> { _dest_bb: mir::BasicBlock, dest_place: &mir::Place<'tcx>, ) { - if let PlaceBase::Local(local) = dest_place.base { - in_out.insert(local); - } + in_out.insert(dest_place.local); } } diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index c05f7f8959dbf..271bcce6ca53c 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -96,12 +96,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { /// Maybe we should have separate "borrowck" and "moveck" modes. fn move_path_for(&mut self, place: &Place<'tcx>) -> Result> { debug!("lookup({:?})", place); - let mut base = match place.base { - PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[local], - PlaceBase::Static(..) => { - return Err(MoveError::cannot_move_out_of(self.loc, Static)); - } - }; + let mut base = self.builder.data.rev_lookup.locals[place.local]; // The move path index of the first union that we find. Once this is // some we stop creating child move paths, since moves from unions @@ -114,7 +109,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { let proj_base = &place.projection[..i]; let body = self.builder.body; let tcx = self.builder.tcx; - let place_ty = Place::ty_from(&place.base, proj_base, body, tcx).ty; + let place_ty = Place::ty_from(&place.local, proj_base, body, tcx).ty; match place_ty.kind { ty::Ref(..) | ty::RawPtr(..) => { let proj = &place.projection[..i + 1]; @@ -122,7 +117,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { self.loc, BorrowedContent { target_place: Place { - base: place.base.clone(), + local: place.local, projection: tcx.intern_place_elems(proj), }, }, @@ -163,7 +158,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { if union_path.is_none() { base = self.add_move_path(base, elem, |tcx| Place { - base: place.base.clone(), + local: place.local.clone(), projection: tcx.intern_place_elems(&place.projection[..i + 1]), }); } @@ -436,7 +431,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { // `ConstIndex` patterns. This is done to ensure that all move paths // are disjoint, which is expected by drop elaboration. let base_place = Place { - base: place.base.clone(), + local: place.local.clone(), projection: self.builder.tcx.intern_place_elems(base), }; let base_path = match self.move_path_for(&base_place) { @@ -497,10 +492,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { // of the union so it is marked as initialized again. if let [proj_base @ .., ProjectionElem::Field(_, _)] = place.projection { if let ty::Adt(def, _) = - Place::ty_from(place.base, proj_base, self.builder.body, self.builder.tcx).ty.kind + Place::ty_from(place.local, proj_base, self.builder.body, self.builder.tcx).ty.kind { if def.is_union() { - place = PlaceRef { base: place.base, projection: proj_base } + place = PlaceRef { local: place.local, projection: proj_base } } } } diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index e5cddaf6c66f2..a46465ab49376 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -246,10 +246,7 @@ impl MovePathLookup { // unknown place, but will rather return the nearest available // parent. pub fn find(&self, place: PlaceRef<'_, '_>) -> LookupResult { - let mut result = match place.base { - PlaceBase::Local(local) => self.locals[*local], - PlaceBase::Static(..) => return LookupResult::Parent(None), - }; + let mut result = self.locals[*place.local]; for elem in place.projection.iter() { if let Some(&subpath) = self.projections.get(&(result, elem.lift())) { @@ -281,9 +278,6 @@ pub struct IllegalMoveOrigin<'tcx> { #[derive(Debug)] pub(crate) enum IllegalMoveOriginKind<'tcx> { - /// Illegal move due to attempt to move from `static` variable. - Static, - /// Illegal move due to attempt to move from behind a reference. BorrowedContent { /// The place the reference refers to: if erroneous code was trying to diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 8fd8143ee374f..471e09fc03b28 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -411,15 +411,18 @@ fn make_mirror_unadjusted<'a, 'tcx>( let def_id = cx.tcx.hir().local_def_id(count.hir_id); let substs = InternalSubsts::identity_for_item(cx.tcx, def_id); let span = cx.tcx.def_span(def_id); - let count = match cx.tcx.const_eval_resolve(cx.param_env, def_id, substs, Some(span)) { - Ok(cv) => cv.eval_usize(cx.tcx, cx.param_env), - Err(ErrorHandled::Reported) => 0, - Err(ErrorHandled::TooGeneric) => { - let span = cx.tcx.def_span(def_id); - cx.tcx.sess.span_err(span, "array lengths can't depend on generic parameters"); - 0 - } - }; + let count = + match cx.tcx.const_eval_resolve(cx.param_env, def_id, substs, None, Some(span)) { + Ok(cv) => cv.eval_usize(cx.tcx, cx.param_env), + Err(ErrorHandled::Reported) => 0, + Err(ErrorHandled::TooGeneric) => { + let span = cx.tcx.def_span(def_id); + cx.tcx + .sess + .span_err(span, "array lengths can't depend on generic parameters"); + 0 + } + }; ExprKind::Repeat { value: v.to_ref(), count } } @@ -523,7 +526,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( // and not the beginning of discriminants (which is always `0`) let substs = InternalSubsts::identity_for_item(cx.tcx(), did); let lhs = mk_const(cx.tcx().mk_const(ty::Const { - val: ty::ConstKind::Unevaluated(did, substs), + val: ty::ConstKind::Unevaluated(did, substs, None), ty: var_ty, })); let bin = ExprKind::Binary { op: BinOp::Add, lhs, rhs: offset }; @@ -719,7 +722,7 @@ fn convert_path_expr<'a, 'tcx>( debug!("convert_path_expr: (const) user_ty={:?}", user_ty); ExprKind::Literal { literal: cx.tcx.mk_const(ty::Const { - val: ty::ConstKind::Unevaluated(def_id, substs), + val: ty::ConstKind::Unevaluated(def_id, substs, None), ty: cx.tables().node_type(expr.hir_id), }), user_ty, diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 2598ce2391fb3..c7e26c6ea4fd4 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -775,6 +775,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { self.param_env.with_reveal_all(), def_id, substs, + None, Some(span), ) { Ok(value) => { diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 864f4f9487c88..206d3d156735e 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -757,13 +757,22 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, gid: GlobalId<'tcx>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - let val = if self.tcx.is_static(gid.instance.def_id()) { - self.tcx.const_eval_poly(gid.instance.def_id())? - } else if let Some(promoted) = gid.promoted { - self.tcx.const_eval_promoted(gid.instance, promoted)? + // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics + // and thus don't care about the parameter environment. While we could just use + // `self.param_env`, that would mean we invoke the query to evaluate the static + // with different parameter environments, thus causing the static to be evaluated + // multiple times. + let param_env = if self.tcx.is_static(gid.instance.def_id()) { + ty::ParamEnv::reveal_all() } else { - self.tcx.const_eval_instance(self.param_env, gid.instance, Some(self.tcx.span))? + self.param_env }; + let val = if let Some(promoted) = gid.promoted { + self.tcx.const_eval_promoted(param_env, gid.instance, promoted)? + } else { + self.tcx.const_eval_instance(param_env, gid.instance, Some(self.tcx.span))? + }; + // Even though `ecx.const_eval` is called from `eval_const_to_op` we can never have a // recursion deeper than one level, because the `tcx.const_eval` above is guaranteed to not // return `ConstValue::Unevaluated`, which is the only way that `eval_const_to_op` will call diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs index 9b3a2fa36f794..220761ce28d81 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/src/librustc_mir/interpret/intern.rs @@ -41,6 +41,11 @@ struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> { /// despite the nested mutable reference! /// The field gets updated when an `UnsafeCell` is encountered. mutability: Mutability, + + /// This flag is to avoid triggering UnsafeCells are not allowed behind references in constants + /// for promoteds. + /// It's a copy of `mir::Body`'s ignore_interior_mut_in_const_validation field + ignore_interior_mut_in_const_validation: bool, } #[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)] @@ -164,14 +169,16 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx // References we encounter inside here are interned as pointing to mutable // allocations. let old = std::mem::replace(&mut self.mutability, Mutability::Mut); - assert_ne!( - self.mode, - InternMode::Const, - "UnsafeCells are not allowed behind references in constants. This should have \ - been prevented statically by const qualification. If this were allowed one \ - would be able to change a constant at one use site and other use sites could \ - observe that mutation.", - ); + if !self.ignore_interior_mut_in_const_validation { + assert_ne!( + self.mode, + InternMode::Const, + "UnsafeCells are not allowed behind references in constants. This should \ + have been prevented statically by const qualification. If this were \ + allowed one would be able to change a constant at one use site and other \ + use sites could observe that mutation.", + ); + } let walked = self.walk_aggregate(mplace, fields); self.mutability = old; return walked; @@ -266,6 +273,7 @@ pub fn intern_const_alloc_recursive>( // The `mutability` of the place, ignoring the type. place_mut: Option, ret: MPlaceTy<'tcx>, + ignore_interior_mut_in_const_validation: bool, ) -> InterpResult<'tcx> { let tcx = ecx.tcx; let (base_mutability, base_intern_mode) = match place_mut { @@ -302,6 +310,7 @@ pub fn intern_const_alloc_recursive>( mode, leftover_allocations, mutability, + ignore_interior_mut_in_const_validation, } .visit_value(mplace); if let Err(error) = interned { diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 6d15827536c55..3309e9b9b622a 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -212,7 +212,7 @@ pub trait Machine<'mir, 'tcx>: Sized { frame.locals[local].access() } - /// Called before a `StaticKind::Static` value is accessed. + /// Called before a `Static` value is accessed. fn before_access_static( _memory_extra: &Self::MemoryExtra, _allocation: &Allocation, diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index ddd9776e89383..b37eff3f40626 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -462,19 +462,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { place: &mir::Place<'tcx>, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - use rustc::mir::PlaceBase; - - let base_op = match &place.base { - PlaceBase::Local(mir::RETURN_PLACE) => throw_unsup!(ReadFromReturnPointer), - PlaceBase::Local(local) => { + let base_op = match place.local { + mir::RETURN_PLACE => throw_unsup!(ReadFromReturnPointer), + local => { // Do not use the layout passed in as argument if the base we are looking at // here is not the entire place. - // FIXME use place_projection.is_empty() when is available let layout = if place.projection.is_empty() { layout } else { None }; - self.access_local(self.frame(), *local, layout)? + self.access_local(self.frame(), local, layout)? } - PlaceBase::Static(place_static) => self.eval_static_to_mplace(&place_static)?.into(), }; let op = place @@ -532,7 +528,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Early-return cases. let val_val = match val.val { ty::ConstKind::Param(_) => throw_inval!(TooGeneric), - ty::ConstKind::Unevaluated(def_id, substs) => { + ty::ConstKind::Unevaluated(def_id, substs, promoted) => { let instance = self.resolve(def_id, substs)?; // We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation. // The reason we use `const_eval_raw` everywhere else is to prevent cycles during @@ -540,9 +536,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // potentially requiring the current static to be evaluated again. This is not a // problem here, because we are building an operand which means an actual read is // happening. - // FIXME(oli-obk): eliminate all the `const_eval_raw` usages when we get rid of - // `StaticKind` once and for all. - return self.const_eval(GlobalId { instance, promoted: None }); + return Ok(OpTy::from(self.const_eval(GlobalId { instance, promoted })?)); } ty::ConstKind::Infer(..) | ty::ConstKind::Bound(..) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 890627a54543a..8888e3fd4632a 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -10,14 +10,13 @@ use rustc::mir::interpret::truncate; use rustc::ty::layout::{ self, Align, HasDataLayout, LayoutOf, PrimitiveExt, Size, TyLayout, VariantIdx, }; -use rustc::ty::TypeFoldable; use rustc::ty::{self, Ty}; use rustc_macros::HashStable; use super::{ - AllocId, AllocMap, Allocation, AllocationExtra, GlobalId, ImmTy, Immediate, InterpCx, - InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, Pointer, PointerArithmetic, - RawConst, Scalar, ScalarMaybeUndef, + AllocId, AllocMap, Allocation, AllocationExtra, ImmTy, Immediate, InterpCx, InterpResult, + LocalValue, Machine, MemoryKind, OpTy, Operand, Pointer, PointerArithmetic, RawConst, Scalar, + ScalarMaybeUndef, }; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)] @@ -619,64 +618,14 @@ where }) } - /// Evaluate statics and promoteds to an `MPlace`. Used to share some code between - /// `eval_place` and `eval_place_to_op`. - pub(super) fn eval_static_to_mplace( - &self, - place_static: &mir::Static<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - use rustc::mir::StaticKind; - - Ok(match place_static.kind { - StaticKind::Promoted(promoted, promoted_substs) => { - let substs = self.subst_from_frame_and_normalize_erasing_regions(promoted_substs); - let instance = ty::Instance::new(place_static.def_id, substs); - - // Even after getting `substs` from the frame, this instance may still be - // polymorphic because `ConstProp` will try to promote polymorphic MIR. - if instance.needs_subst() { - throw_inval!(TooGeneric); - } - - self.const_eval_raw(GlobalId { instance, promoted: Some(promoted) })? - } - - StaticKind::Static => { - let ty = place_static.ty; - assert!(!ty.needs_subst()); - let layout = self.layout_of(ty)?; - // Just create a lazy reference, so we can support recursive statics. - // tcx takes care of assigning every static one and only one unique AllocId. - // When the data here is ever actually used, memory will notice, - // and it knows how to deal with alloc_id that are present in the - // global table but not in its local memory: It calls back into tcx through - // a query, triggering the CTFE machinery to actually turn this lazy reference - // into a bunch of bytes. IOW, statics are evaluated with CTFE even when - // this InterpCx uses another Machine (e.g., in miri). This is what we - // want! This way, computing statics works consistently between codegen - // and miri: They use the same query to eventually obtain a `ty::Const` - // and use that for further computation. - // - // Notice that statics have *two* AllocIds: the lazy one, and the resolved - // one. Here we make sure that the interpreted program never sees the - // resolved ID. Also see the doc comment of `Memory::get_static_alloc`. - let alloc_id = self.tcx.alloc_map.lock().create_static_alloc(place_static.def_id); - let ptr = self.tag_static_base_pointer(Pointer::from(alloc_id)); - MPlaceTy::from_aligned_ptr(ptr, layout) - } - }) - } - /// Computes a place. You should only use this if you intend to write into this /// place; for reading, a more efficient alternative is `eval_place_for_read`. pub fn eval_place( &mut self, place: &mir::Place<'tcx>, ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { - use rustc::mir::PlaceBase; - - let mut place_ty = match &place.base { - PlaceBase::Local(mir::RETURN_PLACE) => { + let mut place_ty = match place.local { + mir::RETURN_PLACE => { // `return_place` has the *caller* layout, but we want to use our // `layout to verify our assumption. The caller will validate // their layout on return. @@ -697,12 +646,11 @@ where ))?, } } - PlaceBase::Local(local) => PlaceTy { + local => PlaceTy { // This works even for dead/uninitialized locals; we check further when writing - place: Place::Local { frame: self.cur_frame(), local: *local }, - layout: self.layout_of_local(self.frame(), *local, None)?, + place: Place::Local { frame: self.cur_frame(), local: local }, + layout: self.layout_of_local(self.frame(), local, None)?, }, - PlaceBase::Static(place_static) => self.eval_static_to_mplace(&place_static)?.into(), }; for elem in place.projection.iter() { diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 511a5fbc61795..f5f00c9343561 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -182,11 +182,11 @@ use rustc::mir::interpret::{AllocId, ConstValue}; use rustc::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar}; use rustc::mir::mono::{InstantiationMode, MonoItem}; use rustc::mir::visit::Visitor as MirVisitor; -use rustc::mir::{self, Location, PlaceBase, Static, StaticKind}; +use rustc::mir::{self, Local, Location}; use rustc::session::config::EntryFnType; use rustc::ty::adjustment::{CustomCoerceUnsized, PointerCast}; use rustc::ty::print::obsolete::DefPathBasedNames; -use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef}; +use rustc::ty::subst::{InternalSubsts, SubstsRef}; use rustc::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator}; @@ -642,39 +642,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { fn visit_place_base( &mut self, - place_base: &mir::PlaceBase<'tcx>, + _place_local: &Local, _context: mir::visit::PlaceContext, - location: Location, + _location: Location, ) { - match place_base { - PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => { - debug!("visiting static {:?} @ {:?}", def_id, location); - - let tcx = self.tcx; - let instance = Instance::mono(tcx, *def_id); - if should_monomorphize_locally(tcx, &instance) { - self.output.push(MonoItem::Static(*def_id)); - } - } - PlaceBase::Static(box Static { - kind: StaticKind::Promoted(promoted, substs), - def_id, - .. - }) => { - let instance = Instance::new(*def_id, substs.subst(self.tcx, self.param_substs)); - match self.tcx.const_eval_promoted(instance, *promoted) { - Ok(val) => collect_const(self.tcx, val, substs, self.output), - Err(ErrorHandled::Reported) => {} - Err(ErrorHandled::TooGeneric) => { - let span = self.tcx.promoted_mir(*def_id)[*promoted].span; - span_bug!(span, "collection encountered polymorphic constant") - } - } - } - PlaceBase::Local(_) => { - // Locals have no relevance for collector. - } - } } } @@ -1249,8 +1220,8 @@ fn collect_const<'tcx>( collect_miri(tcx, id, output); } } - ty::ConstKind::Unevaluated(def_id, substs) => { - match tcx.const_eval_resolve(param_env, def_id, substs, None) { + ty::ConstKind::Unevaluated(def_id, substs, promoted) => { + match tcx.const_eval_resolve(param_env, def_id, substs, promoted, None) { Ok(val) => collect_const(tcx, val, param_substs, output), Err(ErrorHandled::Reported) => {} Err(ErrorHandled::TooGeneric) => { diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs index 0799cc2374ad4..577736f9bd11d 100644 --- a/src/librustc_mir/transform/check_consts/qualifs.rs +++ b/src/librustc_mir/transform/check_consts/qualifs.rs @@ -38,12 +38,15 @@ pub trait Qualif { place: PlaceRef<'_, 'tcx>, ) -> bool { if let [proj_base @ .., elem] = place.projection { - let base_qualif = - Self::in_place(cx, per_local, PlaceRef { base: place.base, projection: proj_base }); + let base_qualif = Self::in_place( + cx, + per_local, + PlaceRef { local: place.local, projection: proj_base }, + ); let qualif = base_qualif && Self::in_any_value_of_ty( cx, - Place::ty_from(place.base, proj_base, *cx.body, cx.tcx) + Place::ty_from(place.local, proj_base, *cx.body, cx.tcx) .projection_ty(cx.tcx, elem) .ty, ); @@ -75,11 +78,8 @@ pub trait Qualif { place: PlaceRef<'_, 'tcx>, ) -> bool { match place { - PlaceRef { base: PlaceBase::Local(local), projection: [] } => per_local(*local), - PlaceRef { base: PlaceBase::Static(_), projection: [] } => { - bug!("qualifying already promoted MIR") - } - PlaceRef { base: _, projection: [.., _] } => Self::in_projection(cx, per_local, place), + PlaceRef { local, projection: [] } => per_local(*local), + PlaceRef { local: _, projection: [.., _] } => Self::in_projection(cx, per_local, place), } } @@ -102,7 +102,9 @@ pub trait Qualif { // Note: this uses `constant.literal.ty` which is a reference or pointer to the // type of the actual `static` item. Self::in_any_value_of_ty(cx, constant.literal.ty) - } else if let ty::ConstKind::Unevaluated(def_id, _) = constant.literal.val { + } else if let ty::ConstKind::Unevaluated(def_id, _, promoted) = constant.literal.val + { + assert!(promoted.is_none()); // Don't peek inside trait associated constants. if cx.tcx.trait_of_item(def_id).is_some() { Self::in_any_value_of_ty(cx, constant.literal.ty) @@ -147,12 +149,12 @@ pub trait Qualif { Rvalue::Ref(_, _, ref place) | Rvalue::AddressOf(_, ref place) => { // Special-case reborrows to be more like a copy of the reference. if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() { - let base_ty = Place::ty_from(&place.base, proj_base, *cx.body, cx.tcx).ty; + let base_ty = Place::ty_from(&place.local, proj_base, *cx.body, cx.tcx).ty; if let ty::Ref(..) = base_ty.kind { return Self::in_place( cx, per_local, - PlaceRef { base: &place.base, projection: proj_base }, + PlaceRef { local: &place.local, projection: proj_base }, ); } } diff --git a/src/librustc_mir/transform/check_consts/resolver.rs b/src/librustc_mir/transform/check_consts/resolver.rs index 207683054f925..c445568dd2a9b 100644 --- a/src/librustc_mir/transform/check_consts/resolver.rs +++ b/src/librustc_mir/transform/check_consts/resolver.rs @@ -47,15 +47,15 @@ where debug_assert!(!place.is_indirect()); match (value, place.as_ref()) { - (true, mir::PlaceRef { base: &mir::PlaceBase::Local(local), .. }) => { - self.qualifs_per_local.insert(local); + (true, mir::PlaceRef { local, .. }) => { + self.qualifs_per_local.insert(*local); } // For now, we do not clear the qualif if a local is overwritten in full by // an unqualified rvalue (e.g. `y = 5`). This is to be consistent // with aggregates where we overwrite all fields with assignments, which would not // get this feature. - (false, mir::PlaceRef { base: &mir::PlaceBase::Local(_local), projection: &[] }) => { + (false, mir::PlaceRef { local: _, projection: &[] }) => { // self.qualifs_per_local.remove(*local); } diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index b818397247624..10a4b7d92b764 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -304,8 +304,8 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { PlaceContext::MutatingUse(MutatingUseContext::Borrow) } }; - self.visit_place_base(&place.base, ctx, location); - self.visit_projection(&place.base, reborrowed_proj, ctx, location); + self.visit_place_base(&place.local, ctx, location); + self.visit_projection(&place.local, reborrowed_proj, ctx, location); return; } } @@ -317,8 +317,8 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { } Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf), }; - self.visit_place_base(&place.base, ctx, location); - self.visit_projection(&place.base, reborrowed_proj, ctx, location); + self.visit_place_base(&place.local, ctx, location); + self.visit_projection(&place.local, reborrowed_proj, ctx, location); return; } } @@ -369,15 +369,6 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { Rvalue::AddressOf(Mutability::Mut, _) => self.check_op(ops::MutAddressOf), - // At the moment, `PlaceBase::Static` is only used for promoted MIR. - Rvalue::Ref(_, BorrowKind::Shared, ref place) - | Rvalue::Ref(_, BorrowKind::Shallow, ref place) - | Rvalue::AddressOf(Mutability::Not, ref place) - if matches!(place.base, PlaceBase::Static(_)) => - { - bug!("Saw a promoted during const-checking, which must run before promotion") - } - Rvalue::Ref(_, BorrowKind::Shared, ref place) | Rvalue::Ref(_, BorrowKind::Shallow, ref place) => { self.check_immutable_borrow_like(location, place) @@ -421,26 +412,14 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { } } - fn visit_place_base( - &mut self, - place_base: &PlaceBase<'tcx>, - context: PlaceContext, - location: Location, - ) { + fn visit_place_base(&mut self, place_local: &Local, context: PlaceContext, location: Location) { trace!( - "visit_place_base: place_base={:?} context={:?} location={:?}", - place_base, + "visit_place_base: place_local={:?} context={:?} location={:?}", + place_local, context, location, ); - self.super_place_base(place_base, context, location); - - match place_base { - PlaceBase::Local(_) => {} - PlaceBase::Static(_) => { - bug!("Promotion must be run after const validation"); - } - } + self.super_place_base(place_local, context, location); } fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) { @@ -453,30 +432,30 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { } fn visit_projection_elem( &mut self, - place_base: &PlaceBase<'tcx>, + place_local: &Local, proj_base: &[PlaceElem<'tcx>], elem: &PlaceElem<'tcx>, context: PlaceContext, location: Location, ) { trace!( - "visit_projection_elem: place_base={:?} proj_base={:?} elem={:?} \ + "visit_projection_elem: place_local={:?} proj_base={:?} elem={:?} \ context={:?} location={:?}", - place_base, + place_local, proj_base, elem, context, location, ); - self.super_projection_elem(place_base, proj_base, elem, context, location); + self.super_projection_elem(place_local, proj_base, elem, context, location); match elem { ProjectionElem::Deref => { - let base_ty = Place::ty_from(place_base, proj_base, *self.body, self.tcx).ty; + let base_ty = Place::ty_from(place_local, proj_base, *self.body, self.tcx).ty; if let ty::RawPtr(_) = base_ty.kind { if proj_base.is_empty() { - if let (PlaceBase::Local(local), []) = (place_base, proj_base) { + if let (local, []) = (place_local, proj_base) { let decl = &self.body.local_decls[*local]; if let LocalInfo::StaticRef { def_id, .. } = decl.local_info { let span = decl.source_info.span; @@ -497,7 +476,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { | ProjectionElem::Subslice { .. } | ProjectionElem::Field(..) | ProjectionElem::Index(_) => { - let base_ty = Place::ty_from(place_base, proj_base, *self.body, self.tcx).ty; + let base_ty = Place::ty_from(place_local, proj_base, *self.body, self.tcx).ty; match base_ty.ty_adt_def() { Some(def) if def.is_union() => { self.check_op(ops::UnionAccess); @@ -681,17 +660,15 @@ fn place_as_reborrow( // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const` // that points to the allocation for the static. Don't treat these as reborrows. - if let PlaceBase::Local(local) = place.base { - if body.local_decls[local].is_ref_to_static() { - return None; - } + if body.local_decls[place.local].is_ref_to_static() { + return None; } // Ensure the type being derefed is a reference and not a raw pointer. // // This is sufficient to prevent an access to a `static mut` from being marked as a // reborrow, even if the check above were to disappear. - let inner_ty = Place::ty_from(&place.base, inner, body, tcx).ty; + let inner_ty = Place::ty_from(&place.local, inner, body, tcx).ty; match inner_ty.kind { ty::Ref(..) => Some(inner), _ => None, diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 02c54803842f0..934b262c2f9cb 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -190,18 +190,6 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { - match place.base { - PlaceBase::Local(..) => { - // Locals are safe. - } - PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => { - bug!("unsafety checking should happen before promotion"); - } - PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => { - bug!("StaticKind::Static should not exist"); - } - } - for (i, elem) in place.projection.iter().enumerate() { let proj_base = &place.projection[..i]; @@ -229,7 +217,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } } let is_borrow_of_interior_mut = context.is_borrow() - && !Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty.is_freeze( + && !Place::ty_from(&place.local, proj_base, self.body, self.tcx).ty.is_freeze( self.tcx, self.param_env, self.source_info.span, @@ -244,7 +232,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { self.check_mut_borrowing_layout_constrained_field(place, context.is_mutating_use()); } let old_source_info = self.source_info; - if let (PlaceBase::Local(local), []) = (&place.base, proj_base) { + if let (local, []) = (&place.local, proj_base) { let decl = &self.body.local_decls[*local]; if decl.internal { // Internal locals are used in the `move_val_init` desugaring. @@ -272,7 +260,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } } } - let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty; + let base_ty = Place::ty_from(&place.local, proj_base, self.body, self.tcx).ty; match base_ty.kind { ty::RawPtr(..) => self.require_unsafe( "dereference of raw pointer", @@ -426,7 +414,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { match elem { ProjectionElem::Field(..) => { let ty = - Place::ty_from(&place.base, proj_base, &self.body.local_decls, self.tcx).ty; + Place::ty_from(&place.local, proj_base, &self.body.local_decls, self.tcx) + .ty; match ty.kind { ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) { (Bound::Unbounded, Bound::Unbounded) => {} diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index d5d56b36cf4c3..1d5a643484a73 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -10,15 +10,15 @@ use rustc::mir::visit::{ }; use rustc::mir::{ read_only, AggregateKind, BasicBlock, BinOp, Body, BodyAndCache, ClearCrossCrate, Constant, - Local, LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, ReadOnlyBodyAndCache, Rvalue, + Local, LocalDecl, LocalKind, Location, Operand, Place, ReadOnlyBodyAndCache, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE, }; use rustc::ty::layout::{ HasDataLayout, HasTyCtxt, LayoutError, LayoutOf, Size, TargetDataLayout, TyLayout, }; -use rustc::ty::subst::InternalSubsts; -use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::subst::{InternalSubsts, Subst}; +use rustc::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -33,7 +33,6 @@ use crate::interpret::{ LocalState, LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer, ScalarMaybeUndef, StackPopCleanup, }; -use crate::rustc::ty::subst::Subst; use crate::transform::{MirPass, MirSource}; /// The maximum number of bytes that we'll allocate space for a return value. @@ -432,12 +431,25 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { source_info: SourceInfo, ) -> Option> { self.ecx.tcx.span = c.span; + + // FIXME we need to revisit this for #67176 + if c.needs_subst() { + return None; + } + match self.ecx.eval_const_to_op(c.literal, None) { Ok(op) => Some(op), Err(error) => { let err = error_to_const_error(&self.ecx, error); - match self.lint_root(source_info) { - Some(lint_root) if c.literal.needs_subst() => { + if let Some(lint_root) = self.lint_root(source_info) { + let lint_only = match c.literal.val { + // Promoteds must lint and not error as the user didn't ask for them + ConstKind::Unevaluated(_, _, Some(_)) => true, + // Out of backwards compatibility we cannot report hard errors in unused + // generic functions using associated constants of the generic parameters. + _ => c.literal.needs_subst(), + }; + if lint_only { // Out of backwards compatibility we cannot report hard errors in unused // generic functions using associated constants of the generic parameters. err.report_as_lint( @@ -446,10 +458,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { lint_root, Some(c.span), ); - } - _ => { + } else { err.report_as_error(self.ecx.tcx, "erroneous constant used"); } + } else { + err.report_as_error(self.ecx.tcx, "erroneous constant used"); } None } @@ -552,6 +565,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return None; } + // FIXME we need to revisit this for #67176 + if rvalue.needs_subst() { + return None; + } + let overflow_check = self.tcx.sess.overflow_checks(); // Perform any special handling for specific Rvalue types. @@ -708,7 +726,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { )) => l.is_bits() && r.is_bits(), interpret::Operand::Indirect(_) if mir_opt_level >= 2 => { let mplace = op.assert_mem_place(&self.ecx); - intern_const_alloc_recursive(&mut self.ecx, None, mplace) + intern_const_alloc_recursive(&mut self.ecx, None, mplace, false) .expect("failed to intern alloc"); true } @@ -866,9 +884,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { // doesn't use the invalid value match cond { Operand::Move(ref place) | Operand::Copy(ref place) => { - if let PlaceBase::Local(local) = place.base { - self.remove_const(local); - } + self.remove_const(place.local); } Operand::Constant(_) => {} } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 96fb992e53b23..825ac4a28d869 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -112,17 +112,17 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor<'tcx> { } fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { - if place.base == PlaceBase::Local(self_arg()) { + if place.local == self_arg() { replace_base( place, Place { - base: PlaceBase::Local(self_arg()), + local: self_arg(), projection: self.tcx().intern_place_elems(&vec![ProjectionElem::Deref]), }, self.tcx, ); } else { - self.visit_place_base(&mut place.base, context, location); + self.visit_place_base(&mut place.local, context, location); for elem in place.projection.iter() { if let PlaceElem::Index(local) = elem { @@ -148,11 +148,11 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { } fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { - if place.base == PlaceBase::Local(self_arg()) { + if place.local == self_arg() { replace_base( place, Place { - base: PlaceBase::Local(self_arg()), + local: self_arg(), projection: self.tcx().intern_place_elems(&vec![ProjectionElem::Field( Field::new(0), self.ref_gen_ty, @@ -161,7 +161,7 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { self.tcx, ); } else { - self.visit_place_base(&mut place.base, context, location); + self.visit_place_base(&mut place.local, context, location); for elem in place.projection.iter() { if let PlaceElem::Index(local) = elem { @@ -173,7 +173,7 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { } fn replace_base<'tcx>(place: &mut Place<'tcx>, new_base: Place<'tcx>, tcx: TyCtxt<'tcx>) { - place.base = new_base.base; + place.local = new_base.local; let mut new_projection = new_base.projection.to_vec(); new_projection.append(&mut place.projection.to_vec()); @@ -236,7 +236,7 @@ impl TransformVisitor<'tcx> { let mut projection = base.projection.to_vec(); projection.push(ProjectionElem::Field(Field::new(idx), ty)); - Place { base: base.base, projection: self.tcx.intern_place_elems(&projection) } + Place { local: base.local, projection: self.tcx.intern_place_elems(&projection) } } // Create a statement which changes the discriminant @@ -275,20 +275,15 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> { assert_eq!(self.remap.get(local), None); } - fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { - if let PlaceBase::Local(l) = place.base { - // Replace an Local in the remap with a generator struct access - if let Some(&(ty, variant_index, idx)) = self.remap.get(&l) { - replace_base(place, self.make_field(variant_index, idx, ty), self.tcx); - } - } else { - self.visit_place_base(&mut place.base, context, location); - - for elem in place.projection.iter() { - if let PlaceElem::Index(local) = elem { - assert_ne!(*local, self_arg()); - } - } + fn visit_place( + &mut self, + place: &mut Place<'tcx>, + _context: PlaceContext, + _location: Location, + ) { + // Replace an Local in the remap with a generator struct access + if let Some(&(ty, variant_index, idx)) = self.remap.get(&place.local) { + replace_base(place, self.make_field(variant_index, idx, ty), self.tcx); } } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 3c5d2c9f310bb..2dd00fe2fee19 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -430,12 +430,7 @@ impl Inliner<'tcx> { } } - match place.base { - // Static variables need a borrow because the callee - // might modify the same static. - PlaceBase::Static(_) => true, - _ => false, - } + false } let dest = if dest_needs_borrow(&destination.0) { @@ -647,10 +642,7 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> { fn make_integrate_local(&self, local: &Local) -> Local { if *local == RETURN_PLACE { - match self.destination.base { - PlaceBase::Local(l) => return l, - PlaceBase::Static(ref s) => bug!("Return place is {:?}, not local", s), - } + return self.destination.local; } let idx = local.index() - 1; @@ -672,19 +664,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { } fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { - match &mut place.base { - PlaceBase::Static(_) => {} - PlaceBase::Local(l) => { - // If this is the `RETURN_PLACE`, we need to rebase any projections onto it. - let dest_proj_len = self.destination.projection.len(); - if *l == RETURN_PLACE && dest_proj_len > 0 { - let mut projs = Vec::with_capacity(dest_proj_len + place.projection.len()); - projs.extend(self.destination.projection); - projs.extend(place.projection); - - place.projection = self.tcx.intern_place_elems(&*projs); - } - } + // If this is the `RETURN_PLACE`, we need to rebase any projections onto it. + let dest_proj_len = self.destination.projection.len(); + if place.local == RETURN_PLACE && dest_proj_len > 0 { + let mut projs = Vec::with_capacity(dest_proj_len + place.projection.len()); + projs.extend(self.destination.projection); + projs.extend(place.projection); + + place.projection = self.tcx.intern_place_elems(&*projs); } // Handles integrating any locals that occur in the base // or projections diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index a2f3fcea7569a..69eedb1ae1876 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -3,7 +3,7 @@ use crate::transform::{MirPass, MirSource}; use rustc::mir::visit::{MutVisitor, Visitor}; use rustc::mir::{ - read_only, Body, BodyAndCache, Constant, Local, Location, Operand, Place, PlaceBase, PlaceRef, + read_only, Body, BodyAndCache, Constant, Local, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, }; use rustc::ty::{self, TyCtxt}; @@ -55,7 +55,7 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { Place { // Replace with dummy - base: mem::replace(&mut place.base, PlaceBase::Local(Local::new(0))), + local: mem::replace(&mut place.local, Local::new(0)), projection: self.tcx().intern_place_elems(proj_l), } } else { @@ -92,10 +92,10 @@ impl OptimizationFinder<'b, 'tcx> { impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { if let Rvalue::Ref(_, _, place) = rvalue { - if let PlaceRef { base, projection: &[ref proj_base @ .., ProjectionElem::Deref] } = + if let PlaceRef { local, projection: &[ref proj_base @ .., ProjectionElem::Deref] } = place.as_ref() { - if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() { + if Place::ty_from(local, proj_base, self.body, self.tcx).ty.is_region_ptr() { self.optimizations.and_stars.insert(location); } } diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 00a39905c0232..f058ac834ef34 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -27,7 +27,7 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_target::spec::abi::Abi; use std::cell::Cell; -use std::{iter, mem, usize}; +use std::{cmp, iter, mem, usize}; use crate::const_eval::{is_const_fn, is_unstable_const_fn}; use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstKind, Item}; @@ -39,7 +39,7 @@ use crate::transform::{MirPass, MirSource}; /// errors when promotion of `#[rustc_args_required_const]` arguments fails. /// /// After this pass is run, `promoted_fragments` will hold the MIR body corresponding to each -/// newly created `StaticKind::Promoted`. +/// newly created `Constant`. #[derive(Default)] pub struct PromoteTemps<'tcx> { pub promoted_fragments: Cell>>, @@ -308,18 +308,14 @@ impl<'tcx> Validator<'_, 'tcx> { // We can only promote interior borrows of promotable temps (non-temps // don't get promoted anyway). - let base = match place.base { - PlaceBase::Local(local) => local, - _ => return Err(Unpromotable), - }; - self.validate_local(base)?; + self.validate_local(place.local)?; if place.projection.contains(&ProjectionElem::Deref) { return Err(Unpromotable); } let mut has_mut_interior = - self.qualif_local::(base); + self.qualif_local::(place.local); // HACK(eddyb) this should compute the same thing as // `::in_projection` from // `check_consts::qualifs` but without recursion. @@ -333,7 +329,7 @@ impl<'tcx> Validator<'_, 'tcx> { // FIXME(eddyb) this is probably excessive, with // the exception of `union` member accesses. let ty = - Place::ty_from(&place.base, proj_base, *self.body, self.tcx) + Place::ty_from(&place.local, proj_base, *self.body, self.tcx) .projection_ty(self.tcx, elem) .ty; if ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) { @@ -349,7 +345,7 @@ impl<'tcx> Validator<'_, 'tcx> { if has_mut_interior { return Err(Unpromotable); } - if self.qualif_local::(base) { + if self.qualif_local::(place.local) { return Err(Unpromotable); } @@ -479,13 +475,8 @@ impl<'tcx> Validator<'_, 'tcx> { fn validate_place(&self, place: PlaceRef<'_, 'tcx>) -> Result<(), Unpromotable> { match place { - PlaceRef { base: PlaceBase::Local(local), projection: [] } => { - self.validate_local(*local) - } - PlaceRef { base: PlaceBase::Static(_), projection: [] } => { - bug!("qualifying already promoted MIR") - } - PlaceRef { base: _, projection: [proj_base @ .., elem] } => { + PlaceRef { local, projection: [] } => self.validate_local(*local), + PlaceRef { local: _, projection: [proj_base @ .., elem] } => { match *elem { ProjectionElem::Deref | ProjectionElem::Downcast(..) => { return Err(Unpromotable); @@ -500,7 +491,7 @@ impl<'tcx> Validator<'_, 'tcx> { ProjectionElem::Field(..) => { if self.const_kind.is_none() { let base_ty = - Place::ty_from(place.base, proj_base, *self.body, self.tcx).ty; + Place::ty_from(place.local, proj_base, *self.body, self.tcx).ty; if let Some(def) = base_ty.ty_adt_def() { // No promotion of union field accesses. if def.is_union() { @@ -511,7 +502,7 @@ impl<'tcx> Validator<'_, 'tcx> { } } - self.validate_place(PlaceRef { base: place.base, projection: proj_base }) + self.validate_place(PlaceRef { local: place.local, projection: proj_base }) } } } @@ -598,10 +589,12 @@ impl<'tcx> Validator<'_, 'tcx> { // Raw reborrows can come from reference to pointer coercions, // so are allowed. if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() { - let base_ty = Place::ty_from(&place.base, proj_base, *self.body, self.tcx).ty; + let base_ty = Place::ty_from(&place.local, proj_base, *self.body, self.tcx).ty; if let ty::Ref(..) = base_ty.kind { - return self - .validate_place(PlaceRef { base: &place.base, projection: proj_base }); + return self.validate_place(PlaceRef { + local: &place.local, + projection: proj_base, + }); } } Err(Unpromotable) @@ -635,9 +628,9 @@ impl<'tcx> Validator<'_, 'tcx> { // Special-case reborrows to be more like a copy of the reference. let mut place = place.as_ref(); if let [proj_base @ .., ProjectionElem::Deref] = &place.projection { - let base_ty = Place::ty_from(&place.base, proj_base, *self.body, self.tcx).ty; + let base_ty = Place::ty_from(&place.local, proj_base, *self.body, self.tcx).ty; if let ty::Ref(..) = base_ty.kind { - place = PlaceRef { base: &place.base, projection: proj_base }; + place = PlaceRef { local: &place.local, projection: proj_base }; } } @@ -646,17 +639,15 @@ impl<'tcx> Validator<'_, 'tcx> { // HACK(eddyb) this should compute the same thing as // `::in_projection` from // `check_consts::qualifs` but without recursion. - let mut has_mut_interior = match place.base { - PlaceBase::Local(local) => self.qualif_local::(*local), - PlaceBase::Static(_) => false, - }; + let mut has_mut_interior = + self.qualif_local::(*place.local); if has_mut_interior { let mut place_projection = place.projection; // FIXME(eddyb) use a forward loop instead of a reverse one. while let [proj_base @ .., elem] = place_projection { // FIXME(eddyb) this is probably excessive, with // the exception of `union` member accesses. - let ty = Place::ty_from(place.base, proj_base, *self.body, self.tcx) + let ty = Place::ty_from(place.local, proj_base, *self.body, self.tcx) .projection_ty(self.tcx, elem) .ty; if ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) { @@ -761,6 +752,7 @@ struct Promoter<'a, 'tcx> { source: &'a mut BodyAndCache<'tcx>, promoted: BodyAndCache<'tcx>, temps: &'a mut IndexVec, + extra_statements: &'a mut Vec<(Location, Statement<'tcx>)>, /// If true, all nested temps are also kept in the /// source MIR, not moved to the promoted MIR. @@ -903,39 +895,76 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { candidate: Candidate, next_promoted_id: usize, ) -> Option> { - let mut operand = { + let mut rvalue = { let promoted = &mut self.promoted; let promoted_id = Promoted::new(next_promoted_id); let tcx = self.tcx; - let mut promoted_place = |ty, span| { + let mut promoted_operand = |ty, span| { promoted.span = span; promoted.local_decls[RETURN_PLACE] = LocalDecl::new_return_place(ty, span); - Place { - base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted( - promoted_id, + + Operand::Constant(Box::new(Constant { + span, + user_ty: None, + literal: tcx.mk_const(ty::Const { + ty, + val: ty::ConstKind::Unevaluated( + def_id, InternalSubsts::identity_for_item(tcx, def_id), + Some(promoted_id), ), - ty, - def_id, }), - projection: List::empty(), - } + })) }; let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut(); match candidate { Candidate::Ref(loc) => { let ref mut statement = blocks[loc.block].statements[loc.statement_index]; match statement.kind { - StatementKind::Assign(box (_, Rvalue::Ref(_, _, ref mut place))) => { + StatementKind::Assign(box ( + _, + Rvalue::Ref(ref mut region, borrow_kind, ref mut place), + )) => { // Use the underlying local for this (necessarily interior) borrow. - let ty = place.base.ty(local_decls).ty; + let ty = local_decls.local_decls()[place.local].ty; let span = statement.source_info.span; - Operand::Move(Place { - base: mem::replace(&mut place.base, promoted_place(ty, span).base), - projection: List::empty(), - }) + let ref_ty = tcx.mk_ref( + tcx.lifetimes.re_erased, + ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() }, + ); + + *region = tcx.lifetimes.re_erased; + + let mut projection = vec![PlaceElem::Deref]; + projection.extend(place.projection); + place.projection = tcx.intern_place_elems(&projection); + + // Create a temp to hold the promoted reference. + // This is because `*r` requires `r` to be a local, + // otherwise we would use the `promoted` directly. + let mut promoted_ref = LocalDecl::new_temp(ref_ty, span); + promoted_ref.source_info = statement.source_info; + let promoted_ref = local_decls.push(promoted_ref); + assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref); + + let promoted_ref_statement = Statement { + source_info: statement.source_info, + kind: StatementKind::Assign(Box::new(( + Place::from(promoted_ref), + Rvalue::Use(promoted_operand(ref_ty, span)), + ))), + }; + self.extra_statements.push((loc, promoted_ref_statement)); + + Rvalue::Ref( + tcx.lifetimes.re_erased, + borrow_kind, + Place { + local: mem::replace(&mut place.local, promoted_ref), + projection: List::empty(), + }, + ) } _ => bug!(), } @@ -946,7 +975,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { StatementKind::Assign(box (_, Rvalue::Repeat(ref mut operand, _))) => { let ty = operand.ty(local_decls, self.tcx); let span = statement.source_info.span; - mem::replace(operand, Operand::Copy(promoted_place(ty, span))) + + Rvalue::Use(mem::replace(operand, promoted_operand(ty, span))) } _ => bug!(), } @@ -957,8 +987,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { TerminatorKind::Call { ref mut args, .. } => { let ty = args[index].ty(local_decls, self.tcx); let span = terminator.source_info.span; - let operand = Operand::Copy(promoted_place(ty, span)); - mem::replace(&mut args[index], operand) + + Rvalue::Use(mem::replace(&mut args[index], promoted_operand(ty, span))) } // We expected a `TerminatorKind::Call` for which we'd like to promote an // argument. `qualify_consts` saw a `TerminatorKind::Call` here, but @@ -975,13 +1005,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { }; assert_eq!(self.new_block(), START_BLOCK); - self.visit_operand( - &mut operand, + self.visit_rvalue( + &mut rvalue, Location { block: BasicBlock::new(0), statement_index: usize::MAX }, ); let span = self.promoted.span; - self.assign(RETURN_PLACE, Rvalue::Use(operand), span); + self.assign(RETURN_PLACE, rvalue, span); Some(self.promoted) } } @@ -1020,6 +1050,7 @@ pub fn promote_candidates<'tcx>( let mut promotions = IndexVec::new(); + let mut extra_statements = vec![]; for candidate in candidates.into_iter().rev() { match candidate { Candidate::Repeat(Location { block, statement_index }) @@ -1043,23 +1074,27 @@ pub fn promote_candidates<'tcx>( let initial_locals = iter::once(LocalDecl::new_return_place(tcx.types.never, body.span)).collect(); + let mut promoted = Body::new( + IndexVec::new(), + // FIXME: maybe try to filter this to avoid blowing up + // memory usage? + body.source_scopes.clone(), + initial_locals, + IndexVec::new(), + 0, + vec![], + body.span, + vec![], + body.generator_kind, + ); + promoted.ignore_interior_mut_in_const_validation = true; + let promoter = Promoter { - promoted: BodyAndCache::new(Body::new( - IndexVec::new(), - // FIXME: maybe try to filter this to avoid blowing up - // memory usage? - body.source_scopes.clone(), - initial_locals, - IndexVec::new(), - 0, - vec![], - body.span, - vec![], - body.generator_kind, - )), + promoted: BodyAndCache::new(promoted), tcx, source: body, temps: &mut temps, + extra_statements: &mut extra_statements, keep_original: false, }; @@ -1069,6 +1104,13 @@ pub fn promote_candidates<'tcx>( } } + // Insert each of `extra_statements` before its indicated location, which + // has to be done in reverse location order, to not invalidate the rest. + extra_statements.sort_by_key(|&(loc, _)| cmp::Reverse(loc)); + for (loc, statement) in extra_statements { + body[loc.block].statements.insert(loc.statement_index, statement); + } + // Eliminate assignments to, and drops of promoted temps. let promoted = |index: Local| temps[index] == TempState::PromotedOut; for block in body.basic_blocks_mut() { diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index c2c1625001d0f..7034556740849 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -261,7 +261,7 @@ fn check_place( ProjectionElem::Downcast(_symbol, _variant_index) => {} ProjectionElem::Field(..) => { - let base_ty = Place::ty_from(&place.base, &proj_base, body, tcx).ty; + let base_ty = Place::ty_from(&place.local, &proj_base, body, tcx).ty; if let Some(def) = base_ty.ty_adt_def() { // No union field accesses in `const fn` if def.is_union() { diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index fb7f4fac4dca4..ddf8d73e5481f 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -388,13 +388,7 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { // Remove unnecessary StorageLive and StorageDead annotations. data.statements.retain(|stmt| match &stmt.kind { StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => self.map[*l].is_some(), - StatementKind::Assign(box (place, _)) => { - if let PlaceBase::Local(local) = place.base { - self.map[local].is_some() - } else { - true - } - } + StatementKind::Assign(box (place, _)) => self.map[place.local].is_some(), _ => true, }); self.super_basic_block_data(block, data); diff --git a/src/librustc_mir/transform/simplify_try.rs b/src/librustc_mir/transform/simplify_try.rs index 3b8871f86b289..e733b0a5b5928 100644 --- a/src/librustc_mir/transform/simplify_try.rs +++ b/src/librustc_mir/transform/simplify_try.rs @@ -137,9 +137,9 @@ struct VarField<'tcx> { fn match_variant_field_place<'tcx>(place: &Place<'tcx>) -> Option<(Local, VarField<'tcx>)> { match place.as_ref() { PlaceRef { - base: &PlaceBase::Local(local), + local, projection: &[ProjectionElem::Downcast(_, var_idx), ProjectionElem::Field(field, ty)], - } => Some((local, VarField { field, field_ty: ty, var_idx })), + } => Some((*local, VarField { field, field_ty: ty, var_idx })), _ => None, } } diff --git a/src/librustc_mir/util/alignment.rs b/src/librustc_mir/util/alignment.rs index 70d6aaf70eb09..e17c7a80f1a76 100644 --- a/src/librustc_mir/util/alignment.rs +++ b/src/librustc_mir/util/alignment.rs @@ -46,7 +46,7 @@ where // encountered a Deref, which is ABI-aligned ProjectionElem::Deref => break, ProjectionElem::Field(..) => { - let ty = Place::ty_from(&place.base, proj_base, local_decls, tcx).ty; + let ty = Place::ty_from(&place.local, proj_base, local_decls, tcx).ty; match ty.kind { ty::Adt(def, _) if def.repr.packed() => return true, _ => {} diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index c15bcd81443d6..dae394b8f4bd4 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -2700,7 +2700,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let def_id = tcx.hir().local_def_id(ast_const.hir_id); let mut const_ = ty::Const { - val: ty::ConstKind::Unevaluated(def_id, InternalSubsts::identity_for_item(tcx, def_id)), + val: ty::ConstKind::Unevaluated( + def_id, + InternalSubsts::identity_for_item(tcx, def_id), + None, + ), ty, }; diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 874cb9b8a5c9e..8058536d60b31 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -460,12 +460,16 @@ pub fn name_from_pat(p: &hir::Pat) -> String { pub fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String { match n.val { - ty::ConstKind::Unevaluated(def_id, _) => { - if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) { + ty::ConstKind::Unevaluated(def_id, _, promoted) => { + let mut s = if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) { print_const_expr(cx, cx.tcx.hir().body_owned_by(hir_id)) } else { inline::print_inlined_const(cx, def_id) + }; + if let Some(promoted) = promoted { + s.push_str(&format!("::{:?}", promoted)) } + s } _ => { let mut s = n.to_string(); diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs index 7d65ad1435e12..a89ecdfd3a901 100644 --- a/src/test/codegen/consts.rs +++ b/src/test/codegen/consts.rs @@ -14,10 +14,9 @@ // This checks the constants from {low,high}_align_const, they share the same // constant, but the alignment differs, so the higher one should be used -// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}}, align 4 +// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}} getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* @2, i32 0, i32 0, i32 0), {{.*}}, #[derive(Copy, Clone)] - // repr(i16) is required for the {low,high}_align_const test #[repr(i16)] pub enum E { @@ -31,7 +30,7 @@ pub static STATIC: E = E::A(0); // CHECK-LABEL: @static_enum_const #[no_mangle] pub fn static_enum_const() -> E { - STATIC + STATIC } // CHECK-LABEL: @inline_enum_const @@ -43,15 +42,15 @@ pub fn inline_enum_const() -> E { // CHECK-LABEL: @low_align_const #[no_mangle] pub fn low_align_const() -> E { -// Check that low_align_const and high_align_const use the same constant -// CHECK: i8* align 2 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), + // Check that low_align_const and high_align_const use the same constant + // CHECK: load %"E"*, %"E"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E"**), *&E::A(0) } // CHECK-LABEL: @high_align_const #[no_mangle] pub fn high_align_const() -> E { -// Check that low_align_const and high_align_const use the same constant -// CHECK: i8* align 4 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), + // Check that low_align_const and high_align_const use the same constant + // CHECK: load %"E"*, %"E"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E"**), *&E::A(0) } diff --git a/src/test/mir-opt/const-promotion-extern-static.rs b/src/test/mir-opt/const-promotion-extern-static.rs index d611ec22c38ec..3abc90e42e8ca 100644 --- a/src/test/mir-opt/const-promotion-extern-static.rs +++ b/src/test/mir-opt/const-promotion-extern-static.rs @@ -48,7 +48,8 @@ fn main() {} // START rustc.BAR.PromoteTemps.after.mir // bb0: { // ... -// _2 = &(promoted[0]: [&'static i32; 1]); +// _6 = const BAR::promoted[0]; +// _2 = &(*_6); // _1 = move _2 as &[&'static i32] (Pointer(Unsize)); // _0 = const core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // } @@ -60,7 +61,8 @@ fn main() {} // START rustc.FOO.PromoteTemps.after.mir // bb0: { // ... -// _2 = &(promoted[0]: [&'static i32; 1]); +// _6 = const FOO::promoted[0]; +// _2 = &(*_6); // _1 = move _2 as &[&'static i32] (Pointer(Unsize)); // _0 = const core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // } diff --git a/src/test/mir-opt/const_prop/ref_deref.rs b/src/test/mir-opt/const_prop/ref_deref.rs index d45ffdc877535..8b48296a5d911 100644 --- a/src/test/mir-opt/const_prop/ref_deref.rs +++ b/src/test/mir-opt/const_prop/ref_deref.rs @@ -3,10 +3,29 @@ fn main() { } // END RUST SOURCE +// START rustc.main.PromoteTemps.before.mir +// bb0: { +// ... +// _3 = const 4i32; +// _2 = &_3; +// _1 = (*_2); +// ... +//} +// END rustc.main.PromoteTemps.before.mir +// START rustc.main.PromoteTemps.after.mir +// bb0: { +// ... +// _4 = const main::promoted[0]; +// _2 = &(*_4); +// _1 = (*_2); +// ... +//} +// END rustc.main.PromoteTemps.after.mir // START rustc.main.ConstProp.before.mir // bb0: { // ... -// _2 = &(promoted[0]: i32); +// _4 = const main::promoted[0]; +// _2 = _4; // _1 = (*_2); // ... //} @@ -14,7 +33,8 @@ fn main() { // START rustc.main.ConstProp.after.mir // bb0: { // ... -// _2 = &(promoted[0]: i32); +// _4 = const main::promoted[0]; +// _2 = _4; // _1 = const 4i32; // ... // } diff --git a/src/test/mir-opt/const_prop/ref_deref_project.rs b/src/test/mir-opt/const_prop/ref_deref_project.rs new file mode 100644 index 0000000000000..5808a8be176d4 --- /dev/null +++ b/src/test/mir-opt/const_prop/ref_deref_project.rs @@ -0,0 +1,41 @@ +fn main() { + *(&(4, 5).1); +} + +// END RUST SOURCE +// START rustc.main.PromoteTemps.before.mir +// bb0: { +// ... +// _3 = (const 4i32, const 5i32); +// _2 = &(_3.1: i32); +// _1 = (*_2); +// ... +//} +// END rustc.main.PromoteTemps.before.mir +// START rustc.main.PromoteTemps.after.mir +// bb0: { +// ... +// _4 = const main::promoted[0]; +// _2 = &((*_4).1: i32); +// _1 = (*_2); +// ... +//} +// END rustc.main.PromoteTemps.after.mir +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _4 = const main::promoted[0]; +// _2 = &((*_4).1: i32); +// _1 = (*_2); +// ... +//} +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _4 = const main::promoted[0]; +// _2 = &((*_4).1: i32); +// _1 = const 5i32; +// ... +// } +// END rustc.main.ConstProp.after.mir diff --git a/src/test/mir-opt/const_prop/slice_len.rs b/src/test/mir-opt/const_prop/slice_len.rs index d6ff76b34b9b5..43813e43d3681 100644 --- a/src/test/mir-opt/const_prop/slice_len.rs +++ b/src/test/mir-opt/const_prop/slice_len.rs @@ -6,7 +6,8 @@ fn main() { // START rustc.main.ConstProp.before.mir // bb0: { // ... -// _4 = &(promoted[0]: [u32; 3]); +// _9 = const main::promoted[0]; +// _4 = _9; // _3 = _4; // _2 = move _3 as &[u32] (Pointer(Unsize)); // ... @@ -24,7 +25,8 @@ fn main() { // START rustc.main.ConstProp.after.mir // bb0: { // ... -// _4 = &(promoted[0]: [u32; 3]); +// _9 = const main::promoted[0]; +// _4 = _9; // _3 = _4; // _2 = move _3 as &[u32] (Pointer(Unsize)); // ... diff --git a/src/test/mir-opt/inline/inline-retag.rs b/src/test/mir-opt/inline/inline-retag.rs index 6cdbcfdb0add7..7b78fc339f2c1 100644 --- a/src/test/mir-opt/inline/inline-retag.rs +++ b/src/test/mir-opt/inline/inline-retag.rs @@ -25,11 +25,11 @@ fn foo(x: &i32, y: &i32) -> bool { // ... // Retag(_3); // Retag(_6); -// StorageLive(_9); -// _9 = (*_3); -// StorageLive(_10); -// _10 = (*_6); -// _0 = Eq(move _9, move _10); +// StorageLive(_11); +// _11 = (*_3); +// StorageLive(_12); +// _12 = (*_6); +// _0 = Eq(move _11, move _12); // ... // return; // } diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index 648856b5523d3..2c20c35e4a491 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -65,7 +65,8 @@ fn main() { // } // bb6: { // binding1 and guard // StorageLive(_6); -// _6 = &(((promoted[0]: std::option::Option) as Some).0: i32); +// _11 = const full_tested_match::promoted[0]; +// _6 = &(((*_11) as Some).0: i32); // _4 = &shallow _2; // StorageLive(_7); // _7 = const guard() -> [return: bb7, unwind: bb1]; diff --git a/src/test/ui/consts/array-literal-index-oob.rs b/src/test/ui/consts/array-literal-index-oob.rs index 1de6bafd293cf..64aeb46894d16 100644 --- a/src/test/ui/consts/array-literal-index-oob.rs +++ b/src/test/ui/consts/array-literal-index-oob.rs @@ -1,7 +1,10 @@ -// build-fail +// build-pass + +#![warn(const_err)] fn main() { - &{[1, 2, 3][4]}; - //~^ ERROR index out of bounds - //~| ERROR reaching this expression at runtime will panic or abort + &{ [1, 2, 3][4] }; + //~^ WARN index out of bounds + //~| WARN reaching this expression at runtime will panic or abort + //~| WARN erroneous constant used [const_err] } diff --git a/src/test/ui/consts/array-literal-index-oob.stderr b/src/test/ui/consts/array-literal-index-oob.stderr index f3ef16659dd3e..50ad8e83e905c 100644 --- a/src/test/ui/consts/array-literal-index-oob.stderr +++ b/src/test/ui/consts/array-literal-index-oob.stderr @@ -1,18 +1,26 @@ -error: index out of bounds: the len is 3 but the index is 4 - --> $DIR/array-literal-index-oob.rs:4:7 +warning: index out of bounds: the len is 3 but the index is 4 + --> $DIR/array-literal-index-oob.rs:6:8 | -LL | &{[1, 2, 3][4]}; - | ^^^^^^^^^^^^ +LL | &{ [1, 2, 3][4] }; + | ^^^^^^^^^^^^ | - = note: `#[deny(const_err)]` on by default +note: lint level defined here + --> $DIR/array-literal-index-oob.rs:3:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ -error: reaching this expression at runtime will panic or abort - --> $DIR/array-literal-index-oob.rs:4:7 +warning: reaching this expression at runtime will panic or abort + --> $DIR/array-literal-index-oob.rs:6:8 | -LL | &{[1, 2, 3][4]}; - | --^^^^^^^^^^^^- - | | - | indexing out of bounds: the len is 3 but the index is 4 +LL | &{ [1, 2, 3][4] }; + | ---^^^^^^^^^^^^-- + | | + | indexing out of bounds: the len is 3 but the index is 4 -error: aborting due to 2 previous errors +warning: erroneous constant used + --> $DIR/array-literal-index-oob.rs:6:5 + | +LL | &{ [1, 2, 3][4] }; + | ^^^^^^^^^^^^^^^^^ referenced constant has errors diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.rs b/src/test/ui/consts/const-eval/conditional_array_execution.rs index 96f67c92a5e93..2058d2e218473 100644 --- a/src/test/ui/consts/const-eval/conditional_array_execution.rs +++ b/src/test/ui/consts/const-eval/conditional_array_execution.rs @@ -10,4 +10,5 @@ const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; fn main() { println!("{}", FOO); //~^ ERROR + //~| WARN erroneous constant used [const_err] } diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.stderr b/src/test/ui/consts/const-eval/conditional_array_execution.stderr index ec18f8f011d61..b5f5f84cf3894 100644 --- a/src/test/ui/consts/const-eval/conditional_array_execution.stderr +++ b/src/test/ui/consts/const-eval/conditional_array_execution.stderr @@ -18,6 +18,12 @@ error[E0080]: evaluation of constant expression failed LL | println!("{}", FOO); | ^^^ referenced constant has errors +warning: erroneous constant used + --> $DIR/conditional_array_execution.rs:11:20 + | +LL | println!("{}", FOO); + | ^^^ referenced constant has errors + error: aborting due to previous error For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs index a5f04d088b611..81f53826d8103 100644 --- a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs +++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs @@ -4,7 +4,9 @@ #![feature(const_fn)] #![allow(const_err)] -fn double(x: usize) -> usize { x * 2 } +fn double(x: usize) -> usize { + x * 2 +} const X: fn(usize) -> usize = double; const fn bar(x: fn(usize) -> usize, y: usize) -> usize { diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr index 19f37fa00795c..f99505c30901d 100644 --- a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr +++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr @@ -1,11 +1,11 @@ warning: skipping const checks - --> $DIR/const_fn_ptr_fail2.rs:11:5 + --> $DIR/const_fn_ptr_fail2.rs:13:5 | LL | x(y) | ^^^^ error[E0080]: evaluation of constant expression failed - --> $DIR/const_fn_ptr_fail2.rs:18:5 + --> $DIR/const_fn_ptr_fail2.rs:20:5 | LL | assert_eq!(Y, 4); | ^^^^^^^^^^^-^^^^^ @@ -15,7 +15,7 @@ LL | assert_eq!(Y, 4); = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error[E0080]: evaluation of constant expression failed - --> $DIR/const_fn_ptr_fail2.rs:20:5 + --> $DIR/const_fn_ptr_fail2.rs:22:5 | LL | assert_eq!(Z, 4); | ^^^^^^^^^^^-^^^^^ diff --git a/src/test/ui/consts/const-eval/issue-43197.rs b/src/test/ui/consts/const-eval/issue-43197.rs index 849c81ad449b5..9109307632b59 100644 --- a/src/test/ui/consts/const-eval/issue-43197.rs +++ b/src/test/ui/consts/const-eval/issue-43197.rs @@ -7,11 +7,13 @@ const fn foo(x: u32) -> u32 { } fn main() { - const X: u32 = 0-1; + const X: u32 = 0 - 1; //~^ WARN any use of this value will cause - const Y: u32 = foo(0-1); + const Y: u32 = foo(0 - 1); //~^ WARN any use of this value will cause println!("{} {}", X, Y); //~^ ERROR evaluation of constant expression failed //~| ERROR evaluation of constant expression failed + //~| WARN erroneous constant used [const_err] + //~| WARN erroneous constant used [const_err] } diff --git a/src/test/ui/consts/const-eval/issue-43197.stderr b/src/test/ui/consts/const-eval/issue-43197.stderr index a1b3a05ed4169..23b54d954c658 100644 --- a/src/test/ui/consts/const-eval/issue-43197.stderr +++ b/src/test/ui/consts/const-eval/issue-43197.stderr @@ -1,8 +1,8 @@ warning: any use of this value will cause an error --> $DIR/issue-43197.rs:10:20 | -LL | const X: u32 = 0-1; - | ---------------^^^- +LL | const X: u32 = 0 - 1; + | ---------------^^^^^- | | | attempt to subtract with overflow | @@ -15,8 +15,8 @@ LL | #![warn(const_err)] warning: any use of this value will cause an error --> $DIR/issue-43197.rs:12:24 | -LL | const Y: u32 = foo(0-1); - | -------------------^^^-- +LL | const Y: u32 = foo(0 - 1); + | -------------------^^^^^-- | | | attempt to subtract with overflow @@ -26,12 +26,24 @@ error[E0080]: evaluation of constant expression failed LL | println!("{} {}", X, Y); | ^ referenced constant has errors +warning: erroneous constant used + --> $DIR/issue-43197.rs:14:23 + | +LL | println!("{} {}", X, Y); + | ^ referenced constant has errors + error[E0080]: evaluation of constant expression failed --> $DIR/issue-43197.rs:14:26 | LL | println!("{} {}", X, Y); | ^ referenced constant has errors +warning: erroneous constant used + --> $DIR/issue-43197.rs:14:26 + | +LL | println!("{} {}", X, Y); + | ^ referenced constant has errors + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/issue-44578.rs b/src/test/ui/consts/const-eval/issue-44578.rs index 7da9256bb398f..f9194709dc0b7 100644 --- a/src/test/ui/consts/const-eval/issue-44578.rs +++ b/src/test/ui/consts/const-eval/issue-44578.rs @@ -25,5 +25,5 @@ impl Foo for u16 { fn main() { println!("{}", as Foo>::AMT); - //~^ ERROR E0080 + //~^ ERROR evaluation of constant expression failed [E0080] } diff --git a/src/test/ui/consts/const-eval/issue-50814.rs b/src/test/ui/consts/const-eval/issue-50814.rs index e589126a9429c..5c3635e4650cd 100644 --- a/src/test/ui/consts/const-eval/issue-50814.rs +++ b/src/test/ui/consts/const-eval/issue-50814.rs @@ -12,11 +12,13 @@ impl Unsigned for U8 { struct Sum(A,B); impl Unsigned for Sum { - const MAX: u8 = A::MAX + B::MAX; //~ ERROR any use of this value will cause an error + const MAX: u8 = A::MAX + B::MAX; + //~^ ERROR any use of this value will cause an error [const_err] } fn foo(_: T) -> &'static u8 { - &Sum::::MAX //~ ERROR E0080 + &Sum::::MAX + //~^ ERROR E0080 } fn main() { diff --git a/src/test/ui/consts/const-eval/issue-50814.stderr b/src/test/ui/consts/const-eval/issue-50814.stderr index f8b017e4b53a1..2e5167a99a2c6 100644 --- a/src/test/ui/consts/const-eval/issue-50814.stderr +++ b/src/test/ui/consts/const-eval/issue-50814.stderr @@ -9,7 +9,7 @@ LL | const MAX: u8 = A::MAX + B::MAX; = note: `#[deny(const_err)]` on by default error[E0080]: evaluation of constant expression failed - --> $DIR/issue-50814.rs:19:5 + --> $DIR/issue-50814.rs:20:5 | LL | &Sum::::MAX | ^----------------- diff --git a/src/test/ui/consts/const-eval/promoted_errors.rs b/src/test/ui/consts/const-eval/promoted_errors.rs index 2eed8ca7d322c..fee232185d29a 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.rs +++ b/src/test/ui/consts/const-eval/promoted_errors.rs @@ -1,20 +1,22 @@ -// build-fail +// build-pass // compile-flags: -O -#![deny(const_err)] +#![warn(const_err)] fn main() { println!("{}", 0u32 - 1); let _x = 0u32 - 1; - //~^ ERROR const_err - println!("{}", 1/(1-1)); - //~^ ERROR attempt to divide by zero [const_err] - //~| ERROR const_err - let _x = 1/(1-1); - //~^ ERROR const_err - println!("{}", 1/(false as u32)); - //~^ ERROR attempt to divide by zero [const_err] - //~| ERROR const_err - let _x = 1/(false as u32); - //~^ ERROR const_err + //~^ WARN const_err + println!("{}", 1 / (1 - 1)); + //~^ WARN attempt to divide by zero [const_err] + //~| WARN const_err + //~| WARN erroneous constant used [const_err] + let _x = 1 / (1 - 1); + //~^ WARN const_err + println!("{}", 1 / (false as u32)); + //~^ WARN attempt to divide by zero [const_err] + //~| WARN const_err + //~| WARN erroneous constant used [const_err] + let _x = 1 / (false as u32); + //~^ WARN const_err } diff --git a/src/test/ui/consts/const-eval/promoted_errors.stderr b/src/test/ui/consts/const-eval/promoted_errors.stderr index 8f17ef05f2356..4de22fdf4ab1e 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.stderr @@ -1,4 +1,4 @@ -error: this expression will panic at runtime +warning: this expression will panic at runtime --> $DIR/promoted_errors.rs:8:14 | LL | let _x = 0u32 - 1; @@ -7,44 +7,54 @@ LL | let _x = 0u32 - 1; note: lint level defined here --> $DIR/promoted_errors.rs:4:9 | -LL | #![deny(const_err)] +LL | #![warn(const_err)] | ^^^^^^^^^ -error: attempt to divide by zero +warning: attempt to divide by zero --> $DIR/promoted_errors.rs:10:20 | -LL | println!("{}", 1/(1-1)); - | ^^^^^^^ +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ -error: reaching this expression at runtime will panic or abort +warning: reaching this expression at runtime will panic or abort --> $DIR/promoted_errors.rs:10:20 | -LL | println!("{}", 1/(1-1)); - | ^^^^^^^ dividing by zero +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ dividing by zero -error: attempt to divide by zero - --> $DIR/promoted_errors.rs:13:14 +warning: erroneous constant used + --> $DIR/promoted_errors.rs:10:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ referenced constant has errors + +warning: attempt to divide by zero + --> $DIR/promoted_errors.rs:14:14 | -LL | let _x = 1/(1-1); - | ^^^^^^^ +LL | let _x = 1 / (1 - 1); + | ^^^^^^^^^^^ -error: attempt to divide by zero - --> $DIR/promoted_errors.rs:15:20 +warning: attempt to divide by zero + --> $DIR/promoted_errors.rs:16:20 | -LL | println!("{}", 1/(false as u32)); - | ^^^^^^^^^^^^^^^^ +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ -error: reaching this expression at runtime will panic or abort - --> $DIR/promoted_errors.rs:15:20 +warning: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors.rs:16:20 | -LL | println!("{}", 1/(false as u32)); - | ^^^^^^^^^^^^^^^^ dividing by zero +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ dividing by zero -error: attempt to divide by zero - --> $DIR/promoted_errors.rs:18:14 +warning: erroneous constant used + --> $DIR/promoted_errors.rs:16:20 | -LL | let _x = 1/(false as u32); - | ^^^^^^^^^^^^^^^^ +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ referenced constant has errors -error: aborting due to 7 previous errors +warning: attempt to divide by zero + --> $DIR/promoted_errors.rs:20:14 + | +LL | let _x = 1 / (false as u32); + | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/consts/const-eval/promoted_errors2.rs b/src/test/ui/consts/const-eval/promoted_errors2.rs index ae680b4f1072e..41a989d91c5d3 100644 --- a/src/test/ui/consts/const-eval/promoted_errors2.rs +++ b/src/test/ui/consts/const-eval/promoted_errors2.rs @@ -1,21 +1,23 @@ -// build-fail +// build-pass // compile-flags: -C overflow-checks=on -O -#![deny(const_err)] +#![warn(const_err)] fn main() { println!("{}", 0u32 - 1); - //~^ ERROR attempt to subtract with overflow + //~^ WARN attempt to subtract with overflow let _x = 0u32 - 1; - //~^ ERROR attempt to subtract with overflow - println!("{}", 1/(1-1)); - //~^ ERROR attempt to divide by zero [const_err] - //~| ERROR const_err - let _x = 1/(1-1); - //~^ ERROR const_err - println!("{}", 1/(false as u32)); - //~^ ERROR attempt to divide by zero [const_err] - //~| ERROR const_err - let _x = 1/(false as u32); - //~^ ERROR const_err + //~^ WARN attempt to subtract with overflow + println!("{}", 1 / (1 - 1)); + //~^ WARN attempt to divide by zero [const_err] + //~| WARN const_err + //~| WARN erroneous constant used [const_err] + let _x = 1 / (1 - 1); + //~^ WARN const_err + println!("{}", 1 / (false as u32)); + //~^ WARN attempt to divide by zero [const_err] + //~| WARN const_err + //~| WARN erroneous constant used [const_err] + let _x = 1 / (false as u32); + //~^ WARN const_err } diff --git a/src/test/ui/consts/const-eval/promoted_errors2.stderr b/src/test/ui/consts/const-eval/promoted_errors2.stderr index 60a3cba6e1ff5..4f7ba8bf385d3 100644 --- a/src/test/ui/consts/const-eval/promoted_errors2.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors2.stderr @@ -1,4 +1,4 @@ -error: attempt to subtract with overflow +warning: attempt to subtract with overflow --> $DIR/promoted_errors2.rs:7:20 | LL | println!("{}", 0u32 - 1); @@ -7,50 +7,60 @@ LL | println!("{}", 0u32 - 1); note: lint level defined here --> $DIR/promoted_errors2.rs:4:9 | -LL | #![deny(const_err)] +LL | #![warn(const_err)] | ^^^^^^^^^ -error: attempt to subtract with overflow +warning: attempt to subtract with overflow --> $DIR/promoted_errors2.rs:9:14 | LL | let _x = 0u32 - 1; | ^^^^^^^^ -error: attempt to divide by zero +warning: attempt to divide by zero --> $DIR/promoted_errors2.rs:11:20 | -LL | println!("{}", 1/(1-1)); - | ^^^^^^^ +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ -error: reaching this expression at runtime will panic or abort +warning: reaching this expression at runtime will panic or abort --> $DIR/promoted_errors2.rs:11:20 | -LL | println!("{}", 1/(1-1)); - | ^^^^^^^ dividing by zero +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ dividing by zero -error: attempt to divide by zero - --> $DIR/promoted_errors2.rs:14:14 +warning: erroneous constant used + --> $DIR/promoted_errors2.rs:11:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ referenced constant has errors + +warning: attempt to divide by zero + --> $DIR/promoted_errors2.rs:15:14 | -LL | let _x = 1/(1-1); - | ^^^^^^^ +LL | let _x = 1 / (1 - 1); + | ^^^^^^^^^^^ -error: attempt to divide by zero - --> $DIR/promoted_errors2.rs:16:20 +warning: attempt to divide by zero + --> $DIR/promoted_errors2.rs:17:20 | -LL | println!("{}", 1/(false as u32)); - | ^^^^^^^^^^^^^^^^ +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ -error: reaching this expression at runtime will panic or abort - --> $DIR/promoted_errors2.rs:16:20 +warning: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors2.rs:17:20 | -LL | println!("{}", 1/(false as u32)); - | ^^^^^^^^^^^^^^^^ dividing by zero +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ dividing by zero -error: attempt to divide by zero - --> $DIR/promoted_errors2.rs:19:14 +warning: erroneous constant used + --> $DIR/promoted_errors2.rs:17:20 | -LL | let _x = 1/(false as u32); - | ^^^^^^^^^^^^^^^^ +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ referenced constant has errors -error: aborting due to 8 previous errors +warning: attempt to divide by zero + --> $DIR/promoted_errors2.rs:21:14 + | +LL | let _x = 1 / (false as u32); + | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/consts/const-eval/ub-nonnull.stderr b/src/test/ui/consts/const-eval/ub-nonnull.stderr index 80d80a986751e..ea9fffa883ea5 100644 --- a/src/test/ui/consts/const-eval/ub-nonnull.stderr +++ b/src/test/ui/consts/const-eval/ub-nonnull.stderr @@ -13,7 +13,7 @@ LL | / const OUT_OF_BOUNDS_PTR: NonNull = { unsafe { LL | | let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle LL | | // Use address-of-element for pointer arithmetic. This could wrap around to NULL! LL | | let out_of_bounds_ptr = &ptr[255]; - | | ^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of allocation 6 which has size 1 + | | ^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of allocation 9 which has size 1 LL | | mem::transmute(out_of_bounds_ptr) LL | | } }; | |____- diff --git a/src/test/ui/consts/miri_unleashed/non_const_fn.rs b/src/test/ui/consts/miri_unleashed/non_const_fn.rs index 32a713ebaa44e..cfb57d21ceec5 100644 --- a/src/test/ui/consts/miri_unleashed/non_const_fn.rs +++ b/src/test/ui/consts/miri_unleashed/non_const_fn.rs @@ -11,5 +11,7 @@ const C: () = foo(); //~ WARN: skipping const checks //~^ WARN any use of this value will cause an error fn main() { - println!("{:?}", C); //~ ERROR: evaluation of constant expression failed + println!("{:?}", C); + //~^ ERROR: evaluation of constant expression failed + //~| WARN: erroneous constant used [const_err] } diff --git a/src/test/ui/consts/miri_unleashed/non_const_fn.stderr b/src/test/ui/consts/miri_unleashed/non_const_fn.stderr index 75f532a81bdc3..6a7df858febcf 100644 --- a/src/test/ui/consts/miri_unleashed/non_const_fn.stderr +++ b/src/test/ui/consts/miri_unleashed/non_const_fn.stderr @@ -24,6 +24,12 @@ error[E0080]: evaluation of constant expression failed LL | println!("{:?}", C); | ^ referenced constant has errors +warning: erroneous constant used + --> $DIR/non_const_fn.rs:14:22 + | +LL | println!("{:?}", C); + | ^ referenced constant has errors + error: aborting due to previous error For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/zst_no_llvm_alloc.rs b/src/test/ui/consts/zst_no_llvm_alloc.rs index 5d779355400cc..2a41f708c2b87 100644 --- a/src/test/ui/consts/zst_no_llvm_alloc.rs +++ b/src/test/ui/consts/zst_no_llvm_alloc.rs @@ -7,13 +7,15 @@ static FOO: Foo = Foo; fn main() { let x: &'static () = &(); - assert_eq!(x as *const () as usize, 1); + assert_ne!(x as *const () as usize, 1); let x: &'static Foo = &Foo; - assert_eq!(x as *const Foo as usize, 4); + assert_ne!(x as *const Foo as usize, 4); // statics must have a unique address assert_ne!(&FOO as *const Foo as usize, 4); - assert_eq!(>::new().as_ptr(), <&[i32]>::default().as_ptr()); - assert_eq!(>::default().as_ptr(), (&[]).as_ptr()); + // FIXME this two tests should be assert_eq! + // this stopped working since we are promoting to constants instead of statics + assert_ne!(>::new().as_ptr(), <&[i32]>::default().as_ptr()); + assert_ne!(>::default().as_ptr(), (&[]).as_ptr()); } diff --git a/src/test/ui/invalid_const_promotion.rs b/src/test/ui/invalid_const_promotion.rs deleted file mode 100644 index 5d7664cefb33a..0000000000000 --- a/src/test/ui/invalid_const_promotion.rs +++ /dev/null @@ -1,61 +0,0 @@ -// run-pass - -#![allow(unused_mut)] -// ignore-wasm32 -// ignore-emscripten -// ignore-sgx no processes - -// compile-flags: -C debug_assertions=yes - -#![stable(feature = "rustc", since = "1.0.0")] -#![feature(const_fn, rustc_private, staged_api, rustc_attrs)] -#![allow(const_err)] - -extern crate libc; - -use std::env; -use std::process::{Command, Stdio}; - -// this will panic in debug mode and overflow in release mode -// -// NB we give bar an unused argument because otherwise memoization -// of the const fn kicks in, causing a different code path in the -// compiler to be executed (see PR #66294). -#[stable(feature = "rustc", since = "1.0.0")] -#[rustc_const_stable(feature = "rustc", since = "1.0.0")] -#[rustc_promotable] -const fn bar(_: bool) -> usize { 0 - 1 } - -fn foo() { - let _: &'static _ = &bar(true); -} - -#[cfg(unix)] -fn check_status(status: std::process::ExitStatus) -{ - use std::os::unix::process::ExitStatusExt; - - assert!(status.signal() == Some(libc::SIGILL) - || status.signal() == Some(libc::SIGTRAP) - || status.signal() == Some(libc::SIGABRT)); -} - -#[cfg(not(unix))] -fn check_status(status: std::process::ExitStatus) -{ - assert!(!status.success()); -} - -fn main() { - let args: Vec = env::args().collect(); - if args.len() > 1 && args[1] == "test" { - foo(); - return; - } - - let mut p = Command::new(&args[0]) - .stdout(Stdio::piped()) - .stdin(Stdio::piped()) - .arg("test").output().unwrap(); - check_status(p.status); -} diff --git a/src/test/ui/symbol-names/impl1.legacy.stderr b/src/test/ui/symbol-names/impl1.legacy.stderr index 53ab2f9878f30..affb5537b1856 100644 --- a/src/test/ui/symbol-names/impl1.legacy.stderr +++ b/src/test/ui/symbol-names/impl1.legacy.stderr @@ -46,13 +46,13 @@ error: def-path(bar::::baz) LL | #[rustc_def_path] | ^^^^^^^^^^^^^^^^^ -error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17h92c563325b7ff21aE) +error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17hf07584432cd4d8beE) --> $DIR/impl1.rs:62:13 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method::h92c563325b7ff21a) +error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method::hf07584432cd4d8be) --> $DIR/impl1.rs:62:13 | LL | #[rustc_symbol_name]