diff --git a/src/doc/unstable-book/src/language-features/non-exhaustive.md b/src/doc/unstable-book/src/language-features/non-exhaustive.md deleted file mode 100644 index 907147c17ef8e..0000000000000 --- a/src/doc/unstable-book/src/language-features/non-exhaustive.md +++ /dev/null @@ -1,76 +0,0 @@ -# `non_exhaustive` - -The tracking issue for this feature is: [#44109] - -[#44109]: https://github.com/rust-lang/rust/issues/44109 - ------------------------- - -The `non_exhaustive` gate allows you to use the `#[non_exhaustive]` attribute -on structs, enums and enum variants. When applied within a crate, users of the -crate will need to use the `_` pattern when matching enums and use the `..` -pattern when matching structs. Enum variants cannot be matched against. -Structs and enum variants marked as `non_exhaustive` will not be able to -be created normally outside of the defining crate. This is demonstrated -below: - -```rust,ignore (pseudo-Rust) -use std::error::Error as StdError; - -#[non_exhaustive] -pub enum Error { - Message(String), - Other, -} -impl StdError for Error { - fn description(&self) -> &str { - // This will not error, despite being marked as non_exhaustive, as this - // enum is defined within the current crate, it can be matched - // exhaustively. - match *self { - Message(ref s) => s, - Other => "other or unknown error", - } - } -} -``` - -```rust,ignore (pseudo-Rust) -use mycrate::Error; - -// This will not error as the non_exhaustive Error enum has been matched with -// a wildcard. -match error { - Message(ref s) => ..., - Other => ..., - _ => ..., -} -``` - -```rust,ignore (pseudo-Rust) -#[non_exhaustive] -pub struct Config { - pub window_width: u16, - pub window_height: u16, -} - -// We can create structs as normal within the defining crate when marked as -// non_exhaustive. -let config = Config { window_width: 640, window_height: 480 }; - -// We can match structs exhaustively when within the defining crate. -if let Ok(Config { window_width, window_height }) = load_config() { - // ... -} -``` - -```rust,ignore (pseudo-Rust) -use mycrate::Config; - -// We cannot create a struct like normal if it has been marked as -// non_exhaustive. -let config = Config { window_width: 640, window_height: 480 }; -// By adding the `..` we can match the config as below outside of the crate -// when marked non_exhaustive. -let &Config { window_width, window_height, .. } = config; -``` diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 30e8dddff85ad..0819969b93360 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -121,7 +121,7 @@ #![feature(hexagon_target_feature)] #![feature(const_int_conversion)] #![feature(const_transmute)] -#![feature(non_exhaustive)] +#![cfg_attr(bootstrap, feature(non_exhaustive))] #![feature(structural_match)] #![feature(abi_unadjusted)] #![feature(adx_target_feature)] diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index f612c52d39835..6166561d87f15 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -25,7 +25,7 @@ #![feature(extern_types)] #![feature(in_band_lifetimes)] #![feature(optin_builtin_traits)] -#![feature(non_exhaustive)] +#![cfg_attr(bootstrap, feature(non_exhaustive))] #![feature(rustc_attrs)] #![feature(specialization)] diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs index 122ae4a6cf66f..cf268078a2c5d 100644 --- a/src/librustc/error_codes.rs +++ b/src/librustc/error_codes.rs @@ -2105,8 +2105,6 @@ on something other than a struct or enum. Examples of erroneous code: ```compile_fail,E0701 -# #![feature(non_exhaustive)] - #[non_exhaustive] trait Foo { } ``` diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index dc1f6fd3131bd..2510d7efb59e7 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -425,6 +425,7 @@ impl<'a> HashStable> for SourceFile { ref lines, ref multibyte_chars, ref non_narrow_chars, + ref normalized_pos, } = *self; (name_hash as u64).hash_stable(hcx, hasher); @@ -453,6 +454,12 @@ impl<'a> HashStable> for SourceFile { for &char_pos in non_narrow_chars.iter() { stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher); } + + normalized_pos.len().hash_stable(hcx, hasher); + for &char_pos in normalized_pos.iter() { + stable_normalized_pos(char_pos, start_pos).hash_stable(hcx, hasher); + } + } } @@ -482,6 +489,18 @@ fn stable_non_narrow_char(swc: ::syntax_pos::NonNarrowChar, (pos.0 - source_file_start.0, width as u32) } +fn stable_normalized_pos(np: ::syntax_pos::NormalizedPos, + source_file_start: ::syntax_pos::BytePos) + -> (u32, u32) { + let ::syntax_pos::NormalizedPos { + pos, + diff + } = np; + + (pos.0 - source_file_start.0, diff) +} + + impl<'tcx> HashStable> for feature_gate::Features { fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { // Unfortunately we cannot exhaustively list fields here, since the diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 3b0ac9ada8f65..996f5b1241263 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -41,7 +41,7 @@ #![feature(overlapping_marker_traits)] #![feature(extern_types)] #![feature(nll)] -#![feature(non_exhaustive)] +#![cfg_attr(bootstrap, feature(non_exhaustive))] #![feature(optin_builtin_traits)] #![feature(option_expect_none)] #![feature(range_is_empty)] diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 08e7001681c29..fb9c95724c955 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -15,8 +15,7 @@ use crate::ty::layout::VariantIdx; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::{ - self, AdtDef, CanonicalUserTypeAnnotations, Region, Ty, TyCtxt, - UserTypeAnnotationIndex, + self, AdtDef, CanonicalUserTypeAnnotations, List, Region, Ty, TyCtxt, UserTypeAnnotationIndex, }; use polonius_engine::Atom; @@ -1712,15 +1711,17 @@ 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, RustcDecodable, HashStable, + Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, HashStable, )] pub struct Place<'tcx> { pub base: PlaceBase<'tcx>, /// projection out of a place (access a field, deref a pointer, etc) - pub projection: Box<[PlaceElem<'tcx>]>, + pub projection: &'tcx List>, } +impl<'tcx> rustc_serialize::UseSpecializedDecodable for Place<'tcx> {} + #[derive( Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable, )] @@ -1824,6 +1825,8 @@ impl ProjectionElem { /// and the index is a local. pub type PlaceElem<'tcx> = ProjectionElem>; +impl<'tcx> Copy for PlaceElem<'tcx> { } + // At least on 64 bit systems, `PlaceElem` should not be larger than two pointers. #[cfg(target_arch = "x86_64")] static_assert_size!(PlaceElem<'_>, 16); @@ -1846,50 +1849,11 @@ pub struct PlaceRef<'a, 'tcx> { } impl<'tcx> Place<'tcx> { - // FIXME change this back to a const when projection is a shared slice. - // - // pub const RETURN_PLACE: Place<'tcx> = Place { - // base: PlaceBase::Local(RETURN_PLACE), - // projection: &[], - // }; + // 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: Box::new([]), - } - } - - pub fn field(self, f: Field, ty: Ty<'tcx>) -> Place<'tcx> { - self.elem(ProjectionElem::Field(f, ty)) - } - - pub fn deref(self) -> Place<'tcx> { - self.elem(ProjectionElem::Deref) - } - - pub fn downcast(self, adt_def: &'tcx AdtDef, variant_index: VariantIdx) -> Place<'tcx> { - self.elem(ProjectionElem::Downcast( - Some(adt_def.variants[variant_index].ident.name), - variant_index, - )) - } - - pub fn downcast_unnamed(self, variant_index: VariantIdx) -> Place<'tcx> { - self.elem(ProjectionElem::Downcast(None, variant_index)) - } - - pub fn index(self, index: Local) -> Place<'tcx> { - self.elem(ProjectionElem::Index(index)) - } - - pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> { - // FIXME(spastorino): revisit this again once projection is not a Box<[T]> anymore - let mut projection = self.projection.into_vec(); - projection.push(elem); - - Place { - base: self.base, - projection: projection.into_boxed_slice(), + projection: List::empty(), } } @@ -1906,15 +1870,15 @@ 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 { - Place { - base: PlaceBase::Local(local), - projection: box [], + match self.as_ref() { + PlaceRef { + base: &PlaceBase::Local(local), + projection: &[], } | - Place { - base: PlaceBase::Local(local), - projection: box [ProjectionElem::Deref], - } => Some(*local), + PlaceRef { + base: &PlaceBase::Local(local), + projection: &[ProjectionElem::Deref], + } => Some(local), _ => None, } } @@ -1922,10 +1886,7 @@ impl<'tcx> Place<'tcx> { /// If this place represents a local variable like `_X` with no /// projections, return `Some(_X)`. pub fn as_local(&self) -> Option { - match self { - Place { projection: box [], base: PlaceBase::Local(l) } => Some(*l), - _ => None, - } + self.as_ref().as_local() } pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> { @@ -1940,7 +1901,7 @@ impl From for Place<'_> { fn from(local: Local) -> Self { Place { base: local.into(), - projection: Box::new([]), + projection: List::empty(), } } } @@ -1969,6 +1930,15 @@ impl<'a, 'tcx> PlaceRef<'a, 'tcx> { _ => None, } } + + /// If this place represents a local variable like `_X` with no + /// projections, return `Some(_X)`. + pub fn as_local(&self) -> Option { + match self { + PlaceRef { base: PlaceBase::Local(l), projection: [] } => Some(*l), + _ => None, + } + } } impl Debug for Place<'_> { @@ -3182,6 +3152,17 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceBase<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); + folder.tcx().intern_place_elems(&v) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.iter().any(|t| t.visit_with(visitor)) + } +} + impl<'tcx> TypeFoldable<'tcx> for Static<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { Static { diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 427540d72758e..6a41b843e5794 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -784,6 +784,8 @@ macro_rules! make_mir_visitor { macro_rules! visit_place_fns { (mut) => ( + fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; + fn super_place( &mut self, place: &mut Place<'tcx>, @@ -793,19 +795,21 @@ macro_rules! visit_place_fns { self.visit_place_base(&mut place.base, context, location); if let Some(new_projection) = self.process_projection(&place.projection) { - place.projection = new_projection; + place.projection = self.tcx().intern_place_elems(&new_projection); } } fn process_projection( &mut self, projection: &'a [PlaceElem<'tcx>], - ) -> Option]>> { + ) -> Option>> { let mut projection = Cow::Borrowed(projection); for i in 0..projection.len() { if let Some(elem) = projection.get(i) { if let Some(elem) = self.process_projection_elem(elem) { + // This converts the borrowed projection into `Cow::Owned(_)` and returns a + // clone of the projection so we can mutate and reintern later. let vec = projection.to_mut(); vec[i] = elem; } @@ -814,7 +818,7 @@ macro_rules! visit_place_fns { match projection { Cow::Borrowed(_) => None, - Cow::Owned(vec) => Some(vec.into_boxed_slice()), + Cow::Owned(vec) => Some(vec), } } diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs index 03cb4775bd83f..d5e7ac19263a0 100644 --- a/src/librustc/ty/codec.rs +++ b/src/librustc/ty/codec.rs @@ -13,9 +13,9 @@ use rustc_data_structures::fx::FxHashMap; use rustc_serialize::{Decodable, Decoder, Encoder, Encodable, opaque}; use std::hash::Hash; use std::intrinsics; -use crate::ty::{self, Ty, TyCtxt}; +use crate::ty::{self, List, Ty, TyCtxt}; use crate::ty::subst::SubstsRef; -use crate::mir::interpret::Allocation; +use crate::mir::{self, interpret::Allocation}; use syntax_pos::Span; /// The shorthand encoding uses an enum's variant index `usize` @@ -218,6 +218,18 @@ where Ok(tcx.mk_substs((0..len).map(|_| Decodable::decode(decoder)))?) } +#[inline] +pub fn decode_place(decoder: &mut D) -> Result, D::Error> +where + D: TyDecoder<'tcx>, +{ + let base: mir::PlaceBase<'tcx> = 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 }) +} + #[inline] pub fn decode_region(decoder: &mut D) -> Result, D::Error> where @@ -413,6 +425,15 @@ macro_rules! implement_ty_decoder { } } + impl<$($typaram),*> SpecializedDecoder<$crate::mir::Place<'tcx>> + for $DecoderName<$($typaram),*> { + fn specialized_decode( + &mut self + ) -> Result<$crate::mir::Place<'tcx>, Self::Error> { + decode_place(self) + } + } + impl<$($typaram),*> SpecializedDecoder> for $DecoderName<$($typaram),*> { fn specialized_decode(&mut self) -> Result, Self::Error> { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index f99298281fecc..f958a7e357b39 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1,3 +1,4 @@ +// ignore-tidy-filelength //! Type context book-keeping. use crate::arena::Arena; @@ -21,7 +22,7 @@ use crate::middle::cstore::EncodedMetadata; use crate::middle::lang_items; use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use crate::middle::stability; -use crate::mir::{Body, interpret, ProjectionKind, Promoted}; +use crate::mir::{Body, Field, interpret, Local, Place, PlaceElem, ProjectionKind, Promoted}; use crate::mir::interpret::{ConstValue, Allocation, Scalar}; use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef, Subst}; use crate::ty::ReprOptions; @@ -106,6 +107,7 @@ pub struct CtxtInterners<'tcx> { goal: InternedSet<'tcx, GoalKind<'tcx>>, goal_list: InternedSet<'tcx, List>>, projs: InternedSet<'tcx, List>, + place_elems: InternedSet<'tcx, List>>, const_: InternedSet<'tcx, Const<'tcx>>, } @@ -124,6 +126,7 @@ impl<'tcx> CtxtInterners<'tcx> { goal: Default::default(), goal_list: Default::default(), projs: Default::default(), + place_elems: Default::default(), const_: Default::default(), } } @@ -2142,6 +2145,13 @@ impl<'tcx> Borrow<[ProjectionKind]> } } +impl<'tcx> Borrow<[PlaceElem<'tcx>]> + for Interned<'tcx, List>> { + fn borrow(&self) -> &[PlaceElem<'tcx>] { + &self.0[..] + } +} + impl<'tcx> Borrow for Interned<'tcx, RegionKind> { fn borrow(&self) -> &RegionKind { &self.0 @@ -2242,7 +2252,8 @@ slice_interners!( predicates: _intern_predicates(Predicate<'tcx>), clauses: _intern_clauses(Clause<'tcx>), goal_list: _intern_goals(Goal<'tcx>), - projs: _intern_projs(ProjectionKind) + projs: _intern_projs(ProjectionKind), + place_elems: _intern_place_elems(PlaceElem<'tcx>) ); impl<'tcx> TyCtxt<'tcx> { @@ -2584,6 +2595,48 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_ty(Opaque(def_id, substs)) } + pub fn mk_place_field(self, place: Place<'tcx>, f: Field, ty: Ty<'tcx>) -> Place<'tcx> { + self.mk_place_elem(place, PlaceElem::Field(f, ty)) + } + + pub fn mk_place_deref(self, place: Place<'tcx>) -> Place<'tcx> { + self.mk_place_elem(place, PlaceElem::Deref) + } + + pub fn mk_place_downcast( + self, + place: Place<'tcx>, + adt_def: &'tcx AdtDef, + variant_index: VariantIdx, + ) -> Place<'tcx> { + self.mk_place_elem( + place, + PlaceElem::Downcast(Some(adt_def.variants[variant_index].ident.name), variant_index), + ) + } + + pub fn mk_place_downcast_unnamed( + self, + place: Place<'tcx>, + variant_index: VariantIdx, + ) -> Place<'tcx> { + self.mk_place_elem(place, PlaceElem::Downcast(None, variant_index)) + } + + pub fn mk_place_index(self, place: Place<'tcx>, index: Local) -> Place<'tcx> { + self.mk_place_elem(place, PlaceElem::Index(index)) + } + + /// This method copies `Place`'s projection, add an element and reintern it. Should not be used + /// to build a full `Place` it's just a convenient way to grab a projection and modify it in + /// flight. + pub fn mk_place_elem(self, place: Place<'tcx>, elem: PlaceElem<'tcx>) -> Place<'tcx> { + let mut projection = place.projection.to_vec(); + projection.push(elem); + + Place { base: place.base, projection: self.intern_place_elems(&projection) } + } + pub fn intern_existential_predicates(self, eps: &[ExistentialPredicate<'tcx>]) -> &'tcx List> { assert!(!eps.is_empty()); @@ -2628,6 +2681,14 @@ impl<'tcx> TyCtxt<'tcx> { } } + pub fn intern_place_elems(self, ts: &[PlaceElem<'tcx>]) -> &'tcx List> { + if ts.len() == 0 { + List::empty() + } else { + self._intern_place_elems(ts) + } + } + pub fn intern_canonical_var_infos(self, ts: &[CanonicalVarInfo]) -> CanonicalVarInfos<'tcx> { if ts.len() == 0 { List::empty() @@ -2690,6 +2751,11 @@ impl<'tcx> TyCtxt<'tcx> { iter.intern_with(|xs| self.intern_substs(xs)) } + pub fn mk_place_elems], + &'tcx List>>>(self, iter: I) -> I::Output { + iter.intern_with(|xs| self.intern_place_elems(xs)) + } + pub fn mk_substs_trait(self, self_ty: Ty<'tcx>, rest: &[GenericArg<'tcx>]) diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index ea1cf926fccf0..604deffcf949b 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -191,10 +191,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> location: Location) { debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue); - if let mir::Place { - base: mir::PlaceBase::Local(index), - projection: box [], - } = *place { + if let Some(index) = place.as_local() { self.assign(index, location); let decl_span = self.fx.mir.local_decls[index].source_info.span; if !self.fx.rvalue_creates_operand(rvalue, decl_span) { diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index dc77d025c005f..28441cae26e3f 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -2,7 +2,7 @@ use rustc_index::vec::Idx; use rustc::middle::lang_items; use rustc::ty::{self, Ty, TypeFoldable, Instance}; use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt}; -use rustc::mir::{self, Place, PlaceBase, Static, StaticKind}; +use rustc::mir::{self, PlaceBase, Static, StaticKind}; use rustc::mir::interpret::PanicInfo; use rustc_target::abi::call::{ArgType, FnType, PassMode}; use rustc_target::spec::abi::Abi; @@ -630,53 +630,43 @@ 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 { + 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 { - base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(promoted, _), + mir::Operand::Copy(place) | mir::Operand::Move(place) => { + if let mir::PlaceRef { + base: + &PlaceBase::Static(box Static { + kind: StaticKind::Promoted(promoted, _), + ty, + def_id: _, + }), + projection: &[], + } = place.as_ref() + { + let param_env = ty::ParamEnv::reveal_all(); + let cid = mir::interpret::GlobalId { + instance: self.instance, + promoted: Some(promoted), + }; + let c = bx.tcx().const_eval(param_env.and(cid)); + let (llval, ty) = self.simd_shuffle_indices( + &bx, + terminator.source_info.span, ty, - def_id: _, - }), - projection: box [], + c, + ); + return OperandRef { + val: Immediate(llval), + layout: bx.layout_of(ty), + }; + } else { + span_bug!(span, "shuffle indices must be constant"); } - ) | - mir::Operand::Move( - Place { - base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(promoted, _), - ty, - def_id: _, - }), - projection: box [], - } - ) => { - let param_env = ty::ParamEnv::reveal_all(); - let cid = mir::interpret::GlobalId { - instance: self.instance, - promoted: Some(promoted), - }; - let c = bx.tcx().const_eval(param_env.and(cid)); - let (llval, ty) = self.simd_shuffle_indices( - &bx, - terminator.source_info.span, - ty, - c, - ); - return OperandRef { - val: Immediate(llval), - layout: bx.layout_of(ty), - }; - - } - mir::Operand::Copy(_) | - mir::Operand::Move(_) => { - span_bug!(span, "shuffle indices must be constant"); } - mir::Operand::Constant(ref constant) => { + + mir::Operand::Constant(constant) => { let c = self.eval_mir_constant(constant); let (llval, ty) = self.simd_shuffle_indices( &bx, @@ -1117,10 +1107,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if fn_ret.is_ignore() { return ReturnDest::Nothing; } - let dest = if let mir::Place { - base: mir::PlaceBase::Local(index), - projection: box [], - } = *dest { + let dest = if let Some(index) = dest.as_local() { match self.locals[index] { LocalRef::Place(dest) => dest, LocalRef::UnsizedPlace(_) => bug!("return type must be sized"), @@ -1178,10 +1165,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { src: &mir::Operand<'tcx>, dst: &mir::Place<'tcx> ) { - if let mir::Place { - base: mir::PlaceBase::Local(index), - projection: box [], - } = *dst { + if let Some(index) = dst.as_local() { match self.locals[index] { LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place), LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"), diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 7e662ea37dbb4..1608f222bc614 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -530,10 +530,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> Bx::Value { // ZST are passed as operands and require special handling // because codegen_place() panics if Local is operand. - if let mir::Place { - base: mir::PlaceBase::Local(index), - projection: box [], - } = *place { + if let Some(index) = place.as_local() { if let LocalRef::Operand(Some(op)) = self.locals[index] { if let ty::Array(_, n) = op.layout.ty.kind { let n = n.eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all()); diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/src/librustc_codegen_ssa/mir/statement.rs index dab7dfc041751..43d5c2570b705 100644 --- a/src/librustc_codegen_ssa/mir/statement.rs +++ b/src/librustc_codegen_ssa/mir/statement.rs @@ -17,11 +17,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.set_debug_loc(&mut bx, statement.source_info); match statement.kind { mir::StatementKind::Assign(box(ref place, ref rvalue)) => { - if let mir::Place { - base: mir::PlaceBase::Local(index), - projection: box [], - } = place { - match self.locals[*index] { + if let Some(index) = place.as_local() { + match self.locals[index] { LocalRef::Place(cg_dest) => { self.codegen_rvalue(bx, cg_dest, rvalue) } @@ -30,7 +27,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } LocalRef::Operand(None) => { let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue); - if let Some(name) = self.mir.local_decls[*index].name { + if let Some(name) = self.mir.local_decls[index].name { match operand.val { OperandValue::Ref(x, ..) | OperandValue::Immediate(x) => { @@ -44,7 +41,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } - self.locals[*index] = LocalRef::Operand(Some(operand)); + self.locals[index] = LocalRef::Operand(Some(operand)); bx } LocalRef::Operand(Some(op)) => { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 8c52168b418fd..09ff7891a9deb 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1319,6 +1319,7 @@ impl<'a, 'tcx> CrateMetadata { mut lines, mut multibyte_chars, mut non_narrow_chars, + mut normalized_pos, name_hash, .. } = source_file_to_import; @@ -1338,6 +1339,9 @@ impl<'a, 'tcx> CrateMetadata { for swc in &mut non_narrow_chars { *swc = *swc - start_pos; } + for np in &mut normalized_pos { + np.pos = np.pos - start_pos; + } let local_version = local_source_map.new_imported_source_file(name, name_was_remapped, @@ -1347,7 +1351,8 @@ impl<'a, 'tcx> CrateMetadata { source_length, lines, multibyte_chars, - non_narrow_chars); + non_narrow_chars, + normalized_pos); debug!("CrateMetaData::imported_source_files alloc \ source_file {:?} original (start_pos {:?} end_pos {:?}) \ translated (start_pos {:?} end_pos {:?})", diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index 7dd1db3b7bdbc..98641031c1787 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -315,10 +315,7 @@ impl<'a, 'tcx> GatherBorrows<'a, 'tcx> { // TEMP = &foo // // so extract `temp`. - let temp = if let &mir::Place { - base: mir::PlaceBase::Local(temp), - projection: box [], - } = assigned_place { + let temp = if let Some(temp) = assigned_place.as_local() { temp } else { span_bug!( diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs index 4c469a82ac3d6..36db68a3372eb 100644 --- a/src/librustc_mir/borrow_check/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/conflict_errors.rs @@ -239,11 +239,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } } - let span = if let Place { - base: PlaceBase::Local(local), - projection: box [], - } = place { - let decl = &self.body.local_decls[*local]; + let span = if let Some(local) = place.as_local() { + let decl = &self.body.local_decls[local]; Some(decl.source_info.span) } else { None @@ -611,7 +608,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { projection, } = first_borrowed_place; - let mut cursor = &**projection; + let mut cursor = projection.as_ref(); while let [proj_base @ .., elem] = cursor { cursor = proj_base; @@ -635,7 +632,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { projection, } = second_borrowed_place; - let mut cursor = &**projection; + let mut cursor = projection.as_ref(); while let [proj_base @ .., elem] = cursor { cursor = proj_base; @@ -710,10 +707,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { _ => drop_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.to_vec().into_boxed_slice(), + projection: root_place_projection, }, borrow_span)) { debug!( @@ -726,7 +725,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.access_place_error_reported .insert((Place { base: root_place.base.clone(), - projection: root_place.projection.to_vec().into_boxed_slice(), + projection: root_place_projection, }, borrow_span)); if let StorageDeadOrDrop::Destructor(dropped_ty) = @@ -1124,26 +1123,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }; let (place_desc, note) = if let Some(place_desc) = opt_place_desc { - let local_kind = match borrow.borrowed_place { - Place { - base: PlaceBase::Local(local), - projection: box [], - } => { - match self.body.local_kind(local) { - LocalKind::ReturnPointer - | LocalKind::Temp => bug!("temporary or return pointer with a name"), - LocalKind::Var => "local variable ", - LocalKind::Arg - if !self.upvars.is_empty() - && local == Local::new(1) => { - "variable captured by `move` " - } - LocalKind::Arg => { - "function parameter " - } + let local_kind = if let Some(local) = borrow.borrowed_place.as_local() { + match self.body.local_kind(local) { + LocalKind::ReturnPointer + | LocalKind::Temp => bug!("temporary or return pointer with a name"), + LocalKind::Var => "local variable ", + LocalKind::Arg + if !self.upvars.is_empty() + && local == Local::new(1) => { + "variable captured by `move` " + } + LocalKind::Arg => { + "function parameter " } } - _ => "local data ", + } else { + "local data " }; ( format!("{}`{}`", local_kind, place_desc), @@ -1480,10 +1475,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { assigned_span: Span, err_place: &Place<'tcx>, ) { - let (from_arg, local_decl) = if let Place { - base: PlaceBase::Local(local), - projection: box [], - } = *err_place { + let (from_arg, local_decl) = if let Some(local) = err_place.as_local() { if let LocalKind::Arg = self.body.local_kind(local) { (true, Some(&self.body.local_decls[local])) } else { @@ -1643,11 +1635,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { reservation ); // Check that the initial assignment of the reserve location is into a temporary. - let mut target = *match reservation { - Place { - base: PlaceBase::Local(local), - projection: box [], - } if self.body.local_kind(*local) == LocalKind::Temp => local, + let mut target = match reservation.as_local() { + Some(local) if self.body.local_kind(local) == LocalKind::Temp => local, _ => return None, }; @@ -1659,127 +1648,122 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}", target, stmt ); - if let StatementKind::Assign( - box( - Place { - base: PlaceBase::Local(assigned_to), - projection: box [], - }, - rvalue - ) - ) = &stmt.kind { - debug!( - "annotate_argument_and_return_for_borrow: assigned_to={:?} \ - rvalue={:?}", - assigned_to, rvalue - ); - // Check if our `target` was captured by a closure. - if let Rvalue::Aggregate( - box AggregateKind::Closure(def_id, substs), - operands, - ) = rvalue - { - for operand in operands { - let assigned_from = match operand { - Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { + if let StatementKind::Assign(box(place, rvalue)) = &stmt.kind { + if let Some(assigned_to) = place.as_local() { + debug!( + "annotate_argument_and_return_for_borrow: assigned_to={:?} \ + rvalue={:?}", + assigned_to, rvalue + ); + // Check if our `target` was captured by a closure. + if let Rvalue::Aggregate( + box AggregateKind::Closure(def_id, substs), + operands, + ) = rvalue + { + for operand in operands { + let assigned_from = match operand { + Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { + assigned_from + } + _ => continue, + }; + debug!( + "annotate_argument_and_return_for_borrow: assigned_from={:?}", assigned_from - } - _ => continue, - }; - debug!( - "annotate_argument_and_return_for_borrow: assigned_from={:?}", - assigned_from - ); + ); - // Find the local from the operand. - let assigned_from_local = match assigned_from.local_or_deref_local() { - Some(local) => local, - None => continue, - }; + // Find the local from the operand. + let assigned_from_local = match assigned_from.local_or_deref_local() + { + Some(local) => local, + None => continue, + }; - if assigned_from_local != target { - continue; - } - - // If a closure captured our `target` and then assigned - // into a place then we should annotate the closure in - // case it ends up being assigned into the return place. - annotated_closure = self.annotate_fn_sig( - *def_id, - self.infcx.closure_sig(*def_id, *substs), - ); - debug!( - "annotate_argument_and_return_for_borrow: \ - annotated_closure={:?} assigned_from_local={:?} \ - assigned_to={:?}", - annotated_closure, assigned_from_local, assigned_to - ); + if assigned_from_local != target { + continue; + } - if *assigned_to == mir::RETURN_PLACE { - // If it was assigned directly into the return place, then - // return now. - return annotated_closure; - } else { - // Otherwise, update the target. - target = *assigned_to; + // If a closure captured our `target` and then assigned + // into a place then we should annotate the closure in + // case it ends up being assigned into the return place. + annotated_closure = self.annotate_fn_sig( + *def_id, + self.infcx.closure_sig(*def_id, *substs), + ); + debug!( + "annotate_argument_and_return_for_borrow: \ + annotated_closure={:?} assigned_from_local={:?} \ + assigned_to={:?}", + annotated_closure, assigned_from_local, assigned_to + ); + + if assigned_to == mir::RETURN_PLACE { + // If it was assigned directly into the return place, then + // return now. + return annotated_closure; + } else { + // Otherwise, update the target. + target = assigned_to; + } } - } - // If none of our closure's operands matched, then skip to the next - // statement. - continue; - } + // If none of our closure's operands matched, then skip to the next + // statement. + continue; + } - // Otherwise, look at other types of assignment. - let assigned_from = match rvalue { - Rvalue::Ref(_, _, assigned_from) => assigned_from, - Rvalue::Use(operand) => match operand { - Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { - assigned_from - } + // Otherwise, look at other types of assignment. + let assigned_from = match rvalue { + Rvalue::Ref(_, _, assigned_from) => assigned_from, + Rvalue::Use(operand) => match operand { + Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { + assigned_from + } + _ => continue, + }, _ => continue, - }, - _ => continue, - }; - debug!( - "annotate_argument_and_return_for_borrow: \ - assigned_from={:?}", - assigned_from, - ); + }; + debug!( + "annotate_argument_and_return_for_borrow: \ + assigned_from={:?}", + assigned_from, + ); - // Find the local from the rvalue. - let assigned_from_local = match assigned_from.local_or_deref_local() { - Some(local) => local, - None => continue, - }; - debug!( - "annotate_argument_and_return_for_borrow: \ - assigned_from_local={:?}", - assigned_from_local, - ); + // Find the local from the rvalue. + let assigned_from_local = match assigned_from.local_or_deref_local() { + Some(local) => local, + None => continue, + }; + debug!( + "annotate_argument_and_return_for_borrow: \ + assigned_from_local={:?}", + assigned_from_local, + ); - // Check if our local matches the target - if so, we've assigned our - // borrow to a new place. - if assigned_from_local != target { - continue; - } + // Check if our local matches the target - if so, we've assigned our + // borrow to a new place. + if assigned_from_local != target { + continue; + } - // If we assigned our `target` into a new place, then we should - // check if it was the return place. - debug!( - "annotate_argument_and_return_for_borrow: \ - assigned_from_local={:?} assigned_to={:?}", - assigned_from_local, assigned_to - ); - if *assigned_to == mir::RETURN_PLACE { - // If it was then return the annotated closure if there was one, - // else, annotate this function. - return annotated_closure.or_else(fallback); - } + // If we assigned our `target` into a new place, then we should + // check if it was the return place. + debug!( + "annotate_argument_and_return_for_borrow: \ + assigned_from_local={:?} assigned_to={:?}", + assigned_from_local, assigned_to + ); + if assigned_to == mir::RETURN_PLACE { + // If it was then return the annotated closure if there was one, + // else, annotate this function. + return annotated_closure.or_else(fallback); + } - // If we didn't assign into the return place, then we just update - // the target. - target = *assigned_to; + // If we didn't assign into the return place, then we just update + // the target. + target = assigned_to; + } } } @@ -1790,38 +1774,37 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { target, terminator ); if let TerminatorKind::Call { - destination: Some((Place { - base: PlaceBase::Local(assigned_to), - projection: box [], - }, _)), + destination: Some((place, _)), args, .. } = &terminator.kind { - debug!( - "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}", - assigned_to, args - ); - for operand in args { - let assigned_from = match operand { - Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { - assigned_from - } - _ => continue, - }; + if let Some(assigned_to) = place.as_local() { debug!( - "annotate_argument_and_return_for_borrow: assigned_from={:?}", - assigned_from, + "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}", + assigned_to, args ); - - if let Some(assigned_from_local) = assigned_from.local_or_deref_local() { + for operand in args { + let assigned_from = match operand { + Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { + assigned_from + } + _ => continue, + }; debug!( - "annotate_argument_and_return_for_borrow: assigned_from_local={:?}", - assigned_from_local, + "annotate_argument_and_return_for_borrow: assigned_from={:?}", + assigned_from, ); - if *assigned_to == mir::RETURN_PLACE && assigned_from_local == target { - return annotated_closure.or_else(fallback); + if let Some(assigned_from_local) = assigned_from.local_or_deref_local() { + debug!( + "annotate_argument_and_return_for_borrow: assigned_from_local={:?}", + assigned_from_local, + ); + + if assigned_to == mir::RETURN_PLACE && assigned_from_local == target { + return annotated_closure.or_else(fallback); + } } } } diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 5e0727d51579f..4036e9db33b34 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -838,12 +838,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .get(location.statement_index) { Some(&Statement { - kind: StatementKind::Assign(box(Place { - base: PlaceBase::Local(local), - projection: box [], - }, _)), + kind: StatementKind::Assign(box(ref place, _)), .. - }) => local, + }) => { + if let Some(local) = place.as_local() { + local + } else { + return OtherUse(use_span); + } + } _ => return OtherUse(use_span), }; diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 75d4b56fdb7c2..c3369e872151a 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1133,15 +1133,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Special case: you can assign a immutable local variable // (e.g., `x = ...`) so long as it has never been initialized // before (at this point in the flow). - if let Place { - base: PlaceBase::Local(local), - projection: box [], - } = place_span.0 { - if let Mutability::Not = self.body.local_decls[*local].mutability { + if let Some(local) = place_span.0.as_local() { + if let Mutability::Not = self.body.local_decls[local].mutability { // check for reassignments to immutable local variables self.check_if_reassignment_to_immutable_state( location, - *local, + local, place_span, flow_state, ); @@ -1288,60 +1285,58 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // captures of a closure are copied/moved directly // when generating MIR. match *operand { - Operand::Move(Place { - base: PlaceBase::Local(local), - projection: box [], - }) | - Operand::Copy(Place { - base: PlaceBase::Local(local), - projection: box [], - }) if self.body.local_decls[local].is_user_variable.is_none() => { - if self.body.local_decls[local].ty.is_mutable_ptr() { - // The variable will be marked as mutable by the borrow. - return; - } - // This is an edge case where we have a `move` closure - // inside a non-move closure, and the inner closure - // contains a mutation: - // - // let mut i = 0; - // || { move || { i += 1; }; }; - // - // In this case our usual strategy of assuming that the - // variable will be captured by mutable reference is - // wrong, since `i` can be copied into the inner - // closure from a shared reference. - // - // As such we have to search for the local that this - // capture comes from and mark it as being used as mut. - - let temp_mpi = self.move_data.rev_lookup.find_local(local); - let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] { - &self.move_data.inits[init_index] - } else { - bug!("temporary should be initialized exactly once") - }; - - let loc = match init.location { - InitLocation::Statement(stmt) => stmt, - _ => bug!("temporary initialized in arguments"), - }; - - let bbd = &self.body[loc.block]; - let stmt = &bbd.statements[loc.statement_index]; - debug!("temporary assigned in: stmt={:?}", stmt); - - if let StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref source))) = stmt.kind { - propagate_closure_used_mut_place(self, source); - } else { - bug!("closures should only capture user variables \ - or references to user variables"); + Operand::Move(ref place) | Operand::Copy(ref place) => { + match place.as_local() { + Some(local) if self.body.local_decls[local].is_user_variable.is_none() => { + if self.body.local_decls[local].ty.is_mutable_ptr() { + // The variable will be marked as mutable by the borrow. + return; + } + // This is an edge case where we have a `move` closure + // inside a non-move closure, and the inner closure + // contains a mutation: + // + // let mut i = 0; + // || { move || { i += 1; }; }; + // + // In this case our usual strategy of assuming that the + // variable will be captured by mutable reference is + // wrong, since `i` can be copied into the inner + // closure from a shared reference. + // + // As such we have to search for the local that this + // capture comes from and mark it as being used as mut. + + let temp_mpi = self.move_data.rev_lookup.find_local(local); + let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] { + &self.move_data.inits[init_index] + } else { + bug!("temporary should be initialized exactly once") + }; + + let loc = match init.location { + InitLocation::Statement(stmt) => stmt, + _ => bug!("temporary initialized in arguments"), + }; + + let bbd = &self.body[loc.block]; + let stmt = &bbd.statements[loc.statement_index]; + debug!("temporary assigned in: stmt={:?}", stmt); + + if let StatementKind::Assign(box (_, Rvalue::Ref(_, _, ref source))) = + stmt.kind + { + propagate_closure_used_mut_place(self, source); + } else { + bug!( + "closures should only capture user variables \ + or references to user variables" + ); + } + } + _ => propagate_closure_used_mut_place(self, place), } } - Operand::Move(ref place) - | Operand::Copy(ref place) => { - propagate_closure_used_mut_place(self, place); - } Operand::Constant(..) => {} } } @@ -1702,7 +1697,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("check_if_assigned_path_is_moved place: {:?}", place); // None case => assigning to `x` does not require `x` be initialized. - let mut cursor = &*place.projection; + let mut cursor = &*place.projection.as_ref(); while let [proj_base @ .., elem] = cursor { cursor = proj_base; diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index 431361fa5a87b..d9e958d945001 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -89,45 +89,41 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // If that ever stops being the case, then the ever initialized // flow could be used. if let Some(StatementKind::Assign( - box( - Place { - base: PlaceBase::Local(local), - projection: box [], - }, - Rvalue::Use(Operand::Move(move_from)) - ) + box(place, Rvalue::Use(Operand::Move(move_from))) )) = self.body.basic_blocks()[location.block] .statements .get(location.statement_index) .map(|stmt| &stmt.kind) { - let local_decl = &self.body.local_decls[*local]; - // opt_match_place is the - // match_span is the span of the expression being matched on - // match *x.y { ... } match_place is Some(*x.y) - // ^^^^ match_span is the span of *x.y - // - // opt_match_place is None for let [mut] x = ... statements, - // whether or not the right-hand side is a place expression - if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { - opt_match_place: Some((ref opt_match_place, match_span)), - binding_mode: _, - opt_ty_info: _, - pat_span: _, - }))) = local_decl.is_user_variable - { - let stmt_source_info = self.body.source_info(location); - self.append_binding_error( - grouped_errors, - kind, - original_path, - move_from, - *local, - opt_match_place, - match_span, - stmt_source_info.span, - ); - return; + if let Some(local) = place.as_local() { + let local_decl = &self.body.local_decls[local]; + // opt_match_place is the + // match_span is the span of the expression being matched on + // match *x.y { ... } match_place is Some(*x.y) + // ^^^^ match_span is the span of *x.y + // + // opt_match_place is None for let [mut] x = ... statements, + // whether or not the right-hand side is a place expression + if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { + opt_match_place: Some((ref opt_match_place, match_span)), + binding_mode: _, + opt_ty_info: _, + pat_span: _, + }))) = local_decl.is_user_variable + { + let stmt_source_info = self.body.source_info(location); + self.append_binding_error( + grouped_errors, + kind, + original_path, + move_from, + local, + opt_match_place, + match_span, + stmt_source_info.span, + ); + return; + } } } @@ -307,11 +303,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All) .find_map(|p| self.is_upvar_field_projection(p)); - let deref_base = match &deref_target_place.projection { - box [proj_base @ .., ProjectionElem::Deref] => { + let deref_base = match deref_target_place.projection.as_ref() { + &[ref proj_base @ .., ProjectionElem::Deref] => { PlaceRef { base: &deref_target_place.base, - projection: proj_base, + projection: &proj_base, } } _ => bug!("deref_target_place is not a deref projection"), diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index 8ab4020394ffd..68b33331a1ffb 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -49,10 +49,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { projection: [], } => { item_msg = format!("`{}`", access_place_desc.unwrap()); - if let Place { - base: PlaceBase::Local(_), - projection: box [], - } = access_place { + if access_place.as_local().is_some() { reason = ", as it is not declared as mutable".to_string(); } else { let name = self.body.local_decls[*local] @@ -153,10 +150,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }), projection: [], } => { - if let Place { - base: PlaceBase::Static(_), - projection: box [], - } = access_place { + if let PlaceRef { + base: &PlaceBase::Static(_), + projection: &[], + } = access_place.as_ref() { item_msg = format!("immutable static item `{}`", access_place_desc.unwrap()); reason = String::new(); } else { diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index b105664399a5c..cae303039a194 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -8,8 +8,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, ProjectionElem, Rvalue, - SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection, + BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, PlaceRef, ProjectionElem, + Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection, }; use rustc::ty::fold::TypeFoldable; use rustc::ty::{self, RegionVid, Ty}; @@ -211,14 +211,14 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> { // - if it's a deeper projection, we have to filter which // of the borrows are killed: the ones whose `borrowed_place` // conflicts with the `place`. - match place { - Place { - base: PlaceBase::Local(local), - projection: box [], + match place.as_ref() { + PlaceRef { + base: &PlaceBase::Local(local), + projection: &[], } | - Place { - base: PlaceBase::Local(local), - projection: box [ProjectionElem::Deref], + PlaceRef { + base: &PlaceBase::Local(local), + projection: &[ProjectionElem::Deref], } => { debug!( "Recording `killed` facts for borrows of local={:?} at location={:?}", @@ -229,21 +229,21 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> { all_facts, self.borrow_set, self.location_table, - local, + &local, location, ); } - Place { - base: PlaceBase::Static(_), + PlaceRef { + base: &PlaceBase::Static(_), .. } => { // Ignore kills of static or static mut variables. } - Place { - base: PlaceBase::Local(local), - projection: box [.., _], + PlaceRef { + base: &PlaceBase::Local(local), + projection: &[.., _], } => { // Kill conflicting borrows of the innermost local. debug!( @@ -252,7 +252,7 @@ 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, diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index 59b2796db7abe..26bead3047d5d 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -6,8 +6,8 @@ use crate::borrow_check::nll::region_infer::{Cause, RegionName}; use crate::borrow_check::nll::ConstraintDescription; use crate::borrow_check::{MirBorrowckCtxt, WriteKind}; use rustc::mir::{ - CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, PlaceBase, - Rvalue, Statement, StatementKind, TerminatorKind, + CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, Rvalue, + Statement, StatementKind, TerminatorKind, }; use rustc::ty::{self, TyCtxt}; use rustc::ty::adjustment::{PointerCast}; @@ -273,12 +273,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut should_note_order = false; if body.local_decls[local].name.is_some() { if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place { - if let Place { - base: PlaceBase::Local(borrowed_local), - projection: box [], - } = place { - if body.local_decls[*borrowed_local].name.is_some() - && local != *borrowed_local + if let Some(borrowed_local) = place.as_local() { + if body.local_decls[borrowed_local].name.is_some() + && local != borrowed_local { should_note_order = true; } @@ -494,22 +491,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Just point to the function, to reduce the chance of overlapping spans. let function_span = match func { Operand::Constant(c) => c.span, - Operand::Copy(Place { - base: PlaceBase::Local(l), - projection: box [], - }) | - Operand::Move(Place { - base: PlaceBase::Local(l), - projection: box [], - }) => { - let local_decl = &self.body.local_decls[*l]; - if local_decl.name.is_none() { - local_decl.source_info.span + Operand::Copy(place) | + Operand::Move(place) => { + if let Some(l) = place.as_local() { + let local_decl = &self.body.local_decls[l]; + if local_decl.name.is_none() { + local_decl.source_info.span + } else { + span + } } else { span } } - _ => span, }; return (LaterUseKind::Call, function_span); } else { @@ -542,14 +536,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // it which simplifies the termination logic. let mut queue = vec![location]; let mut target = if let Some(&Statement { - kind: StatementKind::Assign(box(Place { - base: PlaceBase::Local(local), - projection: box [], - }, _)), + kind: StatementKind::Assign(box(ref place, _)), .. - }) = stmt - { - local + }) = stmt { + if let Some(local) = place.as_local() { + local + } else { + return false; + } } else { return false; }; @@ -582,17 +576,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // If we see a use, we should check whether it is our data, and if so // update the place that we're looking for to that new place. Rvalue::Use(operand) => match operand { - Operand::Copy(Place { - base: PlaceBase::Local(from), - projection: box [], - }) - | Operand::Move(Place { - base: PlaceBase::Local(from), - projection: box [], - }) - if *from == target => - { - target = into; + Operand::Copy(place) + | Operand::Move(place) => { + if let Some(from) = place.as_local() { + if from == target { + target = into; + } + } } _ => {} }, @@ -601,28 +591,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Rvalue::Cast( CastKind::Pointer(PointerCast::Unsize), operand, ty ) => match operand { - Operand::Copy(Place { - base: PlaceBase::Local(from), - projection: box [], - }) - | Operand::Move(Place { - base: PlaceBase::Local(from), - projection: box [], - }) - if *from == target => - { - debug!("was_captured_by_trait_object: ty={:?}", ty); - // Check the type for a trait object. - return match ty.kind { - // `&dyn Trait` - ty::Ref(_, ty, _) if ty.is_trait() => true, - // `Box` - _ if ty.is_box() && ty.boxed_ty().is_trait() => true, - // `dyn Trait` - _ if ty.is_trait() => true, - // Anything else. - _ => false, - }; + Operand::Copy(place) + | Operand::Move(place) => { + if let Some(from) = place.as_local() { + if from == target { + debug!("was_captured_by_trait_object: ty={:?}", ty); + // Check the type for a trait object. + return match ty.kind { + // `&dyn Trait` + ty::Ref(_, ty, _) if ty.is_trait() => true, + // `Box` + _ if ty.is_box() && ty.boxed_ty().is_trait() => true, + // `dyn Trait` + _ if ty.is_trait() => true, + // Anything else. + _ => false, + }; + } + } + return false; } _ => return false, }, @@ -638,34 +625,33 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("was_captured_by_trait_object: terminator={:?}", terminator); if let TerminatorKind::Call { - destination: Some((Place { - base: PlaceBase::Local(dest), - projection: box [], - }, block)), + destination: Some((place, block)), args, .. - } = &terminator.kind - { - debug!( - "was_captured_by_trait_object: target={:?} dest={:?} args={:?}", - target, dest, args - ); - // Check if one of the arguments to this function is the target place. - let found_target = args.iter().any(|arg| { - if let Operand::Move(Place { - base: PlaceBase::Local(potential), - projection: box [], - }) = arg { - *potential == target - } else { - false - } - }); + } = &terminator.kind { + if let Some(dest) = place.as_local() { + debug!( + "was_captured_by_trait_object: target={:?} dest={:?} args={:?}", + target, dest, args + ); + // Check if one of the arguments to this function is the target place. + let found_target = args.iter().any(|arg| { + if let Operand::Move(place) = arg { + if let Some(potential) = place.as_local() { + potential == target + } else { + false + } + } else { + false + } + }); - // If it is, follow this to the next block and update the target. - if found_target { - target = *dest; - queue.push(block.start_location()); + // If it is, follow this to the next block and update the target. + if found_target { + target = dest; + queue.push(block.start_location()); + } } } } diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index 9ecd6f837750e..d949c7e01aab7 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -1,5 +1,5 @@ use rustc::ty::subst::SubstsRef; -use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::mir::{Body, Location, PlaceElem, Promoted}; use rustc::mir::visit::{MutVisitor, TyContext}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; @@ -54,6 +54,10 @@ impl<'a, 'tcx> NLLVisitor<'a, 'tcx> { } impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) { debug!("visit_ty(ty={:?}, ty_context={:?})", ty, ty_context); diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index ed639e8eee774..b5560fe6751bd 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -480,13 +480,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { if place.projection.is_empty() { if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { - let is_promoted = match place { - Place { - base: PlaceBase::Static(box Static { + let is_promoted = match place.as_ref() { + PlaceRef { + base: &PlaceBase::Static(box Static { kind: StaticKind::Promoted(..), .. }), - projection: box [], + projection: &[], } => true, _ => false, }; @@ -1366,11 +1366,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // they are not caused by the user, but rather artifacts // of lowering. Assignments to other sorts of places *are* interesting // though. - let category = match *place { - Place { - base: PlaceBase::Local(RETURN_PLACE), - projection: box [], - } => if let BorrowCheckContext { + let category = match place.as_local() { + Some(RETURN_PLACE) => if let BorrowCheckContext { universal_regions: UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), @@ -1386,10 +1383,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } else { ConstraintCategory::Return }, - Place { - base: PlaceBase::Local(l), - projection: box [], - } if !body.local_decls[l].is_user_variable.is_some() => { + Some(l) if !body.local_decls[l].is_user_variable.is_some() => { ConstraintCategory::Boring } _ => ConstraintCategory::Assignment, @@ -1675,11 +1669,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Some((ref dest, _target_block)) => { let dest_ty = dest.ty(body, tcx).ty; let dest_ty = self.normalize(dest_ty, term_location); - let category = match *dest { - Place { - base: PlaceBase::Local(RETURN_PLACE), - projection: box [], - } => { + let category = match dest.as_local() { + Some(RETURN_PLACE) => { if let BorrowCheckContext { universal_regions: UniversalRegions { @@ -1698,10 +1689,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ConstraintCategory::Return } } - Place { - base: PlaceBase::Local(l), - projection: box [], - } if !body.local_decls[l].is_user_variable.is_some() => { + Some(l) if !body.local_decls[l].is_user_variable.is_some() => { ConstraintCategory::Boring } _ => ConstraintCategory::Assignment, @@ -2432,7 +2420,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { location, borrow_region, borrowed_place ); - let mut cursor = &*borrowed_place.projection; + let mut cursor = borrowed_place.projection.as_ref(); while let [proj_base @ .., elem] = cursor { cursor = proj_base; diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 9dd3e119c217a..264e4807af07e 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -64,14 +64,8 @@ pub(super) fn borrow_conflicts_with_place<'tcx>( // This Local/Local case is handled by the more general code below, but // it's so common that it's a speed win to check for it first. - if let Place { - base: PlaceBase::Local(l1), - projection: box [], - } = borrow_place { - if let PlaceRef { - base: PlaceBase::Local(l2), - projection: [], - } = access_place { + if let Some(l1) = borrow_place.as_local() { + if let Some(l2) = access_place.as_local() { return l1 == l2; } } diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs index 695080dfe23d9..95471afb7884f 100644 --- a/src/librustc_mir/borrow_check/used_muts.rs +++ b/src/librustc_mir/borrow_check/used_muts.rs @@ -1,7 +1,5 @@ use rustc::mir::visit::{PlaceContext, Visitor}; -use rustc::mir::{ - Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind -}; +use rustc::mir::{Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind}; use rustc_data_structures::fx::FxHashSet; @@ -118,10 +116,7 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc "assignment of {:?} to {:?}, adding {:?} to used mutable set", path.place, local, path.place ); - if let Place { - base: PlaceBase::Local(user_local), - projection: box [], - } = path.place { + if let Some(user_local) = path.place.as_local() { self.mbcx.used_mut.insert(user_local); } } diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 60fe37e26e9ad..8d2bef39bed42 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -6,7 +6,7 @@ use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::hair::*; use rustc::mir::interpret::{PanicInfo::BoundsCheck}; use rustc::mir::*; -use rustc::ty::{CanonicalUserTypeAnnotation, Ty, Variance}; +use rustc::ty::{CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance}; use rustc_index::vec::Idx; @@ -23,10 +23,10 @@ struct PlaceBuilder<'tcx> { } impl PlaceBuilder<'tcx> { - fn into_place(self) -> Place<'tcx> { + fn into_place(self, tcx: TyCtxt<'tcx>) -> Place<'tcx> { Place { base: self.base, - projection: self.projection.into_boxed_slice(), + projection: tcx.intern_place_elems(&self.projection), } } @@ -73,7 +73,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { M: Mirror<'tcx, Output = Expr<'tcx>>, { let place_builder = unpack!(block = self.as_place_builder(block, expr)); - block.and(place_builder.into_place()) + block.and(place_builder.into_place(self.hir.tcx())) } /// This is used when constructing a compound `Place`, so that we can avoid creating @@ -96,7 +96,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { M: Mirror<'tcx, Output = Expr<'tcx>>, { let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr)); - block.and(place_builder.into_place()) + block.and(place_builder.into_place(self.hir.tcx())) } /// This is used when constructing a compound `Place`, so that we can avoid creating @@ -165,7 +165,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Mutability::Not, )); - let slice = place_builder.clone().into_place(); + let slice = place_builder.clone().into_place(this.hir.tcx()); // bounds check: let (len, lt) = ( this.temp(usize_ty.clone(), expr_span), @@ -225,7 +225,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ); - let place = place_builder.clone().into_place(); + let place = place_builder.clone().into_place(this.hir.tcx()); this.cfg.push( block, Statement { diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 87d95a751534d..4f1ac8e51dc20 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -139,7 +139,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // initialize the box contents: unpack!( block = this.into( - &Place::from(result).deref(), + &this.hir.tcx().mk_place_deref(Place::from(result)), block, value ) ); @@ -296,8 +296,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .zip(field_types.into_iter()) .map(|(n, ty)| match fields_map.get(&n) { Some(v) => v.clone(), - None => this.consume_by_copy_or_move(base.clone().field(n, ty)), - }).collect() + None => this.consume_by_copy_or_move(this.hir.tcx().mk_place_field( + base.clone(), + n, + ty, + )), + }) + .collect() } else { field_names .iter() @@ -397,8 +402,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let val_fld = Field::new(0); let of_fld = Field::new(1); - let val = result_value.clone().field(val_fld, ty); - let of = result_value.field(of_fld, bool_ty); + let tcx = self.hir.tcx(); + let val = tcx.mk_place_field(result_value.clone(), val_fld, ty); + let of = tcx.mk_place_field(result_value, of_fld, bool_ty); let err = PanicInfo::Overflow(op); @@ -496,14 +502,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let arg_place = unpack!(block = this.as_place(block, arg)); - let mutability = match arg_place { - Place { - base: PlaceBase::Local(local), - projection: box [], + let mutability = match arg_place.as_ref() { + PlaceRef { + base: &PlaceBase::Local(local), + projection: &[], } => this.local_decls[local].mutability, - Place { - base: PlaceBase::Local(local), - projection: box [ProjectionElem::Deref], + PlaceRef { + base: &PlaceBase::Local(local), + projection: &[ProjectionElem::Deref], } => { debug_assert!( this.local_decls[local].is_ref_for_guard(), @@ -511,13 +517,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); this.local_decls[local].mutability } - Place { + PlaceRef { ref base, - projection: box [ref proj_base @ .., ProjectionElem::Field(upvar_index, _)], + projection: &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _)], } - | Place { + | PlaceRef { ref base, - projection: box [ + projection: &[ ref proj_base @ .., ProjectionElem::Field(upvar_index, _), ProjectionElem::Deref diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 8a6bc5a2a764e..e7388b920548b 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -235,7 +235,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }); let ptr_temp = Place::from(ptr_temp); let block = unpack!(this.into(&ptr_temp, block, ptr)); - this.into(&ptr_temp.deref(), block, val) + this.into(&this.hir.tcx().mk_place_deref(ptr_temp), block, val) } else { let args: Vec<_> = args .into_iter() diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 2e451fc88d95c..667b37bbd80c8 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -948,7 +948,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fake_borrows.insert(Place { base: source.base.clone(), - projection: proj_base.to_vec().into_boxed_slice(), + projection: self.hir.tcx().intern_place_elems(proj_base), }); } } @@ -1293,7 +1293,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Insert a Shallow borrow of the prefixes of any fake borrows. for place in fake_borrows { - let mut cursor = &*place.projection; + let mut cursor = place.projection.as_ref(); while let [proj_base @ .., elem] = cursor { cursor = proj_base; @@ -1488,7 +1488,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { BorrowKind::Shallow, Place { base: place.base.clone(), - projection: place.projection.to_vec().into_boxed_slice(), + projection: tcx.intern_place_elems(place.projection), }, ); self.cfg.push_assign( diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index 3826e5e3ba5e6..9b7bccca2ddf3 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -166,7 +166,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } }); if irrefutable { - let place = match_pair.place.downcast(adt_def, variant_index); + let place = tcx.mk_place_downcast(match_pair.place, adt_def, variant_index); candidate.match_pairs.extend(self.field_match_pairs(place, subpatterns)); Ok(()) } else { @@ -191,7 +191,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } PatKind::Deref { ref subpattern } => { - let place = match_pair.place.deref(); + let place = tcx.mk_place_deref(match_pair.place); candidate.match_pairs.push(MatchPair::new(place, subpattern)); Ok(()) } diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index a04c989e6e0de..5c2f72c0a061f 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -743,22 +743,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidate: &mut Candidate<'pat, 'tcx>, ) { let match_pair = candidate.match_pairs.remove(match_pair_index); + let tcx = self.hir.tcx(); // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`, // we want to create a set of derived match-patterns like // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`. let elem = ProjectionElem::Downcast( Some(adt_def.variants[variant_index].ident.name), variant_index); - let downcast_place = match_pair.place.elem(elem); // `(x as Variant)` - let consequent_match_pairs = - subpatterns.iter() - .map(|subpattern| { - // e.g., `(x as Variant).0` - let place = downcast_place.clone().field(subpattern.field, - subpattern.pattern.ty); - // e.g., `(x as Variant).0 @ P1` - MatchPair::new(place, &subpattern.pattern) - }); + let downcast_place = tcx.mk_place_elem(match_pair.place, elem); // `(x as Variant)` + let consequent_match_pairs = subpatterns.iter().map(|subpattern| { + // e.g., `(x as Variant).0` + let place = + tcx.mk_place_field(downcast_place.clone(), subpattern.field, subpattern.pattern.ty); + // e.g., `(x as Variant).0 @ P1` + MatchPair::new(place, &subpattern.pattern) + }); candidate.match_pairs.extend(consequent_match_pairs); } diff --git a/src/librustc_mir/build/matches/util.rs b/src/librustc_mir/build/matches/util.rs index 83fb924af6381..917535f31dc4b 100644 --- a/src/librustc_mir/build/matches/util.rs +++ b/src/librustc_mir/build/matches/util.rs @@ -6,17 +6,22 @@ use std::u32; use std::convert::TryInto; impl<'a, 'tcx> Builder<'a, 'tcx> { - pub fn field_match_pairs<'pat>(&mut self, - place: Place<'tcx>, - subpatterns: &'pat [FieldPat<'tcx>]) - -> Vec> { - subpatterns.iter() - .map(|fieldpat| { - let place = place.clone().field(fieldpat.field, - fieldpat.pattern.ty); - MatchPair::new(place, &fieldpat.pattern) - }) - .collect() + pub fn field_match_pairs<'pat>( + &mut self, + place: Place<'tcx>, + subpatterns: &'pat [FieldPat<'tcx>], + ) -> Vec> { + subpatterns + .iter() + .map(|fieldpat| { + let place = self.hir.tcx().mk_place_field( + place.clone(), + fieldpat.field, + fieldpat.pattern.ty, + ); + MatchPair::new(place, &fieldpat.pattern) + }) + .collect() } pub fn prefix_slice_suffix<'pat>(&mut self, @@ -27,6 +32,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { suffix: &'pat [Pat<'tcx>]) { let min_length = prefix.len() + suffix.len(); let min_length = min_length.try_into().unwrap(); + let tcx = self.hir.tcx(); match_pairs.extend( prefix.iter() @@ -37,13 +43,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { min_length, from_end: false, }; - let place = place.clone().elem(elem); + let place = tcx.mk_place_elem(place.clone(), elem); MatchPair::new(place, subpattern) }) ); if let Some(subslice_pat) = opt_slice { - let subslice = place.clone().elem(ProjectionElem::Subslice { + let subslice = tcx.mk_place_elem(place.clone(),ProjectionElem::Subslice { from: prefix.len() as u32, to: suffix.len() as u32 }); @@ -60,7 +66,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { min_length, from_end: true, }; - let place = place.clone().elem(elem); + let place = tcx.mk_place_elem(place.clone(), elem); MatchPair::new(place, subpattern) }) ); diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index a749b4263ea64..1b3d8641f204e 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -926,46 +926,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // If constants and statics, we don't generate StorageLive for this // temporary, so don't try to generate StorageDead for it either. _ if self.local_scope().is_none() => (), - Operand::Copy(Place { - base: PlaceBase::Local(cond_temp), - projection: box [], - }) - | Operand::Move(Place { - base: PlaceBase::Local(cond_temp), - projection: box [], - }) => { - // Manually drop the condition on both branches. - let top_scope = self.scopes.scopes.last_mut().unwrap(); - let top_drop_data = top_scope.drops.pop().unwrap(); - - match top_drop_data.kind { - DropKind::Value { .. } => { - bug!("Drop scheduled on top of condition variable") - } - DropKind::Storage => { - let source_info = top_scope.source_info(top_drop_data.span); - let local = top_drop_data.local; - assert_eq!(local, cond_temp, "Drop scheduled on top of condition"); - self.cfg.push( - true_block, - Statement { - source_info, - kind: StatementKind::StorageDead(local) - }, - ); - self.cfg.push( - false_block, - Statement { - source_info, - kind: StatementKind::StorageDead(local) - }, - ); + Operand::Copy(place) + | Operand::Move(place) => { + if let Some(cond_temp) = place.as_local() { + // Manually drop the condition on both branches. + let top_scope = self.scopes.scopes.last_mut().unwrap(); + let top_drop_data = top_scope.drops.pop().unwrap(); + + match top_drop_data.kind { + DropKind::Value { .. } => { + bug!("Drop scheduled on top of condition variable") + } + DropKind::Storage => { + let source_info = top_scope.source_info(top_drop_data.span); + let local = top_drop_data.local; + assert_eq!(local, cond_temp, "Drop scheduled on top of condition"); + self.cfg.push( + true_block, + Statement { + source_info, + kind: StatementKind::StorageDead(local) + }, + ); + self.cfg.push( + false_block, + Statement { + source_info, + kind: StatementKind::StorageDead(local) + }, + ); + } } - } - top_scope.invalidate_cache(true, self.is_generator, true); + top_scope.invalidate_cache(true, self.is_generator, true); + } else { + bug!("Expected as_local_operand to produce a temporary"); + } } - _ => bug!("Expected as_local_operand to produce a temporary"), } (true_block, false_block) diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs index c1695ba66d0d5..1b81032bfe62f 100644 --- a/src/librustc_mir/dataflow/impls/storage_liveness.rs +++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs @@ -157,10 +157,12 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> { // Since `propagate_call_unwind` doesn't exist, we have to kill the // destination here, and then gen it again in `propagate_call_return`. if let TerminatorKind::Call { - destination: Some((Place { base: PlaceBase::Local(local), projection: box [] }, _)), + destination: Some((ref place, _)), .. } = self.body[loc.block].terminator().kind { - sets.kill(local); + if let Some(local) = place.as_local() { + sets.kill(local); + } } self.check_for_move(sets, loc); } diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 53b18e4364b95..52016d4c9363a 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -114,7 +114,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { BorrowedContent { target_place: Place { base: place.base.clone(), - projection: proj.to_vec().into_boxed_slice(), + projection: tcx.intern_place_elems(proj), }, }, )); @@ -172,7 +172,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { Some(base), Place { base: place.base.clone(), - projection: proj.to_vec().into_boxed_slice(), + projection: tcx.intern_place_elems(proj), }, ); ent.insert(path); @@ -274,7 +274,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { // Box starts out uninitialized - need to create a separate // move-path for the interior so it will be separate from // the exterior. - self.create_move_path(&place.clone().deref()); + self.create_move_path(&self.builder.tcx.mk_place_deref(place.clone())); self.gather_init(place.as_ref(), InitKind::Shallow); } else { self.gather_init(place.as_ref(), InitKind::Deep); diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index f5a03316d809c..b599f4799446d 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -327,7 +327,7 @@ impl<'tcx> MoveData<'tcx> { pub fn base_local(&self, mut mpi: MovePathIndex) -> Option { loop { let path = &self.move_paths[mpi]; - if let Place { base: PlaceBase::Local(l), projection: box [] } = path.place { + if let Some(l) = path.place.as_local() { return Some(l); } if let Some(parent) = path.parent { diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index f532a18072fbd..177639956f717 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -117,7 +117,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx run_passes(tcx, &mut result, instance, None, MirPhase::Const, &[ &add_moves_for_packed_drops::AddMovesForPackedDrops, - &no_landing_pads::NoLandingPads, + &no_landing_pads::NoLandingPads::new(tcx), &remove_noop_landing_pads::RemoveNoopLandingPads, &simplify::SimplifyCfg::new("make_shim"), &add_call_guards::CriticalCallEdges, @@ -231,7 +231,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) tcx, param_env }; - let dropee = dropee_ptr.deref(); + let dropee = tcx.mk_place_deref(dropee_ptr); let resume_block = elaborator.patch.resume_block(); elaborate_drops::elaborate_drop( &mut elaborator, @@ -312,7 +312,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) - let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env, builder.span); let dest = Place::return_place(); - let src = Place::from(Local::new(1+0)).deref(); + let src = tcx.mk_place_deref(Place::from(Local::new(1+0))); match self_ty.kind { _ if is_copy => builder.copy_shim(), @@ -415,7 +415,7 @@ impl CloneShimBuilder<'tcx> { } fn copy_shim(&mut self) { - let rcvr = Place::from(Local::new(1+0)).deref(); + let rcvr = self.tcx.mk_place_deref(Place::from(Local::new(1+0))); let ret_statement = self.make_statement( StatementKind::Assign( box( @@ -561,8 +561,8 @@ impl CloneShimBuilder<'tcx> { // BB #2 // `dest[i] = Clone::clone(src[beg])`; // Goto #3 if ok, #5 if unwinding happens. - let dest_field = dest.clone().index(beg); - let src_field = src.index(beg); + let dest_field = self.tcx.mk_place_index(dest.clone(), beg); + let src_field = self.tcx.mk_place_index(src, beg); self.make_clone_call(dest_field, src_field, ty, BasicBlock::new(3), BasicBlock::new(5)); @@ -616,7 +616,7 @@ impl CloneShimBuilder<'tcx> { // BB #7 (cleanup) // `drop(dest[beg])`; self.block(vec![], TerminatorKind::Drop { - location: dest.index(beg), + location: self.tcx.mk_place_index(dest, beg), target: BasicBlock::new(8), unwind: None, }, true); @@ -648,9 +648,9 @@ impl CloneShimBuilder<'tcx> { let mut previous_field = None; for (i, ity) in tys.enumerate() { let field = Field::new(i); - let src_field = src.clone().field(field, ity); + let src_field = self.tcx.mk_place_field(src.clone(), field, ity); - let dest_field = dest.clone().field(field, ity); + let dest_field = self.tcx.mk_place_field(dest.clone(), field, ity); // #(2i + 1) is the cleanup block for the previous clone operation let cleanup_block = self.block_index_offset(1); @@ -721,14 +721,14 @@ fn build_call_shim<'tcx>( let rcvr = match rcvr_adjustment { Adjustment::Identity => Operand::Move(rcvr_l), - Adjustment::Deref => Operand::Copy(rcvr_l.deref()), + Adjustment::Deref => Operand::Copy(tcx.mk_place_deref(rcvr_l)), Adjustment::DerefMove => { // fn(Self, ...) -> fn(*mut Self, ...) let arg_ty = local_decls[rcvr_arg].ty; debug_assert!(tcx.generics_of(def_id).has_self && arg_ty == tcx.types.self_param); local_decls[rcvr_arg].ty = tcx.mk_mut_ptr(arg_ty); - Operand::Move(rcvr_l.deref()) + Operand::Move(tcx.mk_place_deref(rcvr_l)) } Adjustment::RefMut => { // let rcvr = &mut rcvr; @@ -772,7 +772,7 @@ fn build_call_shim<'tcx>( if let Some(untuple_args) = untuple_args { args.extend(untuple_args.iter().enumerate().map(|(i, ity)| { let arg_place = Place::from(Local::new(1+1)); - Operand::Move(arg_place.field(Field::new(i), *ity)) + Operand::Move(tcx.mk_place_field(arg_place, Field::new(i), *ity)) })); } else { args.extend((1..sig.inputs().len()).map(|i| { @@ -901,6 +901,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &Body<'_> { )), AggregateKind::Adt(adt_def, variant_index, substs, None, None), source_info, + tcx, ).collect(); let start_block = BasicBlockData { diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs index 40007eb3c4a3e..c8605e22e1084 100644 --- a/src/librustc_mir/transform/check_consts/qualifs.rs +++ b/src/librustc_mir/transform/check_consts/qualifs.rs @@ -164,8 +164,8 @@ pub trait Qualif { Rvalue::Ref(_, _, ref place) => { // Special-case reborrows to be more like a copy of the reference. - if let box [proj_base @ .., elem] = &place.projection { - if ProjectionElem::Deref == *elem { + if let &[ref proj_base @ .., elem] = place.projection.as_ref() { + if ProjectionElem::Deref == elem { let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty; if let ty::Ref(..) = base_ty.kind { return Self::in_place(cx, per_local, PlaceRef { diff --git a/src/librustc_mir/transform/check_consts/resolver.rs b/src/librustc_mir/transform/check_consts/resolver.rs index 4fa4eba4c23b6..fc9290d638018 100644 --- a/src/librustc_mir/transform/check_consts/resolver.rs +++ b/src/librustc_mir/transform/check_consts/resolver.rs @@ -56,16 +56,16 @@ where fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) { debug_assert!(!place.is_indirect()); - match (value, place) { - (true, mir::Place { base: mir::PlaceBase::Local(local), .. }) => { - self.qualifs_per_local.insert(*local); + match (value, place.as_ref()) { + (true, mir::PlaceRef { base: &mir::PlaceBase::Local(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::Place { base: mir::PlaceBase::Local(_local), projection: box [] }) => { + (false, mir::PlaceRef { base: &mir::PlaceBase::Local(_local), projection: &[] }) => { // self.qualifs_per_local.remove(*local); } @@ -101,11 +101,10 @@ where // If a local with no projections is moved from (e.g. `x` in `y = x`), record that // it no longer needs to be dropped. - if let mir::Operand::Move(mir::Place { - base: mir::PlaceBase::Local(local), - projection: box [], - }) = *operand { - self.qualifs_per_local.remove(local); + if let mir::Operand::Move(place) = operand { + if let Some(local) = place.as_local() { + 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 87cd39b02cd97..76a73adf03836 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -244,8 +244,8 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { if let Rvalue::Ref(_, kind, ref place) = *rvalue { // Special-case reborrows to be more like a copy of a reference. let mut reborrow_place = None; - if let box [proj_base @ .., elem] = &place.projection { - if *elem == ProjectionElem::Deref { + if let &[ref proj_base @ .., elem] = place.projection.as_ref() { + if elem == ProjectionElem::Deref { let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty; if let ty::Ref(..) = base_ty.kind { reborrow_place = Some(proj_base); @@ -376,12 +376,15 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { ); if rvalue_has_mut_interior { - let is_derived_from_illegal_borrow = match *borrowed_place { + let is_derived_from_illegal_borrow = match borrowed_place.as_local() { // If an unprojected local was borrowed and its value was the result of an // illegal borrow, suppress this error and mark the result of this borrow as // illegal as well. - Place { base: PlaceBase::Local(borrowed_local), projection: box [] } - if self.derived_from_illegal_borrow.contains(borrowed_local) => true, + Some(borrowed_local) + if self.derived_from_illegal_borrow.contains(borrowed_local) => + { + true + } // Otherwise proceed normally: check the legality of a mutable borrow in this // context. @@ -394,7 +397,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { // FIXME: should we also clear `derived_from_illegal_borrow` when a local is // assigned a new value? if is_derived_from_illegal_borrow { - if let Place { base: PlaceBase::Local(dest), projection: box [] } = *dest { + if let Some(dest) = dest.as_local() { self.derived_from_illegal_borrow.insert(dest); } } @@ -571,10 +574,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { return; } - let needs_drop = if let Place { - base: PlaceBase::Local(local), - projection: box [], - } = *dropped_place { + let needs_drop = if let Some(local) = dropped_place.as_local() { // Use the span where the local was declared as the span of the drop error. err_span = self.body.local_decls[local].source_info.span; self.qualifs.needs_drop.contains(local) diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 3ff36e01275b9..d9b983ab790c2 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -406,8 +406,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { place: &Place<'tcx>, is_mut_use: bool, ) { - let mut cursor = &*place.projection; - while let [proj_base @ .., elem] = cursor { + let mut cursor = place.projection.as_ref(); + while let &[ref proj_base @ .., elem] = cursor { cursor = proj_base; match elem { diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs index ea173279aa073..4fd4fe45cd4f1 100644 --- a/src/librustc_mir/transform/cleanup_post_borrowck.rs +++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs @@ -24,16 +24,22 @@ use crate::transform::{MirPass, MirSource}; pub struct CleanupNonCodegenStatements; -pub struct DeleteNonCodegenStatements; +pub struct DeleteNonCodegenStatements<'tcx> { + tcx: TyCtxt<'tcx>, +} impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements { - fn run_pass(&self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { - let mut delete = DeleteNonCodegenStatements; + fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { + let mut delete = DeleteNonCodegenStatements { tcx }; delete.visit_body(body); } } -impl<'tcx> MutVisitor<'tcx> for DeleteNonCodegenStatements { +impl<'tcx> MutVisitor<'tcx> for DeleteNonCodegenStatements<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 108c6c9786b2a..13097a2156167 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -7,10 +7,9 @@ use std::cell::Cell; use rustc::hir::def::DefKind; use rustc::hir::def_id::DefId; use rustc::mir::{ - AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue, - Local, UnOp, StatementKind, Statement, LocalKind, - TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp, - SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock, + AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue, Local, UnOp, + StatementKind, Statement, LocalKind, TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, + BinOp, SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock, }; use rustc::mir::visit::{ Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext, @@ -525,18 +524,21 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // (e.g. for CTFE) it can never happen. But here in const_prop // unknown data is uninitialized, so if e.g. a function argument is unsized // and has a reference taken, we get an ICE. - Rvalue::Ref(_, _, Place { base: PlaceBase::Local(local), projection: box [] }) => { - trace!("checking Ref({:?})", place); - let alive = - if let LocalValue::Live(_) = self.ecx.frame().locals[*local].value { - true - } else { - false - }; + Rvalue::Ref(_, _, place_ref) => { + trace!("checking Ref({:?})", place_ref); - if !alive { - trace!("skipping Ref({:?}) to uninitialized local", place); - return None; + if let Some(local) = place_ref.as_local() { + let alive = + if let LocalValue::Live(_) = self.ecx.frame().locals[local].value { + true + } else { + false + }; + + if !alive { + trace!("skipping Ref({:?}) to uninitialized local", place); + return None; + } } } @@ -685,6 +687,10 @@ impl<'tcx> Visitor<'tcx> for CanConstProp { } impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_constant( &mut self, constant: &mut Constant<'tcx>, @@ -706,10 +712,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { .ty(&self.local_decls, self.tcx) .ty; if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) { - if let Place { - base: PlaceBase::Local(local), - projection: box [], - } = *place { + if let Some(local) = place.as_local() { let source = statement.source_info; if let Some(()) = self.const_prop(rval, place_layout, source, place) { if self.can_const_prop[local] { diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 28f97f41b50cf..4c26feac4af79 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -19,9 +19,7 @@ //! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the //! future. -use rustc::mir::{ - Constant, Local, LocalKind, Location, Place, PlaceBase, Body, Operand, Rvalue, StatementKind -}; +use rustc::mir::{Constant, Local, LocalKind, Location, Place, Body, Operand, Rvalue, StatementKind}; use rustc::mir::visit::MutVisitor; use rustc::ty::TyCtxt; use crate::transform::{MirPass, MirSource}; @@ -92,28 +90,32 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation { }; // That use of the source must be an assignment. - match statement.kind { - StatementKind::Assign( - box( - Place { - base: PlaceBase::Local(local), - projection: box [], - }, - Rvalue::Use(ref operand) - ) - ) if local == dest_local => { - let maybe_action = match *operand { - Operand::Copy(ref src_place) | - Operand::Move(ref src_place) => { - Action::local_copy(&body, &def_use_analysis, src_place) - } - Operand::Constant(ref src_constant) => { - Action::constant(src_constant) + match &statement.kind { + StatementKind::Assign(box(place, Rvalue::Use(operand))) => { + if let Some(local) = place.as_local() { + if local == dest_local { + let maybe_action = match operand { + Operand::Copy(ref src_place) | + Operand::Move(ref src_place) => { + Action::local_copy(&body, &def_use_analysis, src_place) + } + Operand::Constant(ref src_constant) => { + Action::constant(src_constant) + } + }; + match maybe_action { + Some(this_action) => action = this_action, + None => continue, + } + } else { + debug!(" Can't copy-propagate local: source use is not an \ + assignment"); + continue } - }; - match maybe_action { - Some(this_action) => action = this_action, - None => continue, + } else { + debug!(" Can't copy-propagate local: source use is not an \ + assignment"); + continue } } _ => { @@ -124,7 +126,8 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation { } } - changed = action.perform(body, &def_use_analysis, dest_local, location) || changed; + changed = + action.perform(body, &def_use_analysis, dest_local, location, tcx) || changed; // FIXME(pcwalton): Update the use-def chains to delete the instructions instead of // regenerating the chains. break @@ -148,31 +151,20 @@ fn eliminate_self_assignments( for def in dest_use_info.defs_not_including_drop() { let location = def.location; if let Some(stmt) = body[location.block].statements.get(location.statement_index) { - match stmt.kind { - StatementKind::Assign( - box( - Place { - base: PlaceBase::Local(local), - projection: box [], - }, - Rvalue::Use(Operand::Copy(Place { - base: PlaceBase::Local(src_local), - projection: box [], - })), - ) - ) | - StatementKind::Assign( - box( - Place { - base: PlaceBase::Local(local), - projection: box [], - }, - Rvalue::Use(Operand::Move(Place { - base: PlaceBase::Local(src_local), - projection: box [], - })), - ) - ) if local == dest_local && dest_local == src_local => {} + match &stmt.kind { + StatementKind::Assign(box (place, Rvalue::Use(Operand::Copy(src_place)))) + | StatementKind::Assign(box (place, Rvalue::Use(Operand::Move(src_place)))) => { + if let (Some(local), Some(src_local)) = + (place.as_local(), src_place.as_local()) + { + if local == dest_local && dest_local == src_local { + } else { + continue; + } + } else { + continue; + } + } _ => { continue; } @@ -198,10 +190,7 @@ impl<'tcx> Action<'tcx> { fn local_copy(body: &Body<'tcx>, def_use_analysis: &DefUseAnalysis, src_place: &Place<'tcx>) -> Option> { // The source must be a local. - let src_local = if let Place { - base: PlaceBase::Local(local), - projection: box [], - } = *src_place { + let src_local = if let Some(local) = src_place.as_local() { local } else { debug!(" Can't copy-propagate local: source is not a local"); @@ -256,7 +245,8 @@ impl<'tcx> Action<'tcx> { body: &mut Body<'tcx>, def_use_analysis: &DefUseAnalysis, dest_local: Local, - location: Location) + location: Location, + tcx: TyCtxt<'tcx>) -> bool { match self { Action::PropagateLocalCopy(src_local) => { @@ -280,7 +270,7 @@ impl<'tcx> Action<'tcx> { } // Replace all uses of the destination local with the source local. - def_use_analysis.replace_all_defs_and_uses_with(dest_local, body, src_local); + def_use_analysis.replace_all_defs_and_uses_with(dest_local, body, src_local, tcx); // Finally, zap the now-useless assignment instruction. debug!(" Deleting assignment"); @@ -304,7 +294,8 @@ impl<'tcx> Action<'tcx> { // Replace all uses of the destination local with the constant. let mut visitor = ConstantPropagationVisitor::new(dest_local, - src_constant); + src_constant, + tcx); for dest_place_use in &dest_local_info.defs_and_uses { visitor.visit_location(body, dest_place_use.location) } @@ -336,33 +327,42 @@ impl<'tcx> Action<'tcx> { struct ConstantPropagationVisitor<'tcx> { dest_local: Local, constant: Constant<'tcx>, + tcx: TyCtxt<'tcx>, uses_replaced: usize, } impl<'tcx> ConstantPropagationVisitor<'tcx> { - fn new(dest_local: Local, constant: Constant<'tcx>) + fn new(dest_local: Local, constant: Constant<'tcx>, tcx: TyCtxt<'tcx>) -> ConstantPropagationVisitor<'tcx> { ConstantPropagationVisitor { dest_local, constant, + tcx, uses_replaced: 0, } } } impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) { self.super_operand(operand, location); - match *operand { - Operand::Copy(Place { - base: PlaceBase::Local(local), - projection: box [], - }) | - Operand::Move(Place { - base: PlaceBase::Local(local), - projection: box [], - }) if local == self.dest_local => {} + match operand { + Operand::Copy(place) | + Operand::Move(place) => { + if let Some(local) = place.as_local() { + if local == self.dest_local { + } else { + return; + } + } else { + return; + } + } _ => return, } diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs index c1224be6324e2..cdde9e12edcbb 100644 --- a/src/librustc_mir/transform/deaggregator.rs +++ b/src/librustc_mir/transform/deaggregator.rs @@ -45,6 +45,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator { }), *kind, source_info, + tcx, )) }); } diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 439cae2093ae5..b30e2de4ca0bc 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -23,6 +23,10 @@ impl EraseRegionsVisitor<'tcx> { } impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) { *ty = self.tcx.erase_regions(ty); } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 6533e3c5ba81f..911901be36b24 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -74,12 +74,17 @@ use crate::util::liveness; pub struct StateTransform; -struct RenameLocalVisitor { +struct RenameLocalVisitor<'tcx> { from: Local, to: Local, + tcx: TyCtxt<'tcx>, } -impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor { +impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_local(&mut self, local: &mut Local, _: PlaceContext, @@ -102,9 +107,15 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor { } } -struct DerefArgVisitor; +struct DerefArgVisitor<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } -impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor { fn visit_local(&mut self, local: &mut Local, _: PlaceContext, @@ -119,8 +130,8 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor { if place.base == PlaceBase::Local(self_arg()) { replace_base(place, Place { base: PlaceBase::Local(self_arg()), - projection: Box::new([ProjectionElem::Deref]), - }); + projection: self.tcx().intern_place_elems(&vec![ProjectionElem::Deref]), + }, self.tcx); } else { self.visit_place_base(&mut place.base, context, location); @@ -135,9 +146,14 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor { struct PinArgVisitor<'tcx> { ref_gen_ty: Ty<'tcx>, + tcx: TyCtxt<'tcx>, } impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_local(&mut self, local: &mut Local, _: PlaceContext, @@ -145,15 +161,19 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { assert_ne!(*local, self_arg()); } - fn visit_place(&mut self, - place: &mut Place<'tcx>, - context: PlaceContext, - location: Location) { + fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { if place.base == PlaceBase::Local(self_arg()) { - replace_base(place, Place { - base: PlaceBase::Local(self_arg()), - projection: Box::new([ProjectionElem::Field(Field::new(0), self.ref_gen_ty)]), - }); + replace_base( + place, + Place { + base: PlaceBase::Local(self_arg()), + projection: self.tcx().intern_place_elems(&vec![ProjectionElem::Field( + Field::new(0), + self.ref_gen_ty, + )]), + }, + self.tcx, + ); } else { self.visit_place_base(&mut place.base, context, location); @@ -166,13 +186,13 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { } } -fn replace_base(place: &mut Place<'tcx>, new_base: Place<'tcx>) { +fn replace_base<'tcx>(place: &mut Place<'tcx>, new_base: Place<'tcx>, tcx: TyCtxt<'tcx>) { place.base = new_base.base; let mut new_projection = new_base.projection.to_vec(); new_projection.append(&mut place.projection.to_vec()); - place.projection = new_projection.into_boxed_slice(); + place.projection = tcx.intern_place_elems(&new_projection); } fn self_arg() -> Local { @@ -226,13 +246,13 @@ impl TransformVisitor<'tcx> { // Create a Place referencing a generator struct field fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> { let self_place = Place::from(self_arg()); - let base = self_place.downcast_unnamed(variant_index); + let base = self.tcx.mk_place_downcast_unnamed(self_place, variant_index); let mut projection = base.projection.to_vec(); projection.push(ProjectionElem::Field(Field::new(idx), ty)); Place { base: base.base, - projection: projection.into_boxed_slice(), + projection: self.tcx.intern_place_elems(&projection), } } @@ -264,6 +284,10 @@ impl TransformVisitor<'tcx> { } impl MutVisitor<'tcx> for TransformVisitor<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_local(&mut self, local: &mut Local, _: PlaceContext, @@ -280,7 +304,7 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> { 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)); + replace_base(place, self.make_field(variant_index, idx, ty), self.tcx); } } else { self.visit_place_base(&mut place.base, context, location); @@ -375,7 +399,7 @@ fn make_generator_state_argument_indirect<'tcx>( body.local_decls.raw[1].ty = ref_gen_ty; // Add a deref to accesses of the generator state - DerefArgVisitor.visit_body(body); + DerefArgVisitor { tcx }.visit_body(body); } fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { @@ -390,12 +414,13 @@ fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body body.local_decls.raw[1].ty = pin_ref_gen_ty; // Add the Pin field access to accesses of the generator state - PinArgVisitor { ref_gen_ty }.visit_body(body); + PinArgVisitor { ref_gen_ty, tcx }.visit_body(body); } fn replace_result_variable<'tcx>( ret_ty: Ty<'tcx>, body: &mut Body<'tcx>, + tcx: TyCtxt<'tcx>, ) -> Local { let source_info = source_info(body); let new_ret = LocalDecl { @@ -416,6 +441,7 @@ fn replace_result_variable<'tcx>( RenameLocalVisitor { from: RETURN_PLACE, to: new_ret_local, + tcx, }.visit_body(body); new_ret_local @@ -864,17 +890,24 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut for (block, block_data) in body.basic_blocks().iter_enumerated() { let (target, unwind, source_info) = match block_data.terminator() { - &Terminator { + Terminator { source_info, kind: TerminatorKind::Drop { - location: Place { - base: PlaceBase::Local(local), - projection: box [], - }, + location, target, unwind } - } if local == gen => (target, unwind, source_info), + } => { + if let Some(local) = location.as_local() { + if local == gen { + (target, unwind, source_info) + } else { + continue; + } + } else { + continue; + } + } _ => continue, }; let unwind = if block_data.is_cleanup { @@ -884,10 +917,10 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut }; elaborate_drop( &mut elaborator, - source_info, + *source_info, &Place::from(gen), (), - target, + *target, unwind, block, ); @@ -1175,7 +1208,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform { // We rename RETURN_PLACE which has type mir.return_ty to new_ret_local // RETURN_PLACE then is a fresh unused local with type ret_ty. - let new_ret_local = replace_result_variable(ret_ty, body); + let new_ret_local = replace_result_variable(ret_ty, body, tcx); // Extract locals which are live across suspension point into `layout` // `remap` gives a mapping from local indices onto generator struct indices diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 0cbdcedff4780..5a34e3f471f66 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -461,7 +461,7 @@ impl Inliner<'tcx> { }; caller_body[callsite.bb] .statements.push(stmt); - tmp.deref() + self.tcx.mk_place_deref(tmp) } else { destination.0 }; @@ -481,6 +481,7 @@ impl Inliner<'tcx> { return_block, cleanup_block: cleanup, in_cleanup_block: false, + tcx: self.tcx, }; @@ -559,7 +560,8 @@ impl Inliner<'tcx> { let tuple_tmp_args = tuple_tys.iter().enumerate().map(|(i, ty)| { // This is e.g., `tuple_tmp.0` in our example above. - let tuple_field = Operand::Move(tuple.clone().field( + let tuple_field = Operand::Move(tcx.mk_place_field( + tuple.clone(), Field::new(i), ty.expect_ty(), )); @@ -587,13 +589,12 @@ impl Inliner<'tcx> { // FIXME: Analysis of the usage of the arguments to avoid // unnecessary temporaries. - if let Operand::Move(Place { - base: PlaceBase::Local(local), - projection: box [], - }) = arg { - if caller_body.local_kind(local) == LocalKind::Temp { - // Reuse the operand if it's a temporary already - return local; + if let Operand::Move(place) = &arg { + if let Some(local) = place.as_local() { + if caller_body.local_kind(local) == LocalKind::Temp { + // Reuse the operand if it's a temporary already + return local; + } } } @@ -639,6 +640,7 @@ struct Integrator<'a, 'tcx> { return_block: BasicBlock, cleanup_block: Option, in_cleanup_block: bool, + tcx: TyCtxt<'tcx>, } impl<'a, 'tcx> Integrator<'a, 'tcx> { @@ -650,14 +652,9 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> { fn make_integrate_local(&self, local: &Local) -> Local { if *local == RETURN_PLACE { - match self.destination { - Place { - base: PlaceBase::Local(l), - projection: box [], - } => { - return l; - }, - ref place => bug!("Return place is {:?}, not local", place) + match self.destination.as_local() { + Some(l) => return l, + ref place => bug!("Return place is {:?}, not local", place), } } @@ -671,6 +668,10 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> { } impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_local( &mut self, local: &mut Local, @@ -686,17 +687,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { context: PlaceContext, location: Location, ) { - match place { - Place { - base: PlaceBase::Local(RETURN_PLACE), - projection: box [], - } => { - // Return pointer; update the place itself - *place = self.destination.clone(); - }, - _ => { - self.super_place(place, context, location); - } + if let Some(RETURN_PLACE) = place.as_local() { + // Return pointer; update the place itself + *place = self.destination.clone(); + } else { + self.super_place(place, context, location); } } diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index bb98d63b1ee10..a567ed668bfa5 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -1,7 +1,8 @@ //! Performs various peephole optimizations. -use rustc::mir::{Constant, Location, Place, PlaceBase, Body, Operand, ProjectionElem, Rvalue, - Local}; +use rustc::mir::{ + Constant, Location, Place, PlaceBase, PlaceRef, Body, Operand, ProjectionElem, Rvalue, Local +}; use rustc::mir::visit::{MutVisitor, Visitor}; use rustc::ty::{self, TyCtxt}; use rustc::util::nodemap::{FxHashMap, FxHashSet}; @@ -28,32 +29,33 @@ impl<'tcx> MirPass<'tcx> for InstCombine { }; // Then carry out those optimizations. - MutVisitor::visit_body(&mut InstCombineVisitor { optimizations }, body); + MutVisitor::visit_body(&mut InstCombineVisitor { optimizations, tcx }, body); } } pub struct InstCombineVisitor<'tcx> { optimizations: OptimizationList<'tcx>, + tcx: TyCtxt<'tcx>, } impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { if self.optimizations.and_stars.remove(&location) { debug!("replacing `&*`: {:?}", rvalue); - let new_place = match *rvalue { - Rvalue::Ref(_, _, Place { - ref mut base, - projection: ref mut projection @ box [.., _], - }) => { - if let box [proj_l @ .., proj_r] = projection { - let place = Place { - // Replace with dummy - base: mem::replace(base, PlaceBase::Local(Local::new(0))), - projection: proj_l.to_vec().into_boxed_slice(), - }; - *projection = vec![proj_r.clone()].into_boxed_slice(); + let new_place = match rvalue { + Rvalue::Ref(_, _, place) => { + if let &[ref proj_l @ .., proj_r] = place.projection.as_ref() { + place.projection = self.tcx().intern_place_elems(&vec![proj_r.clone()]); - place + Place { + // Replace with dummy + base: mem::replace(&mut place.base, PlaceBase::Local(Local::new(0))), + projection: self.tcx().intern_place_elems(proj_l), + } } else { unreachable!(); } @@ -91,12 +93,14 @@ 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 { - base, - projection: box [proj_base @ .., ProjectionElem::Deref], - }) = rvalue { - if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() { - self.optimizations.and_stars.insert(location); + if let Rvalue::Ref(_, _, place) = rvalue { + if let PlaceRef { + base, + projection: &[ref proj_base @ .., ProjectionElem::Deref], + } = place.as_ref() { + if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() { + self.optimizations.and_stars.insert(location); + } } } diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 7e06729c2c742..dbe6c7845926d 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -228,7 +228,7 @@ fn run_optimization_passes<'tcx>( ) { run_passes(tcx, body, InstanceDef::Item(def_id), promoted, MirPhase::Optimized, &[ // Remove all things only needed by analysis - &no_landing_pads::NoLandingPads, + &no_landing_pads::NoLandingPads::new(tcx), &simplify_branches::SimplifyBranches::new("initial"), &remove_noop_landing_pads::RemoveNoopLandingPads, &cleanup_post_borrowck::CleanupNonCodegenStatements, @@ -238,7 +238,7 @@ fn run_optimization_passes<'tcx>( // These next passes must be executed together &add_call_guards::CriticalCallEdges, &elaborate_drops::ElaborateDrops, - &no_landing_pads::NoLandingPads, + &no_landing_pads::NoLandingPads::new(tcx), // AddMovesForPackedDrops needs to run after drop // elaboration. &add_moves_for_packed_drops::AddMovesForPackedDrops, @@ -257,7 +257,7 @@ fn run_optimization_passes<'tcx>( // Optimizations begin. - &uniform_array_move_out::RestoreSubsliceArrayMoveOut, + &uniform_array_move_out::RestoreSubsliceArrayMoveOut::new(tcx), &inline::Inline, // Lowering generator control-flow and variables diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index 762bb5d44839f..fbd14d9ef6170 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -6,9 +6,17 @@ use rustc::mir::*; use rustc::mir::visit::MutVisitor; use crate::transform::{MirPass, MirSource}; -pub struct NoLandingPads; +pub struct NoLandingPads<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> NoLandingPads<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>) -> Self { + NoLandingPads { tcx } + } +} -impl<'tcx> MirPass<'tcx> for NoLandingPads { +impl<'tcx> MirPass<'tcx> for NoLandingPads<'tcx> { fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { no_landing_pads(tcx, body) } @@ -16,11 +24,15 @@ impl<'tcx> MirPass<'tcx> for NoLandingPads { pub fn no_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { if tcx.sess.no_landing_pads() { - NoLandingPads.visit_body(body); + NoLandingPads::new(tcx).visit_body(body); } } -impl<'tcx> MutVisitor<'tcx> for NoLandingPads { +impl<'tcx> MutVisitor<'tcx> for NoLandingPads<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_terminator_kind(&mut self, kind: &mut TerminatorKind<'tcx>, location: Location) { diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index ad1785417cd93..7a9c489fa791e 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -17,7 +17,7 @@ use rustc::mir::*; use rustc::mir::visit::{PlaceContext, MutatingUseContext, MutVisitor, Visitor}; use rustc::mir::traversal::ReversePostorder; use rustc::ty::subst::InternalSubsts; -use rustc::ty::TyCtxt; +use rustc::ty::{List, TyCtxt}; use syntax_pos::Span; use rustc_index::vec::{IndexVec, Idx}; @@ -321,7 +321,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { ty, def_id, }), - projection: box [], + projection: List::empty(), } }; let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut(); @@ -339,7 +339,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { &mut place.base, promoted_place(ty, span).base, ), - projection: box [], + projection: List::empty(), }) } _ => bug!() @@ -396,6 +396,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { /// Replaces all temporaries with their promoted counterparts. impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_local(&mut self, local: &mut Local, _: PlaceContext, @@ -434,14 +438,13 @@ pub fn promote_candidates<'tcx>( match candidate { Candidate::Repeat(Location { block, statement_index }) | Candidate::Ref(Location { block, statement_index }) => { - match body[block].statements[statement_index].kind { - StatementKind::Assign(box(Place { - base: PlaceBase::Local(local), - projection: box [], - }, _)) => { - if temps[local] == TempState::PromotedOut { - // Already promoted. - continue; + match &body[block].statements[statement_index].kind { + StatementKind::Assign(box(place, _)) => { + if let Some(local) = place.as_local() { + if temps[local] == TempState::PromotedOut { + // Already promoted. + continue; + } } } _ => {} @@ -487,28 +490,30 @@ pub fn promote_candidates<'tcx>( let promoted = |index: Local| temps[index] == TempState::PromotedOut; for block in body.basic_blocks_mut() { block.statements.retain(|statement| { - match statement.kind { - StatementKind::Assign(box(Place { - base: PlaceBase::Local(index), - projection: box [], - }, _)) | + match &statement.kind { + StatementKind::Assign(box(place, _)) => { + if let Some(index) = place.as_local() { + !promoted(index) + } else { + true + } + } StatementKind::StorageLive(index) | StatementKind::StorageDead(index) => { - !promoted(index) + !promoted(*index) } _ => true } }); let terminator = block.terminator_mut(); - match terminator.kind { - TerminatorKind::Drop { location: Place { - base: PlaceBase::Local(index), - projection: box [], - }, target, .. } => { - if promoted(index) { - terminator.kind = TerminatorKind::Goto { - target, - }; + match &terminator.kind { + TerminatorKind::Drop { location: place, target, .. } => { + if let Some(index) = place.as_local() { + if promoted(index) { + terminator.kind = TerminatorKind::Goto { + target: *target, + }; + } } } _ => {} diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index da1abb9747c1a..6aba91f416299 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -292,8 +292,8 @@ trait Qualif { Rvalue::Ref(_, _, ref place) => { // Special-case reborrows to be more like a copy of the reference. - if let box [proj_base @ .., elem] = &place.projection { - if ProjectionElem::Deref == *elem { + if let &[ref proj_base @ .., elem] = place.projection.as_ref() { + if ProjectionElem::Deref == elem { let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty; if let ty::Ref(..) = base_ty.kind { return Self::in_place(cx, PlaceRef { @@ -1041,26 +1041,24 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { match *candidate { Candidate::Repeat(Location { block: bb, statement_index: stmt_idx }) => { if let StatementKind::Assign(box(_, Rvalue::Repeat( - Operand::Move(Place { - base: PlaceBase::Local(index), - projection: box [], - }), + Operand::Move(place), _ - ))) = self.body[bb].statements[stmt_idx].kind { - promoted_temps.insert(index); + ))) = &self.body[bb].statements[stmt_idx].kind { + if let Some(index) = place.as_local() { + promoted_temps.insert(index); + } } } Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => { if let StatementKind::Assign( box( _, - Rvalue::Ref(_, _, Place { - base: PlaceBase::Local(index), - projection: box [], - }) + Rvalue::Ref(_, _, place) ) - ) = self.body[bb].statements[stmt_idx].kind { - promoted_temps.insert(index); + ) = &self.body[bb].statements[stmt_idx].kind { + if let Some(index) = place.as_local() { + promoted_temps.insert(index); + } } } Candidate::Argument { .. } => {} @@ -1237,10 +1235,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { match *operand { Operand::Move(ref place) => { // Mark the consumed locals to indicate later drops are noops. - if let Place { - base: PlaceBase::Local(local), - projection: box [], - } = *place { + if let Some(local) = place.as_local() { self.cx.per_local[NeedsDrop].remove(local); } } @@ -1256,8 +1251,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { if let Rvalue::Ref(_, kind, ref place) = *rvalue { // Special-case reborrows. let mut reborrow_place = None; - if let box [proj_base @ .., elem] = &place.projection { - if *elem == ProjectionElem::Deref { + if let &[ref proj_base @ .., elem] = place.projection.as_ref() { + if elem == ProjectionElem::Deref { let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty; if let ty::Ref(..) = base_ty.kind { reborrow_place = Some(proj_base); @@ -1568,10 +1563,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { unleash_miri!(self); // HACK(eddyb): emulate a bit of dataflow analysis, // conservatively, that drop elaboration will do. - let needs_drop = if let Place { - base: PlaceBase::Local(local), - projection: box [], - } = *place { + let needs_drop = if let Some(local) = place.as_local() { if NeedsDrop::in_local(self, local) { Some(self.body.local_decls[local].source_info.span) } else { @@ -1817,16 +1809,17 @@ fn remove_drop_and_storage_dead_on_promoted_locals( } }); let terminator = block.terminator_mut(); - match terminator.kind { + match &terminator.kind { TerminatorKind::Drop { - location: Place { - base: PlaceBase::Local(index), - projection: box [], - }, + location, target, .. - } if promoted_temps.contains(index) => { - terminator.kind = TerminatorKind::Goto { target }; + } => { + if let Some(index) = location.as_local() { + if promoted_temps.contains(index) { + terminator.kind = TerminatorKind::Goto { target: *target }; + } + } } _ => {} } diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 7b6255defd148..c4e44091bc90d 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -259,8 +259,8 @@ fn check_place( def_id: DefId, body: &Body<'tcx> ) -> McfResult { - let mut cursor = &*place.projection; - while let [proj_base @ .., elem] = cursor { + let mut cursor = place.projection.as_ref(); + while let &[ref proj_base @ .., elem] = cursor { cursor = proj_base; match elem { ProjectionElem::Downcast(..) => { diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs index e1994c5f639b0..130393e2c4c86 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs @@ -32,7 +32,7 @@ impl RemoveNoopLandingPads { nop_landing_pads: &BitSet, ) -> bool { for stmt in &body[bb].statements { - match stmt.kind { + match &stmt.kind { StatementKind::FakeRead(..) | StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | @@ -41,12 +41,13 @@ impl RemoveNoopLandingPads { // These are all nops in a landing pad } - StatementKind::Assign(box(Place { - base: PlaceBase::Local(_), - projection: box [], - }, Rvalue::Use(_))) => { - // Writing to a local (e.g., a drop flag) does not - // turn a landing pad to a non-nop + StatementKind::Assign(box(place, Rvalue::Use(_))) => { + if place.as_local().is_some() { + // Writing to a local (e.g., a drop flag) does not + // turn a landing pad to a non-nop + } else { + return false; + } } StatementKind::Assign { .. } | diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index 6edd28a4259a5..aada7641df67a 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -155,8 +155,8 @@ fn value_assigned_to_local<'a, 'tcx>( local: Local, ) -> Option<&'a mir::Rvalue<'tcx>> { if let mir::StatementKind::Assign(box (place, rvalue)) = &stmt.kind { - if let mir::Place { base: mir::PlaceBase::Local(l), projection: box [] } = place { - if local == *l { + if let Some(l) = place.as_local() { + if local == l { return Some(&*rvalue); } } @@ -192,7 +192,7 @@ impl PeekCall { tcx: TyCtxt<'tcx>, terminator: &mir::Terminator<'tcx>, ) -> Option { - use mir::{Operand, Place, PlaceBase}; + use mir::Operand; let span = terminator.source_info.span; if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } = @@ -207,14 +207,23 @@ impl PeekCall { assert_eq!(args.len(), 1); let kind = PeekCallKind::from_arg_ty(substs.type_at(0)); - let arg = match args[0] { - | Operand::Copy(Place { base: PlaceBase::Local(local), projection: box [] }) - | Operand::Move(Place { base: PlaceBase::Local(local), projection: box [] }) - => local, - + let arg = match &args[0] { + Operand::Copy(place) | Operand::Move(place) => { + if let Some(local) = place.as_local() { + local + } else { + tcx.sess.diagnostic().span_err( + span, + "dataflow::sanity_check cannot feed a non-temp to rustc_peek.", + ); + return None; + } + } _ => { tcx.sess.diagnostic().span_err( - span, "dataflow::sanity_check cannot feed a non-temp to rustc_peek."); + span, + "dataflow::sanity_check cannot feed a non-temp to rustc_peek.", + ); return None; } }; @@ -277,12 +286,11 @@ impl<'tcx> RustcPeekAt<'tcx> for IndirectlyMutableLocals<'_, 'tcx> { call: PeekCall, ) { warn!("peek_at: place={:?}", place); - let local = match place { - mir::Place { base: mir::PlaceBase::Local(l), projection: box [] } => *l, - _ => { - tcx.sess.span_err(call.span, "rustc_peek: argument was not a local"); - return; - } + let local = if let Some(l) = place.as_local() { + l + } else { + tcx.sess.span_err(call.span, "rustc_peek: argument was not a local"); + return; }; if !flow_state.contains(local) { diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index e41b4678dbd0d..1b90ea78c6450 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -319,7 +319,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyLocals { let map = make_local_map(&mut body.local_decls, locals); // Update references to all vars and tmps now - LocalUpdater { map }.visit_body(body); + LocalUpdater { map, tcx }.visit_body(body); body.local_decls.shrink_to_fit(); } } @@ -374,11 +374,16 @@ impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> { } } -struct LocalUpdater { +struct LocalUpdater<'tcx> { map: IndexVec>, + tcx: TyCtxt<'tcx>, } -impl<'tcx> MutVisitor<'tcx> for LocalUpdater { +impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { // Remove unnecessary StorageLive and StorageDead annotations. data.statements.retain(|stmt| { diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs index efa39d91205b4..e4c2f7d389b50 100644 --- a/src/librustc_mir/transform/uniform_array_move_out.rs +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -61,7 +61,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> { rvalue: &Rvalue<'tcx>, location: Location) { if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue { - if let box [proj_base @ .., elem] = &src_place.projection { + if let &[ref proj_base @ .., elem] = src_place.projection.as_ref() { if let ProjectionElem::ConstantIndex{offset: _, min_length: _, from_end: false} = elem { @@ -116,16 +116,13 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { min_length: size, from_end: false, }); - self.patch.add_assign(location, - Place::from(temp), - Rvalue::Use( - Operand::Move( - Place { - base: base.clone(), - projection: projection.into_boxed_slice(), - } - ) - ) + self.patch.add_assign( + location, + Place::from(temp), + Rvalue::Use(Operand::Move(Place { + base: base.clone(), + projection: self.tcx.intern_place_elems(&projection), + })), ); temp }).collect(); @@ -153,16 +150,13 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { min_length: size, from_end: false, }); - self.patch.add_assign(location, - dst_place.clone(), - Rvalue::Use( - Operand::Move( - Place { - base: base.clone(), - projection: projection.into_boxed_slice(), - } - ) - ) + self.patch.add_assign( + location, + dst_place.clone(), + Rvalue::Use(Operand::Move(Place { + base: base.clone(), + projection: self.tcx.intern_place_elems(&projection), + })), ); } _ => {} @@ -185,9 +179,11 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { // // replaced by _10 = move _2[:-1]; -pub struct RestoreSubsliceArrayMoveOut; +pub struct RestoreSubsliceArrayMoveOut<'tcx> { + tcx: TyCtxt<'tcx> +} -impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut { +impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut<'tcx> { fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { let mut patch = MirPatch::new(body); let param_env = tcx.param_env(src.def_id()); @@ -203,18 +199,17 @@ impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut { if let StatementKind::Assign(box(ref dst_place, ref rval)) = statement.kind { if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval { let items : Vec<_> = items.iter().map(|item| { - if let Operand::Move(Place { - base: PlaceBase::Local(local), - projection: box [], - }) = item { - let local_use = &visitor.locals_use[*local]; - let opt_index_and_place = - Self::try_get_item_source(local_use, body); - // each local should be used twice: - // in assign and in aggregate statements - if local_use.use_count == 2 && opt_index_and_place.is_some() { - let (index, src_place) = opt_index_and_place.unwrap(); - return Some((local_use, index, src_place)); + if let Operand::Move(place) = item { + if let Some(local) = place.as_local() { + let local_use = &visitor.locals_use[local]; + let opt_index_and_place = + Self::try_get_item_source(local_use, body); + // each local should be used twice: + // in assign and in aggregate statements + if local_use.use_count == 2 && opt_index_and_place.is_some() { + let (index, src_place) = opt_index_and_place.unwrap(); + return Some((local_use, index, src_place)); + } } } None @@ -230,7 +225,9 @@ impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut { None } }); - Self::check_and_patch(*candidate, &items, opt_size, &mut patch, dst_place); + let restore_subslice = RestoreSubsliceArrayMoveOut { tcx }; + restore_subslice + .check_and_patch(*candidate, &items, opt_size, &mut patch, dst_place); } } } @@ -239,15 +236,20 @@ impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut { } } -impl RestoreSubsliceArrayMoveOut { +impl RestoreSubsliceArrayMoveOut<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>) -> Self { + RestoreSubsliceArrayMoveOut { tcx } + } + // Checks that source has size, all locals are inited from same source place and // indices is an integer interval. If all checks pass do the replacent. // items are Vec> - fn check_and_patch<'tcx>(candidate: Location, - items: &[Option<(&LocalUse, u32, PlaceRef<'_, 'tcx>)>], - opt_size: Option, - patch: &mut MirPatch<'tcx>, - dst_place: &Place<'tcx>) { + fn check_and_patch(&self, + candidate: Location, + items: &[Option<(&LocalUse, u32, PlaceRef<'_, 'tcx>)>], + opt_size: Option, + patch: &mut MirPatch<'tcx>, + dst_place: &Place<'tcx>) { let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2); if opt_size.is_some() && items.iter().all( @@ -280,46 +282,40 @@ impl RestoreSubsliceArrayMoveOut { dst_place.clone(), Rvalue::Use(Operand::Move(Place { base: src_place.base.clone(), - projection: projection.into_boxed_slice(), + projection: self.tcx.intern_place_elems(&projection), })), ); } } - fn try_get_item_source<'a, 'tcx>(local_use: &LocalUse, - body: &'a Body<'tcx>) -> Option<(u32, PlaceRef<'a, 'tcx>)> { + fn try_get_item_source<'a>(local_use: &LocalUse, + body: &'a Body<'tcx>) -> Option<(u32, PlaceRef<'a, 'tcx>)> { if let Some(location) = local_use.first_use { let block = &body[location.block]; if block.statements.len() > location.statement_index { let statement = &block.statements[location.statement_index]; if let StatementKind::Assign( - box( - Place { - base: PlaceBase::Local(_), - projection: box [], - }, - Rvalue::Use(Operand::Move(Place { - base: _, - projection: box [.., ProjectionElem::ConstantIndex { - offset, min_length: _, from_end: false - }], - })), - ) + box(place, Rvalue::Use(Operand::Move(src_place))) ) = &statement.kind { - // FIXME remove once we can use slices patterns - if let StatementKind::Assign( - box( - _, - Rvalue::Use(Operand::Move(Place { + if let (Some(_), PlaceRef { + base: _, + projection: &[.., ProjectionElem::ConstantIndex { + offset, min_length: _, from_end: false + }], + }) = (place.as_local(), src_place.as_ref()) { + if let StatementKind::Assign( + box(_, Rvalue::Use(Operand::Move(place))) + ) = &statement.kind { + if let PlaceRef { base, - projection: box [proj_base @ .., _], - })), - ) - ) = &statement.kind { - return Some((*offset, PlaceRef { - base, - projection: proj_base, - })) + projection: &[ref proj_base @ .., _], + } = place.as_ref() { + return Some((offset, PlaceRef { + base, + projection: proj_base, + })) + } + } } } } diff --git a/src/librustc_mir/util/aggregate.rs b/src/librustc_mir/util/aggregate.rs index c0f9218574556..e6c3e4384d7ae 100644 --- a/src/librustc_mir/util/aggregate.rs +++ b/src/librustc_mir/util/aggregate.rs @@ -1,5 +1,5 @@ use rustc::mir::*; -use rustc::ty::Ty; +use rustc::ty::{Ty, TyCtxt}; use rustc::ty::layout::VariantIdx; use rustc_index::vec::Idx; @@ -17,6 +17,7 @@ pub fn expand_aggregate<'tcx>( operands: impl Iterator, Ty<'tcx>)> + TrustedLen, kind: AggregateKind<'tcx>, source_info: SourceInfo, + tcx: TyCtxt<'tcx>, ) -> impl Iterator> + TrustedLen { let mut set_discriminant = None; let active_field_index = match kind { @@ -29,7 +30,7 @@ pub fn expand_aggregate<'tcx>( }, source_info, }); - lhs = lhs.downcast(adt_def, variant_index); + lhs = tcx.mk_place_downcast(lhs, adt_def, variant_index); } active_field_index } @@ -58,7 +59,7 @@ pub fn expand_aggregate<'tcx>( // FIXME(eddyb) `offset` should be u64. let offset = i as u32; assert_eq!(offset as usize, i); - lhs.clone().elem(ProjectionElem::ConstantIndex { + tcx.mk_place_elem(lhs.clone(), ProjectionElem::ConstantIndex { offset, // FIXME(eddyb) `min_length` doesn't appear to be used. min_length: offset + 1, @@ -66,7 +67,7 @@ pub fn expand_aggregate<'tcx>( }) } else { let field = Field::new(active_field_index.unwrap_or(i)); - lhs.clone().field(field, ty) + tcx.mk_place_field(lhs.clone(), field, ty) }; Statement { source_info, diff --git a/src/librustc_mir/util/alignment.rs b/src/librustc_mir/util/alignment.rs index 1bad85ec42d08..f949fcf0745f0 100644 --- a/src/librustc_mir/util/alignment.rs +++ b/src/librustc_mir/util/alignment.rs @@ -38,8 +38,8 @@ fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: &Place<' where L: HasLocalDecls<'tcx>, { - let mut cursor = &*place.projection; - while let [proj_base @ .., elem] = cursor { + let mut cursor = place.projection.as_ref(); + while let &[ref proj_base @ .., elem] = cursor { cursor = proj_base; match elem { diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs index cdd07ad4b8ff4..725ec84ca6237 100644 --- a/src/librustc_mir/util/def_use.rs +++ b/src/librustc_mir/util/def_use.rs @@ -2,6 +2,7 @@ use rustc::mir::{Body, Local, Location, PlaceElem}; use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor}; +use rustc::ty::TyCtxt; use rustc_index::vec::IndexVec; use std::mem; @@ -47,20 +48,26 @@ impl DefUseAnalysis { &self.info[local] } - fn mutate_defs_and_uses(&self, local: Local, body: &mut Body<'_>, new_local: Local) { + fn mutate_defs_and_uses( + &self, + local: Local, + body: &mut Body<'tcx>, + new_local: Local, + tcx: TyCtxt<'tcx>, + ) { for place_use in &self.info[local].defs_and_uses { - MutateUseVisitor::new(local, - new_local, - body).visit_location(body, place_use.location) + MutateUseVisitor::new(local, new_local, body, tcx) + .visit_location(body, place_use.location) } } // FIXME(pcwalton): this should update the def-use chains. pub fn replace_all_defs_and_uses_with(&self, local: Local, - body: &mut Body<'_>, - new_local: Local) { - self.mutate_defs_and_uses(local, body, new_local) + body: &mut Body<'tcx>, + new_local: Local, + tcx: TyCtxt<'tcx>) { + self.mutate_defs_and_uses(local, body, new_local, tcx) } } @@ -114,21 +121,28 @@ impl Info { } } -struct MutateUseVisitor { +struct MutateUseVisitor<'tcx> { query: Local, new_local: Local, + tcx: TyCtxt<'tcx>, } -impl MutateUseVisitor { - fn new(query: Local, new_local: Local, _: &Body<'_>) -> MutateUseVisitor { - MutateUseVisitor { - query, - new_local, - } +impl MutateUseVisitor<'tcx> { + fn new( + query: Local, + new_local: Local, + _: &Body<'tcx>, + tcx: TyCtxt<'tcx>, + ) -> MutateUseVisitor<'tcx> { + MutateUseVisitor { query, new_local, tcx } } } -impl MutVisitor<'_> for MutateUseVisitor { +impl MutVisitor<'tcx> for MutateUseVisitor<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn visit_local(&mut self, local: &mut Local, _context: PlaceContext, diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index f7ba6f1ec6993..a1846a1fb5eaf 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -200,13 +200,14 @@ where variant.fields.iter().enumerate().map(|(i, f)| { let field = Field::new(i); let subpath = self.elaborator.field_subpath(variant_path, field); + let tcx = self.tcx(); assert_eq!(self.elaborator.param_env().reveal, Reveal::All); - let field_ty = self.tcx().normalize_erasing_regions( + let field_ty = tcx.normalize_erasing_regions( self.elaborator.param_env(), - f.ty(self.tcx(), substs), + f.ty(tcx, substs), ); - (base_place.clone().field(field, field_ty), subpath) + (tcx.mk_place_field(base_place.clone(), field, field_ty), subpath) }).collect() } @@ -323,7 +324,7 @@ where debug!("open_drop_for_tuple({:?}, {:?})", self, tys); let fields = tys.iter().enumerate().map(|(i, &ty)| { - (self.place.clone().field(Field::new(i), ty), + (self.tcx().mk_place_field(self.place.clone(), Field::new(i), ty), self.elaborator.field_subpath(self.path, Field::new(i))) }).collect(); @@ -334,7 +335,7 @@ where fn open_drop_for_box(&mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>) -> BasicBlock { debug!("open_drop_for_box({:?}, {:?}, {:?})", self, adt, substs); - let interior = self.place.clone().deref(); + let interior = self.tcx().mk_place_deref(self.place.clone()); let interior_path = self.elaborator.deref_subpath(self.path); let succ = self.succ; // FIXME(#43234) @@ -406,14 +407,19 @@ where }; let mut have_otherwise = false; + let tcx = self.tcx(); - for (variant_index, discr) in adt.discriminants(self.tcx()) { + for (variant_index, discr) in adt.discriminants(tcx) { let subpath = self.elaborator.downcast_subpath( self.path, variant_index); if let Some(variant_path) = subpath { - let base_place = self.place.clone().elem( - ProjectionElem::Downcast(Some(adt.variants[variant_index].ident.name), - variant_index)); + let base_place = tcx.mk_place_elem( + self.place.clone(), + ProjectionElem::Downcast( + Some(adt.variants[variant_index].ident.name), + variant_index, + ), + ); let fields = self.move_paths_for_fields( &base_place, variant_path, @@ -586,7 +592,7 @@ where BorrowKind::Mut { allow_two_phase_borrow: false }, Place { base: PlaceBase::Local(cur), - projection: Box::new([ProjectionElem::Deref]), + projection: tcx.intern_place_elems(&vec![ProjectionElem::Deref]), } ), Rvalue::BinaryOp(BinOp::Offset, move_(&Place::from(cur)), one)) @@ -594,7 +600,7 @@ where (Rvalue::Ref( tcx.lifetimes.re_erased, BorrowKind::Mut { allow_two_phase_borrow: false }, - self.place.clone().index(cur)), + tcx.mk_place_index(self.place.clone(), cur)), Rvalue::BinaryOp(BinOp::Add, move_(&Place::from(cur)), one)) }; @@ -627,7 +633,7 @@ where let loop_block = self.elaborator.patch().new_block(loop_block); self.elaborator.patch().patch_terminator(drop_block, TerminatorKind::Drop { - location: ptr.clone().deref(), + location: tcx.mk_place_deref(ptr.clone()), target: loop_block, unwind: unwind.into_option() }); @@ -644,18 +650,27 @@ where // ptr_based_loop // } + let tcx = self.tcx(); + if let Some(size) = opt_size { let size: u32 = size.try_into().unwrap_or_else(|_| { bug!("move out check isn't implemented for array sizes bigger than u32::MAX"); }); - let fields: Vec<(Place<'tcx>, Option)> = (0..size).map(|i| { - (self.place.clone().elem(ProjectionElem::ConstantIndex{ - offset: i, - min_length: size, - from_end: false - }), - self.elaborator.array_subpath(self.path, i, size)) - }).collect(); + let fields: Vec<(Place<'tcx>, Option)> = (0..size) + .map(|i| { + ( + tcx.mk_place_elem( + self.place.clone(), + ProjectionElem::ConstantIndex { + offset: i, + min_length: size, + from_end: false, + }, + ), + self.elaborator.array_subpath(self.path, i, size), + ) + }) + .collect(); if fields.iter().any(|(_,path)| path.is_some()) { let (succ, unwind) = self.drop_ladder_bottom(); @@ -664,7 +679,6 @@ where } let move_ = |place: &Place<'tcx>| Operand::Move(place.clone()); - let tcx = self.tcx(); let elem_size = &Place::from(self.new_temp(tcx.types.usize)); let len = &Place::from(self.new_temp(tcx.types.usize)); @@ -900,8 +914,8 @@ where ); let args = adt.variants[VariantIdx::new(0)].fields.iter().enumerate().map(|(i, f)| { let field = Field::new(i); - let field_ty = f.ty(self.tcx(), substs); - Operand::Move(self.place.clone().field(field, field_ty)) + let field_ty = f.ty(tcx, substs); + Operand::Move(tcx.mk_place_field(self.place.clone(), field, field_ty)) }).collect(); let call = TerminatorKind::Call { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index abc8b83144941..a642491b28181 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -26,9 +26,10 @@ use rustc::ty::{self, DefIdTree, TyCtxt, Region, RegionVid, Ty, AdtKind}; use rustc::ty::fold::TypeFolder; use rustc::ty::layout::VariantIdx; use rustc::util::nodemap::{FxHashMap, FxHashSet}; -use syntax::ast::{self, AttrStyle, Ident}; +use syntax::ast::{self, Attribute, AttrStyle, AttrItem, Ident}; use syntax::attr; use syntax_expand::base::MacroKind; +use syntax::parse::lexer::comments; use syntax::source_map::DUMMY_SP; use syntax::symbol::{Symbol, kw, sym}; use syntax_pos::{self, Pos, FileName}; @@ -858,8 +859,31 @@ impl Attributes { let mut cfg = Cfg::True; let mut doc_line = 0; + /// Converts `attr` to a normal `#[doc="foo"]` comment, if it is a + /// comment like `///` or `/** */`. (Returns `attr` unchanged for + /// non-sugared doc attributes.) + pub fn with_desugared_doc(attr: &Attribute, f: impl FnOnce(&Attribute) -> T) -> T { + if attr.is_sugared_doc { + let comment = attr.value_str().unwrap(); + let meta = attr::mk_name_value_item_str( + Ident::with_dummy_span(sym::doc), + Symbol::intern(&comments::strip_doc_comment_decoration(&comment.as_str())), + DUMMY_SP, + ); + f(&Attribute { + item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) }, + id: attr.id, + style: attr.style, + is_sugared_doc: true, + span: attr.span, + }) + } else { + f(attr) + } + } + let other_attrs = attrs.iter().filter_map(|attr| { - attr.with_desugared_doc(|attr| { + with_desugared_doc(attr, |attr| { if attr.check_name(sym::doc) { if let Some(mi) = attr.meta() { if let Some(value) = mi.value_str() { diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index f0104c9156ded..a0e07d58c9da9 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -79,7 +79,7 @@ function getSearchElement() { "derive", "traitalias"]; - var disableShortcuts = getCurrentValue("rustdoc-disable-shortcuts") !== "true"; + var disableShortcuts = getCurrentValue("rustdoc-disable-shortcuts") === "true"; var search_input = getSearchInput(); // On the search screen, so you remain on the last tab you opened. diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 2894cd1c1f685..c7adad896a51a 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -283,7 +283,7 @@ #![feature(needs_panic_runtime)] #![feature(never_type)] #![feature(nll)] -#![feature(non_exhaustive)] +#![cfg_attr(bootstrap, feature(non_exhaustive))] #![feature(on_unimplemented)] #![feature(optin_builtin_traits)] #![feature(panic_info_message)] diff --git a/src/libstd/path.rs b/src/libstd/path.rs index ca81044ee8560..6d6bc760649e0 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1363,20 +1363,24 @@ impl PathBuf { } fn _set_extension(&mut self, extension: &OsStr) -> bool { - if self.file_name().is_none() { - return false; - } - - let mut stem = match self.file_stem() { - Some(stem) => stem.to_os_string(), - None => OsString::new(), + let file_stem = match self.file_stem() { + None => return false, + Some(f) => os_str_as_u8_slice(f), }; - if !os_str_as_u8_slice(extension).is_empty() { - stem.push("."); - stem.push(extension); + // truncate until right after the file stem + let end_file_stem = file_stem[file_stem.len()..].as_ptr() as usize; + let start = os_str_as_u8_slice(&self.inner).as_ptr() as usize; + let v = self.as_mut_vec(); + v.truncate(end_file_stem.wrapping_sub(start)); + + // add the new extension, if any + let new = os_str_as_u8_slice(extension); + if !new.is_empty() { + v.reserve_exact(new.len() + 1); + v.push(b'.'); + v.extend_from_slice(new); } - self.set_file_name(&stem); true } diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 39cc120594aab..5e1f10c03ceda 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -105,11 +105,14 @@ cfg_has_statx! {{ flags: i32, mask: u32, ) -> Option> { - use crate::sync::atomic::{AtomicBool, Ordering}; + use crate::sync::atomic::{AtomicU8, Ordering}; // Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx` - // We store the availability in a global to avoid unnecessary syscalls - static HAS_STATX: AtomicBool = AtomicBool::new(true); + // We store the availability in global to avoid unnecessary syscalls. + // 0: Unknown + // 1: Not available + // 2: Available + static STATX_STATE: AtomicU8 = AtomicU8::new(0); syscall! { fn statx( fd: c_int, @@ -120,50 +123,60 @@ cfg_has_statx! {{ ) -> c_int } - if !HAS_STATX.load(Ordering::Relaxed) { - return None; - } - - let mut buf: libc::statx = mem::zeroed(); - let ret = cvt(statx(fd, path, flags, mask, &mut buf)); - match ret { - Err(err) => match err.raw_os_error() { - Some(libc::ENOSYS) => { - HAS_STATX.store(false, Ordering::Relaxed); + match STATX_STATE.load(Ordering::Relaxed) { + 0 => { + // It is a trick to call `statx` with NULL pointers to check if the syscall + // is available. According to the manual, it is expected to fail with EFAULT. + // We do this mainly for performance, since it is nearly hundreds times + // faster than a normal successfull call. + let err = cvt(statx(0, ptr::null(), 0, libc::STATX_ALL, ptr::null_mut())) + .err() + .and_then(|e| e.raw_os_error()); + // We don't check `err == Some(libc::ENOSYS)` because the syscall may be limited + // and returns `EPERM`. Listing all possible errors seems not a good idea. + // See: https://github.com/rust-lang/rust/issues/65662 + if err != Some(libc::EFAULT) { + STATX_STATE.store(1, Ordering::Relaxed); return None; } - _ => return Some(Err(err)), + STATX_STATE.store(2, Ordering::Relaxed); } - Ok(_) => { - // We cannot fill `stat64` exhaustively because of private padding fields. - let mut stat: stat64 = mem::zeroed(); - // `c_ulong` on gnu-mips, `dev_t` otherwise - stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor) as _; - stat.st_ino = buf.stx_ino as libc::ino64_t; - stat.st_nlink = buf.stx_nlink as libc::nlink_t; - stat.st_mode = buf.stx_mode as libc::mode_t; - stat.st_uid = buf.stx_uid as libc::uid_t; - stat.st_gid = buf.stx_gid as libc::gid_t; - stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor) as _; - stat.st_size = buf.stx_size as off64_t; - stat.st_blksize = buf.stx_blksize as libc::blksize_t; - stat.st_blocks = buf.stx_blocks as libc::blkcnt64_t; - stat.st_atime = buf.stx_atime.tv_sec as libc::time_t; - // `i64` on gnu-x86_64-x32, `c_ulong` otherwise. - stat.st_atime_nsec = buf.stx_atime.tv_nsec as _; - stat.st_mtime = buf.stx_mtime.tv_sec as libc::time_t; - stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as _; - stat.st_ctime = buf.stx_ctime.tv_sec as libc::time_t; - stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as _; - - let extra = StatxExtraFields { - stx_mask: buf.stx_mask, - stx_btime: buf.stx_btime, - }; + 1 => return None, + _ => {} + } - Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) })) - } + let mut buf: libc::statx = mem::zeroed(); + if let Err(err) = cvt(statx(fd, path, flags, mask, &mut buf)) { + return Some(Err(err)); } + + // We cannot fill `stat64` exhaustively because of private padding fields. + let mut stat: stat64 = mem::zeroed(); + // `c_ulong` on gnu-mips, `dev_t` otherwise + stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor) as _; + stat.st_ino = buf.stx_ino as libc::ino64_t; + stat.st_nlink = buf.stx_nlink as libc::nlink_t; + stat.st_mode = buf.stx_mode as libc::mode_t; + stat.st_uid = buf.stx_uid as libc::uid_t; + stat.st_gid = buf.stx_gid as libc::gid_t; + stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor) as _; + stat.st_size = buf.stx_size as off64_t; + stat.st_blksize = buf.stx_blksize as libc::blksize_t; + stat.st_blocks = buf.stx_blocks as libc::blkcnt64_t; + stat.st_atime = buf.stx_atime.tv_sec as libc::time_t; + // `i64` on gnu-x86_64-x32, `c_ulong` otherwise. + stat.st_atime_nsec = buf.stx_atime.tv_nsec as _; + stat.st_mtime = buf.stx_mtime.tv_sec as libc::time_t; + stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as _; + stat.st_ctime = buf.stx_ctime.tv_sec as libc::time_t; + stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as _; + + let extra = StatxExtraFields { + stx_mask: buf.stx_mask, + stx_btime: buf.stx_btime, + }; + + Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) })) } } else { diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 4aec50408812f..27de084ae98ca 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -13,8 +13,8 @@ use crate::ast::{AttrItem, AttrId, AttrStyle, Name, Ident, Path, PathSegment}; use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem}; use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam}; use crate::mut_visit::visit_clobber; -use crate::source_map::{BytePos, Spanned, DUMMY_SP}; -use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; +use crate::source_map::{BytePos, Spanned}; +use crate::parse::lexer::comments::doc_comment_style; use crate::parse::parser::Parser; use crate::parse::PResult; use crate::parse::token::{self, Token}; @@ -312,31 +312,6 @@ impl Attribute { span: self.span, }) } - - /// Converts `self` to a normal `#[doc="foo"]` comment, if it is a - /// comment like `///` or `/** */`. (Returns `self` unchanged for - /// non-sugared doc attributes.) - pub fn with_desugared_doc(&self, f: F) -> T where - F: FnOnce(&Attribute) -> T, - { - if self.is_sugared_doc { - let comment = self.value_str().unwrap(); - let meta = mk_name_value_item_str( - Ident::with_dummy_span(sym::doc), - Symbol::intern(&strip_doc_comment_decoration(&comment.as_str())), - DUMMY_SP, - ); - f(&Attribute { - item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) }, - id: self.id, - style: self.style, - is_sugared_doc: true, - span: self.span, - }) - } else { - f(self) - } - } } /* Constructors */ diff --git a/src/libsyntax/feature_gate/accepted.rs b/src/libsyntax/feature_gate/accepted.rs index cda1ef1436ca1..36fcab8450b85 100644 --- a/src/libsyntax/feature_gate/accepted.rs +++ b/src/libsyntax/feature_gate/accepted.rs @@ -245,8 +245,10 @@ declare_features! ( (accepted, bind_by_move_pattern_guards, "1.39.0", Some(15287), None), /// Allows attributes in formal function parameters. (accepted, param_attrs, "1.39.0", Some(60406), None), - // Allows macro invocations in `extern {}` blocks. + /// Allows macro invocations in `extern {}` blocks. (accepted, macros_in_extern, "1.40.0", Some(49476), None), + /// Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008). + (accepted, non_exhaustive, "1.40.0", Some(44109), None), // ------------------------------------------------------------------------- // feature-group-end: accepted features diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs index 4f92401d2bc57..f6e1d6c422499 100644 --- a/src/libsyntax/feature_gate/active.rs +++ b/src/libsyntax/feature_gate/active.rs @@ -383,9 +383,6 @@ declare_features! ( /// Allows `#[doc(include = "some-file")]`. (active, external_doc, "1.22.0", Some(44732), None), - /// Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008). - (active, non_exhaustive, "1.22.0", Some(44109), None), - /// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`. (active, crate_visibility_modifier, "1.23.0", Some(53120), None), diff --git a/src/libsyntax/feature_gate/builtin_attrs.rs b/src/libsyntax/feature_gate/builtin_attrs.rs index 7dd6ae90d9a46..efe84238795a5 100644 --- a/src/libsyntax/feature_gate/builtin_attrs.rs +++ b/src/libsyntax/feature_gate/builtin_attrs.rs @@ -252,6 +252,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ungated!(path, Normal, template!(NameValueStr: "file")), ungated!(no_std, CrateLevel, template!(Word)), ungated!(no_implicit_prelude, Normal, template!(Word)), + ungated!(non_exhaustive, Whitelisted, template!(Word)), // Runtime ungated!(windows_subsystem, Whitelisted, template!(NameValueStr: "windows|console")), @@ -314,9 +315,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ test_runner, CrateLevel, template!(List: "path"), custom_test_frameworks, "custom test frameworks are an unstable feature", ), - - // RFC #2008 - gated!(non_exhaustive, Whitelisted, template!(Word), experimental!(non_exhaustive)), // RFC #1268 gated!(marker, Normal, template!(Word), marker_trait_attr, experimental!(marker)), gated!( diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index e3296788d9fa7..0b157938375e1 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -25,6 +25,9 @@ use std::sync::{Arc, Mutex}; use rustc_serialize::json::{as_json, as_pretty_json}; +#[cfg(test)] +mod tests; + pub struct JsonEmitter { dst: Box, registry: Option, @@ -336,8 +339,8 @@ impl DiagnosticSpan { DiagnosticSpan { file_name: start.file.name.to_string(), - byte_start: span.lo().0 - start.file.start_pos.0, - byte_end: span.hi().0 - start.file.start_pos.0, + byte_start: start.file.original_relative_byte_pos(span.lo()).0, + byte_end: start.file.original_relative_byte_pos(span.hi()).0, line_start: start.line, line_end: end.line, column_start: start.col.0 + 1, diff --git a/src/libsyntax/json/tests.rs b/src/libsyntax/json/tests.rs new file mode 100644 index 0000000000000..eb0d9ef3947c8 --- /dev/null +++ b/src/libsyntax/json/tests.rs @@ -0,0 +1,186 @@ +use super::*; + +use crate::json::JsonEmitter; +use crate::source_map::{FilePathMapping, SourceMap}; +use crate::tests::Shared; +use crate::with_default_globals; + +use errors::emitter::{ColorConfig, HumanReadableErrorType}; +use errors::Handler; +use rustc_serialize::json::decode; +use syntax_pos::{BytePos, Span}; + +use std::str; + +#[derive(RustcDecodable, Debug, PartialEq, Eq)] +struct TestData { + spans: Vec, +} + +#[derive(RustcDecodable, Debug, PartialEq, Eq)] +struct SpanTestData { + pub byte_start: u32, + pub byte_end: u32, + pub line_start: u32, + pub column_start: u32, + pub line_end: u32, + pub column_end: u32, +} + +/// Test the span yields correct positions in JSON. +fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) { + let expected_output = TestData { spans: vec![expected_output] }; + + with_default_globals(|| { + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + sm.new_source_file(Path::new("test.rs").to_owned().into(), code.to_owned()); + + let output = Arc::new(Mutex::new(Vec::new())); + let je = JsonEmitter::new( + Box::new(Shared { data: output.clone() }), + None, + sm, + true, + HumanReadableErrorType::Short(ColorConfig::Never), + false, + ); + + let span = Span::with_root_ctxt(BytePos(span.0), BytePos(span.1)); + let handler = Handler::with_emitter(true, None, Box::new(je)); + handler.span_err(span, "foo"); + + let bytes = output.lock().unwrap(); + let actual_output = str::from_utf8(&bytes).unwrap(); + let actual_output: TestData = decode(actual_output).unwrap(); + + assert_eq!(expected_output, actual_output) + }) +} + +#[test] +fn empty() { + test_positions( + " ", + (0, 1), + SpanTestData { + byte_start: 0, + byte_end: 1, + line_start: 1, + column_start: 1, + line_end: 1, + column_end: 2, + }, + ) +} + +#[test] +fn bom() { + test_positions( + "\u{feff} ", + (0, 1), + SpanTestData { + byte_start: 3, + byte_end: 4, + line_start: 1, + column_start: 1, + line_end: 1, + column_end: 2, + }, + ) +} + +#[test] +fn lf_newlines() { + test_positions( + "\nmod foo;\nmod bar;\n", + (5, 12), + SpanTestData { + byte_start: 5, + byte_end: 12, + line_start: 2, + column_start: 5, + line_end: 3, + column_end: 3, + }, + ) +} + +#[test] +fn crlf_newlines() { + test_positions( + "\r\nmod foo;\r\nmod bar;\r\n", + (5, 12), + SpanTestData { + byte_start: 6, + byte_end: 14, + line_start: 2, + column_start: 5, + line_end: 3, + column_end: 3, + }, + ) +} + +#[test] +fn crlf_newlines_with_bom() { + test_positions( + "\u{feff}\r\nmod foo;\r\nmod bar;\r\n", + (5, 12), + SpanTestData { + byte_start: 9, + byte_end: 17, + line_start: 2, + column_start: 5, + line_end: 3, + column_end: 3, + }, + ) +} + +#[test] +fn span_before_crlf() { + test_positions( + "foo\r\nbar", + (2, 3), + SpanTestData { + byte_start: 2, + byte_end: 3, + line_start: 1, + column_start: 3, + line_end: 1, + column_end: 4, + }, + ) +} + +#[test] +fn span_on_crlf() { + test_positions( + "foo\r\nbar", + (3, 4), + SpanTestData { + byte_start: 3, + byte_end: 5, + line_start: 1, + column_start: 4, + line_end: 2, + column_end: 1, + }, + ) +} + +#[test] +fn span_after_crlf() { + test_positions( + "foo\r\nbar", + (4, 5), + SpanTestData { + byte_start: 5, + byte_end: 6, + line_start: 2, + column_start: 1, + line_end: 2, + column_end: 2, + }, + ) +} diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 3fa13f08d3ab6..3a2af96f7db64 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -31,23 +31,6 @@ mod tests; pub const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments"); -// A variant of 'panictry!' that works on a Vec instead of a single DiagnosticBuilder. -macro_rules! panictry_buffer { - ($handler:expr, $e:expr) => ({ - use std::result::Result::{Ok, Err}; - use errors::FatalError; - match $e { - Ok(e) => e, - Err(errs) => { - for e in errs { - $handler.emit_diagnostic(&e); - } - FatalError.raise() - } - } - }) -} - #[macro_export] macro_rules! unwrap_or { ($opt:expr, $default:expr) => { diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs index 5121a9ef7b5fc..ac79ce323bf97 100644 --- a/src/libsyntax/parse/lexer/comments.rs +++ b/src/libsyntax/parse/lexer/comments.rs @@ -176,7 +176,7 @@ fn split_block_comment_into_lines( // it appears this function is called only from pprust... that's // probably not a good thing. -pub fn gather_comments(sess: &ParseSess, path: FileName, src: String) -> Vec { +crate fn gather_comments(sess: &ParseSess, path: FileName, src: String) -> Vec { let cm = SourceMap::new(sess.source_map().path_mapping().clone()); let source_file = cm.new_source_file(path, src); let text = (*source_file.src.as_ref().unwrap()).clone(); diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index b4dd23c9f9b0f..853723de14f44 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -1,8 +1,9 @@ use rustc_data_structures::fx::FxHashMap; use syntax_pos::Span; +use super::{StringReader, UnmatchedBrace}; + use crate::print::pprust::token_to_string; -use crate::parse::lexer::{StringReader, UnmatchedBrace}; use crate::parse::token::{self, Token}; use crate::parse::PResult; use crate::tokenstream::{DelimSpan, IsJoint::{self, *}, TokenStream, TokenTree, TreeAndJoint}; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index e6b794a6a990e..e6ddf8778ccf0 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -59,6 +59,23 @@ pub enum DirectoryOwnership { // uses a HOF to parse anything, and includes file and // `source_str`. +/// A variant of 'panictry!' that works on a Vec instead of a single DiagnosticBuilder. +macro_rules! panictry_buffer { + ($handler:expr, $e:expr) => ({ + use std::result::Result::{Ok, Err}; + use errors::FatalError; + match $e { + Ok(e) => e, + Err(errs) => { + for e in errs { + $handler.emit_diagnostic(&e); + } + FatalError.raise() + } + } + }) +} + pub fn parse_crate_from_file<'a>(input: &Path, sess: &'a ParseSess) -> PResult<'a, ast::Crate> { let mut parser = new_parser_from_file(sess, input); parser.parse_crate_mod() diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f25224d1e36f5..6ead1ce811d49 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1368,25 +1368,6 @@ impl<'a> Parser<'a> { } } } - - fn report_invalid_macro_expansion_item(&self) { - self.struct_span_err( - self.prev_span, - "macros that expand to items must be delimited with braces or followed by a semicolon", - ).multipart_suggestion( - "change the delimiters to curly braces", - vec![ - (self.prev_span.with_hi(self.prev_span.lo() + BytePos(1)), String::from(" {")), - (self.prev_span.with_lo(self.prev_span.hi() - BytePos(1)), '}'.to_string()), - ], - Applicability::MaybeIncorrect, - ).span_suggestion( - self.sess.source_map().next_point(self.prev_span), - "add a semicolon", - ';'.to_string(), - Applicability::MaybeIncorrect, - ).emit(); - } } pub fn emit_unclosed_delims(unclosed_delims: &mut Vec, handler: &errors::Handler) { diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 95bddb5afdd08..506a1a2a27a34 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -19,6 +19,7 @@ use log::debug; use std::mem; use rustc_target::spec::abi::Abi; use errors::{Applicability, DiagnosticBuilder, DiagnosticId, StashKey}; +use syntax_pos::BytePos; /// Whether the type alias or associated type is a concrete type or an opaque type. #[derive(Debug)] @@ -1739,6 +1740,25 @@ impl<'a> Parser<'a> { } } + fn report_invalid_macro_expansion_item(&self) { + self.struct_span_err( + self.prev_span, + "macros that expand to items must be delimited with braces or followed by a semicolon", + ).multipart_suggestion( + "change the delimiters to curly braces", + vec![ + (self.prev_span.with_hi(self.prev_span.lo() + BytePos(1)), String::from(" {")), + (self.prev_span.with_lo(self.prev_span.hi() - BytePos(1)), '}'.to_string()), + ], + Applicability::MaybeIncorrect, + ).span_suggestion( + self.sess.source_map().next_point(self.prev_span), + "add a semicolon", + ';'.to_string(), + Applicability::MaybeIncorrect, + ).emit(); + } + fn mk_item(&self, span: Span, ident: Ident, kind: ItemKind, vis: Visibility, attrs: Vec) -> P { P(Item { diff --git a/src/libsyntax/source_map.rs b/src/libsyntax/source_map.rs index a1d147637e27e..d7760e0cf9ee4 100644 --- a/src/libsyntax/source_map.rs +++ b/src/libsyntax/source_map.rs @@ -283,6 +283,7 @@ impl SourceMap { mut file_local_lines: Vec, mut file_local_multibyte_chars: Vec, mut file_local_non_narrow_chars: Vec, + mut file_local_normalized_pos: Vec, ) -> Lrc { let start_pos = self.next_start_pos(); @@ -301,6 +302,10 @@ impl SourceMap { *swc = *swc + start_pos; } + for nc in &mut file_local_normalized_pos { + nc.pos = nc.pos + start_pos; + } + let source_file = Lrc::new(SourceFile { name: filename, name_was_remapped, @@ -314,6 +319,7 @@ impl SourceMap { lines: file_local_lines, multibyte_chars: file_local_multibyte_chars, non_narrow_chars: file_local_non_narrow_chars, + normalized_pos: file_local_normalized_pos, name_hash, }); diff --git a/src/libsyntax/tests.rs b/src/libsyntax/tests.rs index 881bdaa84d099..e73c8b43bccbf 100644 --- a/src/libsyntax/tests.rs +++ b/src/libsyntax/tests.rs @@ -111,8 +111,8 @@ struct SpanLabel { label: &'static str, } -struct Shared { - data: Arc>, +crate struct Shared { + pub data: Arc>, } impl Write for Shared { diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 7e42b931961f8..9034f8c1afd1b 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -9,7 +9,7 @@ #![feature(const_fn)] #![feature(crate_visibility_modifier)] #![feature(nll)] -#![feature(non_exhaustive)] +#![cfg_attr(bootstrap, feature(non_exhaustive))] #![feature(optin_builtin_traits)] #![feature(rustc_attrs)] #![cfg_attr(bootstrap, feature(proc_macro_hygiene))] @@ -855,6 +855,15 @@ impl Sub for NonNarrowChar { } } +/// Identifies an offset of a character that was normalized away from `SourceFile`. +#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq, Debug)] +pub struct NormalizedPos { + /// The absolute offset of the character in the `SourceMap`. + pub pos: BytePos, + /// The difference between original and normalized string at position. + pub diff: u32, +} + /// The state of the lazy external source loading mechanism of a `SourceFile`. #[derive(PartialEq, Eq, Clone)] pub enum ExternalSource { @@ -918,6 +927,8 @@ pub struct SourceFile { pub multibyte_chars: Vec, /// Width of characters that are not narrow in the source code. pub non_narrow_chars: Vec, + /// Locations of characters removed during normalization. + pub normalized_pos: Vec, /// A hash of the filename, used for speeding up hashing in incremental compilation. pub name_hash: u128, } @@ -984,6 +995,9 @@ impl Encodable for SourceFile { })?; s.emit_struct_field("name_hash", 8, |s| { self.name_hash.encode(s) + })?; + s.emit_struct_field("normalized_pos", 9, |s| { + self.normalized_pos.encode(s) }) }) } @@ -1034,6 +1048,8 @@ impl Decodable for SourceFile { d.read_struct_field("non_narrow_chars", 7, |d| Decodable::decode(d))?; let name_hash: u128 = d.read_struct_field("name_hash", 8, |d| Decodable::decode(d))?; + let normalized_pos: Vec = + d.read_struct_field("normalized_pos", 9, |d| Decodable::decode(d))?; Ok(SourceFile { name, name_was_remapped, @@ -1050,6 +1066,7 @@ impl Decodable for SourceFile { lines, multibyte_chars, non_narrow_chars, + normalized_pos, name_hash, }) }) @@ -1068,8 +1085,7 @@ impl SourceFile { unmapped_path: FileName, mut src: String, start_pos: BytePos) -> Result { - remove_bom(&mut src); - normalize_newlines(&mut src); + let normalized_pos = normalize_src(&mut src, start_pos); let src_hash = { let mut hasher: StableHasher = StableHasher::new(); @@ -1102,6 +1118,7 @@ impl SourceFile { lines, multibyte_chars, non_narrow_chars, + normalized_pos, name_hash, }) } @@ -1228,12 +1245,44 @@ impl SourceFile { pub fn contains(&self, byte_pos: BytePos) -> bool { byte_pos >= self.start_pos && byte_pos <= self.end_pos } + + /// Calculates the original byte position relative to the start of the file + /// based on the given byte position. + pub fn original_relative_byte_pos(&self, pos: BytePos) -> BytePos { + + // Diff before any records is 0. Otherwise use the previously recorded + // diff as that applies to the following characters until a new diff + // is recorded. + let diff = match self.normalized_pos.binary_search_by( + |np| np.pos.cmp(&pos)) { + Ok(i) => self.normalized_pos[i].diff, + Err(i) if i == 0 => 0, + Err(i) => self.normalized_pos[i-1].diff, + }; + + BytePos::from_u32(pos.0 - self.start_pos.0 + diff) + } +} + +/// Normalizes the source code and records the normalizations. +fn normalize_src(src: &mut String, start_pos: BytePos) -> Vec { + let mut normalized_pos = vec![]; + remove_bom(src, &mut normalized_pos); + normalize_newlines(src, &mut normalized_pos); + + // Offset all the positions by start_pos to match the final file positions. + for np in &mut normalized_pos { + np.pos.0 += start_pos.0; + } + + normalized_pos } /// Removes UTF-8 BOM, if any. -fn remove_bom(src: &mut String) { +fn remove_bom(src: &mut String, normalized_pos: &mut Vec) { if src.starts_with("\u{feff}") { src.drain(..3); + normalized_pos.push(NormalizedPos { pos: BytePos(0), diff: 3 }); } } @@ -1241,7 +1290,7 @@ fn remove_bom(src: &mut String) { /// Replaces `\r\n` with `\n` in-place in `src`. /// /// Returns error if there's a lone `\r` in the string -fn normalize_newlines(src: &mut String) { +fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec) { if !src.as_bytes().contains(&b'\r') { return; } @@ -1254,6 +1303,8 @@ fn normalize_newlines(src: &mut String) { let mut buf = std::mem::replace(src, String::new()).into_bytes(); let mut gap_len = 0; let mut tail = buf.as_mut_slice(); + let mut cursor = 0; + let original_gap = normalized_pos.last().map_or(0, |l| l.diff); loop { let idx = match find_crlf(&tail[gap_len..]) { None => tail.len(), @@ -1264,7 +1315,12 @@ fn normalize_newlines(src: &mut String) { if tail.len() == gap_len { break; } + cursor += idx - gap_len; gap_len += 1; + normalized_pos.push(NormalizedPos { + pos: BytePos::from_usize(cursor + 1), + diff: original_gap + gap_len as u32, + }); } // Account for removed `\r`. diff --git a/src/libsyntax_pos/tests.rs b/src/libsyntax_pos/tests.rs index 6bd6016020a27..87cc3505e389b 100644 --- a/src/libsyntax_pos/tests.rs +++ b/src/libsyntax_pos/tests.rs @@ -19,20 +19,25 @@ fn test_lookup_line() { #[test] fn test_normalize_newlines() { - fn check(before: &str, after: &str) { + fn check(before: &str, after: &str, expected_positions: &[u32]) { let mut actual = before.to_string(); - normalize_newlines(&mut actual); + let mut actual_positions = vec![]; + normalize_newlines(&mut actual, &mut actual_positions); + let actual_positions : Vec<_> = actual_positions + .into_iter() + .map(|nc| nc.pos.0).collect(); assert_eq!(actual.as_str(), after); + assert_eq!(actual_positions, expected_positions); } - check("", ""); - check("\n", "\n"); - check("\r", "\r"); - check("\r\r", "\r\r"); - check("\r\n", "\n"); - check("hello world", "hello world"); - check("hello\nworld", "hello\nworld"); - check("hello\r\nworld", "hello\nworld"); - check("\r\nhello\r\nworld\r\n", "\nhello\nworld\n"); - check("\r\r\n", "\r\n"); - check("hello\rworld", "hello\rworld"); + check("", "", &[]); + check("\n", "\n", &[]); + check("\r", "\r", &[]); + check("\r\r", "\r\r", &[]); + check("\r\n", "\n", &[1]); + check("hello world", "hello world", &[]); + check("hello\nworld", "hello\nworld", &[]); + check("hello\r\nworld", "hello\nworld", &[6]); + check("\r\nhello\r\nworld\r\n", "\nhello\nworld\n", &[1, 7, 13]); + check("\r\r\n", "\r\n", &[2]); + check("hello\rworld", "hello\rworld", &[]); } diff --git a/src/test/ui/.gitattributes b/src/test/ui/.gitattributes index 489dc8ad1118c..9ea3d3fb0e1f1 100644 --- a/src/test/ui/.gitattributes +++ b/src/test/ui/.gitattributes @@ -1,3 +1,6 @@ lexer-crlf-line-endings-string-literal-doc-comment.rs -text +json-bom-plus-crlf.rs -text +json-bom-plus-crlf-multifile.rs -text +json-bom-plus-crlf-multifile-aux.rs -text trailing-carriage-return-in-string.rs -text *.bin -text diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive.rs b/src/test/ui/feature-gates/feature-gate-non_exhaustive.rs deleted file mode 100644 index 950f170f4fd41..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-non_exhaustive.rs +++ /dev/null @@ -1,10 +0,0 @@ -//#![feature(non_exhaustive)] - -#[non_exhaustive] //~ERROR the `#[non_exhaustive]` attribute is an experimental feature -pub enum NonExhaustiveEnum { - Unit, - Tuple(u32), - Struct { field: u32 } -} - -fn main() { } diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive.stderr b/src/test/ui/feature-gates/feature-gate-non_exhaustive.stderr deleted file mode 100644 index 482332b8d706c..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-non_exhaustive.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: the `#[non_exhaustive]` attribute is an experimental feature - --> $DIR/feature-gate-non_exhaustive.rs:3:1 - | -LL | #[non_exhaustive] - | ^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/44109 - = help: add `#![feature(non_exhaustive)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/json-bom-plus-crlf-multifile-aux.rs b/src/test/ui/json-bom-plus-crlf-multifile-aux.rs new file mode 100644 index 0000000000000..991ea1d85d2ca --- /dev/null +++ b/src/test/ui/json-bom-plus-crlf-multifile-aux.rs @@ -0,0 +1,27 @@ +// (This line has BOM so it's ignored by compiletest for directives) +// +// ignore-test Not a test. Used by other tests +// ignore-tidy-cr + +// For easier verifying, the byte offsets in this file should match those +// in the json-bom-plus-crlf.rs - given the actual fn is identical (just with +// a different, but equally sized name), the easiest way to do this is to +// ensure the two files are of equal size on disk. +// Padding............................ + +// N.B., this file needs CRLF line endings. The .gitattributes file in +// this directory should enforce it. + +pub fn test() { + + let s : String = 1; // Error in the middle of line. + + let s : String = 1 + ; // Error before the newline. + + let s : String = +1; // Error after the newline. + + let s : String = ( + ); // Error spanning the newline. +} diff --git a/src/test/ui/json-bom-plus-crlf-multifile.rs b/src/test/ui/json-bom-plus-crlf-multifile.rs new file mode 100644 index 0000000000000..c71dd325f4427 --- /dev/null +++ b/src/test/ui/json-bom-plus-crlf-multifile.rs @@ -0,0 +1,12 @@ +// (This line has BOM so it's ignored by compiletest for directives) +// +// build-fail +// compile-flags: --json=diagnostic-short --error-format=json +// ignore-tidy-cr + +#[path = "json-bom-plus-crlf-multifile-aux.rs"] +mod json_bom_plus_crlf_multifile_aux; + +fn main() { + json_bom_plus_crlf_multifile_aux::test(); +} diff --git a/src/test/ui/json-bom-plus-crlf-multifile.stderr b/src/test/ui/json-bom-plus-crlf-multifile.stderr new file mode 100644 index 0000000000000..8472f16108909 --- /dev/null +++ b/src/test/ui/json-bom-plus-crlf-multifile.stderr @@ -0,0 +1,86 @@ +{"message":"mismatched types","code":{"code":"E0308","explanation":" +This error occurs when the compiler was unable to infer the concrete type of a +variable. It can occur for several cases, the most common of which is a +mismatch in the expected type that the compiler inferred for a variable's +initializing expression, and the actual type explicitly assigned to the +variable. + +For example: + +```compile_fail,E0308 +let x: i32 = \"I am not a number!\"; +// ~~~ ~~~~~~~~~~~~~~~~~~~~ +// | | +// | initializing expression; +// | compiler infers type `&str` +// | +// type `i32` assigned to variable `x` +``` +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected type `std::string::String` + found type `{integer}`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types +"} +{"message":"mismatched types","code":{"code":"E0308","explanation":" +This error occurs when the compiler was unable to infer the concrete type of a +variable. It can occur for several cases, the most common of which is a +mismatch in the expected type that the compiler inferred for a variable's +initializing expression, and the actual type explicitly assigned to the +variable. + +For example: + +```compile_fail,E0308 +let x: i32 = \"I am not a number!\"; +// ~~~ ~~~~~~~~~~~~~~~~~~~~ +// | | +// | initializing expression; +// | compiler infers type `&str` +// | +// type `i32` assigned to variable `x` +``` +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected type `std::string::String` + found type `{integer}`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types +"} +{"message":"mismatched types","code":{"code":"E0308","explanation":" +This error occurs when the compiler was unable to infer the concrete type of a +variable. It can occur for several cases, the most common of which is a +mismatch in the expected type that the compiler inferred for a variable's +initializing expression, and the actual type explicitly assigned to the +variable. + +For example: + +```compile_fail,E0308 +let x: i32 = \"I am not a number!\"; +// ~~~ ~~~~~~~~~~~~~~~~~~~~ +// | | +// | initializing expression; +// | compiler infers type `&str` +// | +// type `i32` assigned to variable `x` +``` +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected type `std::string::String` + found type `{integer}`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types +"} +{"message":"mismatched types","code":{"code":"E0308","explanation":" +This error occurs when the compiler was unable to infer the concrete type of a +variable. It can occur for several cases, the most common of which is a +mismatch in the expected type that the compiler inferred for a variable's +initializing expression, and the actual type explicitly assigned to the +variable. + +For example: + +```compile_fail,E0308 +let x: i32 = \"I am not a number!\"; +// ~~~ ~~~~~~~~~~~~~~~~~~~~ +// | | +// | initializing expression; +// | compiler infers type `&str` +// | +// type `i32` assigned to variable `x` +``` +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":801,"byte_end":809,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `std::string::String`, found ()","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected type `std::string::String` + found type `()`","code":null,"level":"note","spans":[],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:25:22: error[E0308]: mismatched types +"} +{"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors +"} diff --git a/src/test/ui/json-bom-plus-crlf.rs b/src/test/ui/json-bom-plus-crlf.rs new file mode 100644 index 0000000000000..ae54a35d4805c --- /dev/null +++ b/src/test/ui/json-bom-plus-crlf.rs @@ -0,0 +1,27 @@ +// (This line has BOM so it's ignored by compiletest for directives) +// +// build-fail +// compile-flags: --json=diagnostic-short --error-format=json +// ignore-tidy-cr + +// For easier verifying, the byte offsets in this file should match those +// in the json_bom_plus_crlf_multifile_aux.rs - given the actual fn is +// identical (just with a different, but equally sized name), the easiest way +// to do this is to ensure the two files are of equal size on disk. + +// N.B., this file needs CRLF line endings. The .gitattributes file in +// this directory should enforce it. + +fn main() { + + let s : String = 1; // Error in the middle of line. + + let s : String = 1 + ; // Error before the newline. + + let s : String = +1; // Error after the newline. + + let s : String = ( + ); // Error spanning the newline. +} diff --git a/src/test/ui/json-bom-plus-crlf.stderr b/src/test/ui/json-bom-plus-crlf.stderr new file mode 100644 index 0000000000000..17775f59fd16f --- /dev/null +++ b/src/test/ui/json-bom-plus-crlf.stderr @@ -0,0 +1,86 @@ +{"message":"mismatched types","code":{"code":"E0308","explanation":" +This error occurs when the compiler was unable to infer the concrete type of a +variable. It can occur for several cases, the most common of which is a +mismatch in the expected type that the compiler inferred for a variable's +initializing expression, and the actual type explicitly assigned to the +variable. + +For example: + +```compile_fail,E0308 +let x: i32 = \"I am not a number!\"; +// ~~~ ~~~~~~~~~~~~~~~~~~~~ +// | | +// | initializing expression; +// | compiler infers type `&str` +// | +// type `i32` assigned to variable `x` +``` +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected type `std::string::String` + found type `{integer}`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:17:22: error[E0308]: mismatched types +"} +{"message":"mismatched types","code":{"code":"E0308","explanation":" +This error occurs when the compiler was unable to infer the concrete type of a +variable. It can occur for several cases, the most common of which is a +mismatch in the expected type that the compiler inferred for a variable's +initializing expression, and the actual type explicitly assigned to the +variable. + +For example: + +```compile_fail,E0308 +let x: i32 = \"I am not a number!\"; +// ~~~ ~~~~~~~~~~~~~~~~~~~~ +// | | +// | initializing expression; +// | compiler infers type `&str` +// | +// type `i32` assigned to variable `x` +``` +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected type `std::string::String` + found type `{integer}`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:19:22: error[E0308]: mismatched types +"} +{"message":"mismatched types","code":{"code":"E0308","explanation":" +This error occurs when the compiler was unable to infer the concrete type of a +variable. It can occur for several cases, the most common of which is a +mismatch in the expected type that the compiler inferred for a variable's +initializing expression, and the actual type explicitly assigned to the +variable. + +For example: + +```compile_fail,E0308 +let x: i32 = \"I am not a number!\"; +// ~~~ ~~~~~~~~~~~~~~~~~~~~ +// | | +// | initializing expression; +// | compiler infers type `&str` +// | +// type `i32` assigned to variable `x` +``` +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected type `std::string::String` + found type `{integer}`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:23:1: error[E0308]: mismatched types +"} +{"message":"mismatched types","code":{"code":"E0308","explanation":" +This error occurs when the compiler was unable to infer the concrete type of a +variable. It can occur for several cases, the most common of which is a +mismatch in the expected type that the compiler inferred for a variable's +initializing expression, and the actual type explicitly assigned to the +variable. + +For example: + +```compile_fail,E0308 +let x: i32 = \"I am not a number!\"; +// ~~~ ~~~~~~~~~~~~~~~~~~~~ +// | | +// | initializing expression; +// | compiler infers type `&str` +// | +// type `i32` assigned to variable `x` +``` +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":801,"byte_end":809,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `std::string::String`, found ()","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected type `std::string::String` + found type `()`","code":null,"level":"note","spans":[],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:25:22: error[E0308]: mismatched types +"} +{"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors +"} diff --git a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs index e3820599c72d9..bbc25d40256ff 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs @@ -1,5 +1,4 @@ #![crate_type = "rlib"] -#![feature(non_exhaustive)] #[non_exhaustive] pub enum NonExhaustiveEnum { diff --git a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs index ddfb9ad003748..6bfe7bf923d09 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs @@ -1,5 +1,3 @@ -#![feature(non_exhaustive)] - #[non_exhaustive] pub struct NormalStruct { pub first_field: u16, diff --git a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/variants.rs b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/variants.rs index f590d0a3268ff..02672d5454e57 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/variants.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/variants.rs @@ -1,5 +1,4 @@ #![crate_type = "rlib"] -#![feature(non_exhaustive)] pub enum NonExhaustiveVariants { #[non_exhaustive] Unit, diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate.rs index a3626bf60b260..54e42917f52d2 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(non_exhaustive)] - #[non_exhaustive] pub enum NonExhaustiveEnum { Unit, diff --git a/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs b/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs index 1a187d042517e..d6251fcb768f4 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs @@ -1,5 +1,3 @@ -#![feature(non_exhaustive)] - #[non_exhaustive] #[repr(C)] pub enum NonExhaustiveEnum { diff --git a/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/same_crate_proper.rs b/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/same_crate_proper.rs index 3f38e3cd8e5a7..c09aa256e0e74 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/same_crate_proper.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/same_crate_proper.rs @@ -1,5 +1,4 @@ // check-pass -#![feature(non_exhaustive)] #![deny(improper_ctypes)] // This test checks that non-exhaustive types with `#[repr(C)]` are considered proper within diff --git a/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.rs b/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.rs index b7938e1afa3bc..3c4a09fafd2db 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.rs @@ -1,5 +1,3 @@ -#![feature(non_exhaustive)] - #[non_exhaustive(anything)] //~^ ERROR malformed `non_exhaustive` attribute struct Foo; diff --git a/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.stderr b/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.stderr index 21dc340d21204..76d9e2d8205b7 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.stderr @@ -1,11 +1,11 @@ error: malformed `non_exhaustive` attribute input - --> $DIR/invalid-attribute.rs:3:1 + --> $DIR/invalid-attribute.rs:1:1 | LL | #[non_exhaustive(anything)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[non_exhaustive]` error[E0701]: attribute can only be applied to a struct or enum - --> $DIR/invalid-attribute.rs:7:1 + --> $DIR/invalid-attribute.rs:5:1 | LL | #[non_exhaustive] | ^^^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL | trait Bar { } | ------------- not a struct or enum error[E0701]: attribute can only be applied to a struct or enum - --> $DIR/invalid-attribute.rs:11:1 + --> $DIR/invalid-attribute.rs:9:1 | LL | #[non_exhaustive] | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/rfc-2008-non-exhaustive/struct.stderr b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr index d3686a1b86961..04cfe51cab025 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/struct.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr @@ -16,7 +16,7 @@ error[E0603]: tuple struct constructor `TupleStruct` is private LL | let ts_explicit = structs::TupleStruct(640, 480); | ^^^^^^^^^^^ | - ::: $DIR/auxiliary/structs.rs:13:24 + ::: $DIR/auxiliary/structs.rs:11:24 | LL | pub struct TupleStruct(pub u16, pub u16); | ---------------- a constructor is private if any of the fields is private diff --git a/src/test/ui/rfc-2008-non-exhaustive/structs_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/structs_same_crate.rs index 2b1d7d9ac5030..5f76b0cb2f4b6 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/structs_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/structs_same_crate.rs @@ -1,7 +1,6 @@ // run-pass #![allow(unused_variables)] -#![feature(non_exhaustive)] #[non_exhaustive] pub struct NormalStruct { diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs index 8cb9a8cf1f613..a2735d4cbfb29 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs @@ -1,6 +1,5 @@ #![crate_type = "rlib"] #![feature(never_type)] -#![feature(non_exhaustive)] #[non_exhaustive] pub enum UninhabitedEnum { diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs index 803a542f8aa4b..6b911dd989cc5 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs @@ -1,5 +1,4 @@ #![feature(never_type)] -#![feature(non_exhaustive)] #[non_exhaustive] pub enum UninhabitedEnum { diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr index 8f6b709bb1f34..a07473dade22c 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/coercions_same_crate.rs:31:5 + --> $DIR/coercions_same_crate.rs:30:5 | LL | fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { | - expected `A` because of return type @@ -10,7 +10,7 @@ LL | x found type `UninhabitedEnum` error[E0308]: mismatched types - --> $DIR/coercions_same_crate.rs:35:5 + --> $DIR/coercions_same_crate.rs:34:5 | LL | fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { | - expected `A` because of return type @@ -21,7 +21,7 @@ LL | x found type `UninhabitedTupleStruct` error[E0308]: mismatched types - --> $DIR/coercions_same_crate.rs:39:5 + --> $DIR/coercions_same_crate.rs:38:5 | LL | fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { | - expected `A` because of return type @@ -32,7 +32,7 @@ LL | x found type `UninhabitedStruct` error[E0308]: mismatched types - --> $DIR/coercions_same_crate.rs:43:5 + --> $DIR/coercions_same_crate.rs:42:5 | LL | fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { | - expected `A` because of return type diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs index 3c8d495e12cb6..8f090fe886a00 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs @@ -1,5 +1,4 @@ #![feature(never_type)] -#![feature(non_exhaustive)] #[non_exhaustive] pub enum UninhabitedEnum { diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr index 27b120792d6d1..c03018a523647 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedEnum` of type `IndirectUninhabitedEnum` is not handled - --> $DIR/indirect_match_same_crate.rs:35:11 + --> $DIR/indirect_match_same_crate.rs:34:11 | LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum); | ---------------------------------------------------- @@ -13,7 +13,7 @@ LL | match x {} = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedStruct` of type `IndirectUninhabitedStruct` is not handled - --> $DIR/indirect_match_same_crate.rs:39:11 + --> $DIR/indirect_match_same_crate.rs:38:11 | LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct); | -------------------------------------------------------- @@ -27,7 +27,7 @@ LL | match x {} = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedTupleStruct` of type `IndirectUninhabitedTupleStruct` is not handled - --> $DIR/indirect_match_same_crate.rs:43:11 + --> $DIR/indirect_match_same_crate.rs:42:11 | LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); | ------------------------------------------------------------------ @@ -41,7 +41,7 @@ LL | match x {} = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedVariants` of type `IndirectUninhabitedVariants` is not handled - --> $DIR/indirect_match_same_crate.rs:49:11 + --> $DIR/indirect_match_same_crate.rs:48:11 | LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants); | ------------------------------------------------------------ diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs index d1e7c3b4d518a..60289aa780378 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs @@ -3,7 +3,6 @@ #![deny(unreachable_patterns)] #![feature(exhaustive_patterns)] #![feature(never_type)] -#![feature(non_exhaustive)] #[non_exhaustive] pub enum UninhabitedEnum { diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs index 0096e2963007a..230ac75298e72 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs @@ -1,7 +1,6 @@ // aux-build:uninhabited.rs #![deny(unreachable_patterns)] #![feature(never_type)] -#![feature(non_exhaustive)] extern crate uninhabited; diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr index d46b1fd4c4202..f2b9983af8602 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr @@ -1,5 +1,5 @@ error: unreachable pattern - --> $DIR/issue-65157-repeated-match-arm.rs:16:9 + --> $DIR/issue-65157-repeated-match-arm.rs:15:9 | LL | PartiallyInhabitedVariants::Struct { .. } => {}, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs index 6405dd3bd65b7..ebbdfba15f3a3 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs @@ -1,5 +1,4 @@ #![feature(never_type)] -#![feature(non_exhaustive)] #[non_exhaustive] pub enum UninhabitedEnum { diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr index 410285a39a945..c39df05a8f74e 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: pattern `UninhabitedStruct` of type `UninhabitedStruct` is not handled - --> $DIR/match_same_crate.rs:31:11 + --> $DIR/match_same_crate.rs:30:11 | LL | pub struct UninhabitedStruct { | - ----------------- variant not covered @@ -15,7 +15,7 @@ LL | match x {} = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: pattern `UninhabitedTupleStruct` of type `UninhabitedTupleStruct` is not handled - --> $DIR/match_same_crate.rs:35:11 + --> $DIR/match_same_crate.rs:34:11 | LL | pub struct UninhabitedTupleStruct(!); | ------------------------------------- @@ -29,7 +29,7 @@ LL | match x {} = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: multiple patterns of type `UninhabitedVariants` are not handled - --> $DIR/match_same_crate.rs:39:11 + --> $DIR/match_same_crate.rs:38:11 | LL | / pub enum UninhabitedVariants { LL | | #[non_exhaustive] Tuple(!), diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs index 8973d21bff6fa..de5530485f3e6 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs @@ -3,7 +3,6 @@ #![deny(unreachable_patterns)] #![feature(exhaustive_patterns)] #![feature(never_type)] -#![feature(non_exhaustive)] #[non_exhaustive] pub enum UninhabitedEnum { diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs index 302a35cab5f90..ffc496a975ecf 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs @@ -1,7 +1,6 @@ #![deny(unreachable_patterns)] #![feature(exhaustive_patterns)] #![feature(never_type)] -#![feature(non_exhaustive)] #[non_exhaustive] pub enum UninhabitedEnum { diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr index 72f37d9a60ba8..e3de94be1282e 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr @@ -1,5 +1,5 @@ error: unreachable pattern - --> $DIR/patterns_same_crate.rs:53:9 + --> $DIR/patterns_same_crate.rs:52:9 | LL | Some(_x) => (), | ^^^^^^^^ @@ -11,25 +11,25 @@ LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/patterns_same_crate.rs:58:9 + --> $DIR/patterns_same_crate.rs:57:9 | LL | Some(_x) => (), | ^^^^^^^^ error: unreachable pattern - --> $DIR/patterns_same_crate.rs:62:15 + --> $DIR/patterns_same_crate.rs:61:15 | LL | while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/patterns_same_crate.rs:66:15 + --> $DIR/patterns_same_crate.rs:65:15 | LL | while let Some(_x) = uninhabited_struct() { | ^^^^^^^^ error: unreachable pattern - --> $DIR/patterns_same_crate.rs:69:15 + --> $DIR/patterns_same_crate.rs:68:15 | LL | while let Some(_x) = uninhabited_tuple_struct() { | ^^^^^^^^ diff --git a/src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs index fe7df44590b8d..5f2816ec62102 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(non_exhaustive)] - pub enum NonExhaustiveVariants { #[non_exhaustive] Unit, #[non_exhaustive] Tuple(u32),