1
Fork 0

Auto merge of #65804 - Centril:rollup-arlxgch, r=Centril

Rollup of 9 pull requests

Successful merges:

 - #64639 (Stabilize `#[non_exhaustive]` (RFC 2008))
 - #65074 (Fix the start/end byte positions in the compiler JSON output)
 - #65315 (Intern place projection)
 - #65685 (Fix check of `statx` and handle EPERM)
 - #65731 (Prevent unnecessary allocation in PathBuf::set_extension.)
 - #65740 (Fix default "disable-shortcuts" feature value)
 - #65787 (move panictry! to where it is used.)
 - #65789 (move Attribute::with_desugared_doc to librustdoc)
 - #65790 (move report_invalid_macro_expansion_item to item.rs)

Failed merges:

r? @ghost
This commit is contained in:
bors 2019-10-25 11:13:30 +00:00
commit 23f890f102
117 changed files with 1862 additions and 1358 deletions

View file

@ -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;
```

View file

@ -121,7 +121,7 @@
#![feature(hexagon_target_feature)] #![feature(hexagon_target_feature)]
#![feature(const_int_conversion)] #![feature(const_int_conversion)]
#![feature(const_transmute)] #![feature(const_transmute)]
#![feature(non_exhaustive)] #![cfg_attr(bootstrap, feature(non_exhaustive))]
#![feature(structural_match)] #![feature(structural_match)]
#![feature(abi_unadjusted)] #![feature(abi_unadjusted)]
#![feature(adx_target_feature)] #![feature(adx_target_feature)]

View file

@ -25,7 +25,7 @@
#![feature(extern_types)] #![feature(extern_types)]
#![feature(in_band_lifetimes)] #![feature(in_band_lifetimes)]
#![feature(optin_builtin_traits)] #![feature(optin_builtin_traits)]
#![feature(non_exhaustive)] #![cfg_attr(bootstrap, feature(non_exhaustive))]
#![feature(rustc_attrs)] #![feature(rustc_attrs)]
#![feature(specialization)] #![feature(specialization)]

View file

@ -2105,8 +2105,6 @@ on something other than a struct or enum.
Examples of erroneous code: Examples of erroneous code:
```compile_fail,E0701 ```compile_fail,E0701
# #![feature(non_exhaustive)]
#[non_exhaustive] #[non_exhaustive]
trait Foo { } trait Foo { }
``` ```

View file

@ -425,6 +425,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
ref lines, ref lines,
ref multibyte_chars, ref multibyte_chars,
ref non_narrow_chars, ref non_narrow_chars,
ref normalized_pos,
} = *self; } = *self;
(name_hash as u64).hash_stable(hcx, hasher); (name_hash as u64).hash_stable(hcx, hasher);
@ -453,6 +454,12 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
for &char_pos in non_narrow_chars.iter() { for &char_pos in non_narrow_chars.iter() {
stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher); 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) (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<StableHashingContext<'tcx>> for feature_gate::Features { impl<'tcx> HashStable<StableHashingContext<'tcx>> for feature_gate::Features {
fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
// Unfortunately we cannot exhaustively list fields here, since the // Unfortunately we cannot exhaustively list fields here, since the

View file

@ -41,7 +41,7 @@
#![feature(overlapping_marker_traits)] #![feature(overlapping_marker_traits)]
#![feature(extern_types)] #![feature(extern_types)]
#![feature(nll)] #![feature(nll)]
#![feature(non_exhaustive)] #![cfg_attr(bootstrap, feature(non_exhaustive))]
#![feature(optin_builtin_traits)] #![feature(optin_builtin_traits)]
#![feature(option_expect_none)] #![feature(option_expect_none)]
#![feature(range_is_empty)] #![feature(range_is_empty)]

View file

@ -15,8 +15,7 @@ use crate::ty::layout::VariantIdx;
use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::print::{FmtPrinter, Printer};
use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::subst::{Subst, SubstsRef};
use crate::ty::{ use crate::ty::{
self, AdtDef, CanonicalUserTypeAnnotations, Region, Ty, TyCtxt, self, AdtDef, CanonicalUserTypeAnnotations, List, Region, Ty, TyCtxt, UserTypeAnnotationIndex,
UserTypeAnnotationIndex,
}; };
use polonius_engine::Atom; use polonius_engine::Atom;
@ -1712,15 +1711,17 @@ impl Debug for Statement<'_> {
/// A path to a value; something that can be evaluated without /// A path to a value; something that can be evaluated without
/// changing or disturbing program state. /// changing or disturbing program state.
#[derive( #[derive(
Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, HashStable,
)] )]
pub struct Place<'tcx> { pub struct Place<'tcx> {
pub base: PlaceBase<'tcx>, pub base: PlaceBase<'tcx>,
/// projection out of a place (access a field, deref a pointer, etc) /// projection out of a place (access a field, deref a pointer, etc)
pub projection: Box<[PlaceElem<'tcx>]>, pub projection: &'tcx List<PlaceElem<'tcx>>,
} }
impl<'tcx> rustc_serialize::UseSpecializedDecodable for Place<'tcx> {}
#[derive( #[derive(
Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
)] )]
@ -1824,6 +1825,8 @@ impl<V, T> ProjectionElem<V, T> {
/// and the index is a local. /// and the index is a local.
pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>; pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>;
impl<'tcx> Copy for PlaceElem<'tcx> { }
// At least on 64 bit systems, `PlaceElem` should not be larger than two pointers. // At least on 64 bit systems, `PlaceElem` should not be larger than two pointers.
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
static_assert_size!(PlaceElem<'_>, 16); static_assert_size!(PlaceElem<'_>, 16);
@ -1846,50 +1849,11 @@ pub struct PlaceRef<'a, 'tcx> {
} }
impl<'tcx> Place<'tcx> { impl<'tcx> Place<'tcx> {
// FIXME change this back to a const when projection is a shared slice. // FIXME change this to a const fn by also making List::empty a const fn.
//
// pub const RETURN_PLACE: Place<'tcx> = Place {
// base: PlaceBase::Local(RETURN_PLACE),
// projection: &[],
// };
pub fn return_place() -> Place<'tcx> { pub fn return_place() -> Place<'tcx> {
Place { Place {
base: PlaceBase::Local(RETURN_PLACE), base: PlaceBase::Local(RETURN_PLACE),
projection: Box::new([]), projection: List::empty(),
}
}
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(),
} }
} }
@ -1906,15 +1870,15 @@ impl<'tcx> Place<'tcx> {
// //
// FIXME: can we safely swap the semantics of `fn base_local` below in here instead? // FIXME: can we safely swap the semantics of `fn base_local` below in here instead?
pub fn local_or_deref_local(&self) -> Option<Local> { pub fn local_or_deref_local(&self) -> Option<Local> {
match self { match self.as_ref() {
Place { PlaceRef {
base: PlaceBase::Local(local), base: &PlaceBase::Local(local),
projection: box [], projection: &[],
} | } |
Place { PlaceRef {
base: PlaceBase::Local(local), base: &PlaceBase::Local(local),
projection: box [ProjectionElem::Deref], projection: &[ProjectionElem::Deref],
} => Some(*local), } => Some(local),
_ => None, _ => None,
} }
} }
@ -1922,10 +1886,7 @@ impl<'tcx> Place<'tcx> {
/// If this place represents a local variable like `_X` with no /// If this place represents a local variable like `_X` with no
/// projections, return `Some(_X)`. /// projections, return `Some(_X)`.
pub fn as_local(&self) -> Option<Local> { pub fn as_local(&self) -> Option<Local> {
match self { self.as_ref().as_local()
Place { projection: box [], base: PlaceBase::Local(l) } => Some(*l),
_ => None,
}
} }
pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> { pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> {
@ -1940,7 +1901,7 @@ impl From<Local> for Place<'_> {
fn from(local: Local) -> Self { fn from(local: Local) -> Self {
Place { Place {
base: local.into(), base: local.into(),
projection: Box::new([]), projection: List::empty(),
} }
} }
} }
@ -1969,6 +1930,15 @@ impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
_ => None, _ => None,
} }
} }
/// If this place represents a local variable like `_X` with no
/// projections, return `Some(_X)`.
pub fn as_local(&self) -> Option<Local> {
match self {
PlaceRef { base: PlaceBase::Local(l), projection: [] } => Some(*l),
_ => None,
}
}
} }
impl Debug for Place<'_> { impl Debug for Place<'_> {
@ -3182,6 +3152,17 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceBase<'tcx> {
} }
} }
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
let v = self.iter().map(|t| t.fold_with(folder)).collect::<Vec<_>>();
folder.tcx().intern_place_elems(&v)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.iter().any(|t| t.visit_with(visitor))
}
}
impl<'tcx> TypeFoldable<'tcx> for Static<'tcx> { impl<'tcx> TypeFoldable<'tcx> for Static<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
Static { Static {

View file

@ -784,6 +784,8 @@ macro_rules! make_mir_visitor {
macro_rules! visit_place_fns { macro_rules! visit_place_fns {
(mut) => ( (mut) => (
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
fn super_place( fn super_place(
&mut self, &mut self,
place: &mut Place<'tcx>, place: &mut Place<'tcx>,
@ -793,19 +795,21 @@ macro_rules! visit_place_fns {
self.visit_place_base(&mut place.base, context, location); self.visit_place_base(&mut place.base, context, location);
if let Some(new_projection) = self.process_projection(&place.projection) { 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( fn process_projection(
&mut self, &mut self,
projection: &'a [PlaceElem<'tcx>], projection: &'a [PlaceElem<'tcx>],
) -> Option<Box<[PlaceElem<'tcx>]>> { ) -> Option<Vec<PlaceElem<'tcx>>> {
let mut projection = Cow::Borrowed(projection); let mut projection = Cow::Borrowed(projection);
for i in 0..projection.len() { for i in 0..projection.len() {
if let Some(elem) = projection.get(i) { if let Some(elem) = projection.get(i) {
if let Some(elem) = self.process_projection_elem(elem) { 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(); let vec = projection.to_mut();
vec[i] = elem; vec[i] = elem;
} }
@ -814,7 +818,7 @@ macro_rules! visit_place_fns {
match projection { match projection {
Cow::Borrowed(_) => None, Cow::Borrowed(_) => None,
Cow::Owned(vec) => Some(vec.into_boxed_slice()), Cow::Owned(vec) => Some(vec),
} }
} }

View file

@ -13,9 +13,9 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_serialize::{Decodable, Decoder, Encoder, Encodable, opaque}; use rustc_serialize::{Decodable, Decoder, Encoder, Encodable, opaque};
use std::hash::Hash; use std::hash::Hash;
use std::intrinsics; use std::intrinsics;
use crate::ty::{self, Ty, TyCtxt}; use crate::ty::{self, List, Ty, TyCtxt};
use crate::ty::subst::SubstsRef; use crate::ty::subst::SubstsRef;
use crate::mir::interpret::Allocation; use crate::mir::{self, interpret::Allocation};
use syntax_pos::Span; use syntax_pos::Span;
/// The shorthand encoding uses an enum's variant index `usize` /// 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)))?) Ok(tcx.mk_substs((0..len).map(|_| Decodable::decode(decoder)))?)
} }
#[inline]
pub fn decode_place<D>(decoder: &mut D) -> Result<mir::Place<'tcx>, D::Error>
where
D: TyDecoder<'tcx>,
{
let base: mir::PlaceBase<'tcx> = Decodable::decode(decoder)?;
let len = decoder.read_usize()?;
let projection: &'tcx List<mir::PlaceElem<'tcx>> =
decoder.tcx().mk_place_elems((0..len).map(|_| Decodable::decode(decoder)))?;
Ok(mir::Place { base, projection })
}
#[inline] #[inline]
pub fn decode_region<D>(decoder: &mut D) -> Result<ty::Region<'tcx>, D::Error> pub fn decode_region<D>(decoder: &mut D) -> Result<ty::Region<'tcx>, D::Error>
where 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<ty::Region<'tcx>> impl<$($typaram),*> SpecializedDecoder<ty::Region<'tcx>>
for $DecoderName<$($typaram),*> { for $DecoderName<$($typaram),*> {
fn specialized_decode(&mut self) -> Result<ty::Region<'tcx>, Self::Error> { fn specialized_decode(&mut self) -> Result<ty::Region<'tcx>, Self::Error> {

View file

@ -1,3 +1,4 @@
// ignore-tidy-filelength
//! Type context book-keeping. //! Type context book-keeping.
use crate::arena::Arena; use crate::arena::Arena;
@ -21,7 +22,7 @@ use crate::middle::cstore::EncodedMetadata;
use crate::middle::lang_items; use crate::middle::lang_items;
use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault};
use crate::middle::stability; 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::mir::interpret::{ConstValue, Allocation, Scalar};
use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef, Subst}; use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef, Subst};
use crate::ty::ReprOptions; use crate::ty::ReprOptions;
@ -106,6 +107,7 @@ pub struct CtxtInterners<'tcx> {
goal: InternedSet<'tcx, GoalKind<'tcx>>, goal: InternedSet<'tcx, GoalKind<'tcx>>,
goal_list: InternedSet<'tcx, List<Goal<'tcx>>>, goal_list: InternedSet<'tcx, List<Goal<'tcx>>>,
projs: InternedSet<'tcx, List<ProjectionKind>>, projs: InternedSet<'tcx, List<ProjectionKind>>,
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
const_: InternedSet<'tcx, Const<'tcx>>, const_: InternedSet<'tcx, Const<'tcx>>,
} }
@ -124,6 +126,7 @@ impl<'tcx> CtxtInterners<'tcx> {
goal: Default::default(), goal: Default::default(),
goal_list: Default::default(), goal_list: Default::default(),
projs: Default::default(), projs: Default::default(),
place_elems: Default::default(),
const_: Default::default(), const_: Default::default(),
} }
} }
@ -2142,6 +2145,13 @@ impl<'tcx> Borrow<[ProjectionKind]>
} }
} }
impl<'tcx> Borrow<[PlaceElem<'tcx>]>
for Interned<'tcx, List<PlaceElem<'tcx>>> {
fn borrow(&self) -> &[PlaceElem<'tcx>] {
&self.0[..]
}
}
impl<'tcx> Borrow<RegionKind> for Interned<'tcx, RegionKind> { impl<'tcx> Borrow<RegionKind> for Interned<'tcx, RegionKind> {
fn borrow(&self) -> &RegionKind { fn borrow(&self) -> &RegionKind {
&self.0 &self.0
@ -2242,7 +2252,8 @@ slice_interners!(
predicates: _intern_predicates(Predicate<'tcx>), predicates: _intern_predicates(Predicate<'tcx>),
clauses: _intern_clauses(Clause<'tcx>), clauses: _intern_clauses(Clause<'tcx>),
goal_list: _intern_goals(Goal<'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> { impl<'tcx> TyCtxt<'tcx> {
@ -2584,6 +2595,48 @@ impl<'tcx> TyCtxt<'tcx> {
self.mk_ty(Opaque(def_id, substs)) 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>]) pub fn intern_existential_predicates(self, eps: &[ExistentialPredicate<'tcx>])
-> &'tcx List<ExistentialPredicate<'tcx>> { -> &'tcx List<ExistentialPredicate<'tcx>> {
assert!(!eps.is_empty()); assert!(!eps.is_empty());
@ -2628,6 +2681,14 @@ impl<'tcx> TyCtxt<'tcx> {
} }
} }
pub fn intern_place_elems(self, ts: &[PlaceElem<'tcx>]) -> &'tcx List<PlaceElem<'tcx>> {
if ts.len() == 0 {
List::empty()
} else {
self._intern_place_elems(ts)
}
}
pub fn intern_canonical_var_infos(self, ts: &[CanonicalVarInfo]) -> CanonicalVarInfos<'tcx> { pub fn intern_canonical_var_infos(self, ts: &[CanonicalVarInfo]) -> CanonicalVarInfos<'tcx> {
if ts.len() == 0 { if ts.len() == 0 {
List::empty() List::empty()
@ -2690,6 +2751,11 @@ impl<'tcx> TyCtxt<'tcx> {
iter.intern_with(|xs| self.intern_substs(xs)) iter.intern_with(|xs| self.intern_substs(xs))
} }
pub fn mk_place_elems<I: InternAs<[PlaceElem<'tcx>],
&'tcx List<PlaceElem<'tcx>>>>(self, iter: I) -> I::Output {
iter.intern_with(|xs| self.intern_place_elems(xs))
}
pub fn mk_substs_trait(self, pub fn mk_substs_trait(self,
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
rest: &[GenericArg<'tcx>]) rest: &[GenericArg<'tcx>])

View file

@ -191,10 +191,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
location: Location) { location: Location) {
debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue); debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue);
if let mir::Place { if let Some(index) = place.as_local() {
base: mir::PlaceBase::Local(index),
projection: box [],
} = *place {
self.assign(index, location); self.assign(index, location);
let decl_span = self.fx.mir.local_decls[index].source_info.span; let decl_span = self.fx.mir.local_decls[index].source_info.span;
if !self.fx.rvalue_creates_operand(rvalue, decl_span) { if !self.fx.rvalue_creates_operand(rvalue, decl_span) {

View file

@ -2,7 +2,7 @@ use rustc_index::vec::Idx;
use rustc::middle::lang_items; use rustc::middle::lang_items;
use rustc::ty::{self, Ty, TypeFoldable, Instance}; use rustc::ty::{self, Ty, TypeFoldable, Instance};
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt}; 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::mir::interpret::PanicInfo;
use rustc_target::abi::call::{ArgType, FnType, PassMode}; use rustc_target::abi::call::{ArgType, FnType, PassMode};
use rustc_target::spec::abi::Abi; 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 // checked by const-qualification, which also
// promotes any complex rvalues to constants. // promotes any complex rvalues to constants.
if i == 2 && intrinsic.unwrap().starts_with("simd_shuffle") { if i == 2 && intrinsic.unwrap().starts_with("simd_shuffle") {
match *arg { match arg {
// The shuffle array argument is usually not an explicit constant, // The shuffle array argument is usually not an explicit constant,
// but specified directly in the code. This means it gets promoted // but specified directly in the code. This means it gets promoted
// and we can then extract the value by evaluating the promoted. // and we can then extract the value by evaluating the promoted.
mir::Operand::Copy( mir::Operand::Copy(place) | mir::Operand::Move(place) => {
Place { if let mir::PlaceRef {
base: PlaceBase::Static(box Static { base:
kind: StaticKind::Promoted(promoted, _), &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, ty,
def_id: _, c,
}), );
projection: box [], 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::Constant(constant) => {
mir::Operand::Copy(_) |
mir::Operand::Move(_) => {
span_bug!(span, "shuffle indices must be constant");
}
mir::Operand::Constant(ref constant) => {
let c = self.eval_mir_constant(constant); let c = self.eval_mir_constant(constant);
let (llval, ty) = self.simd_shuffle_indices( let (llval, ty) = self.simd_shuffle_indices(
&bx, &bx,
@ -1117,10 +1107,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if fn_ret.is_ignore() { if fn_ret.is_ignore() {
return ReturnDest::Nothing; return ReturnDest::Nothing;
} }
let dest = if let mir::Place { let dest = if let Some(index) = dest.as_local() {
base: mir::PlaceBase::Local(index),
projection: box [],
} = *dest {
match self.locals[index] { match self.locals[index] {
LocalRef::Place(dest) => dest, LocalRef::Place(dest) => dest,
LocalRef::UnsizedPlace(_) => bug!("return type must be sized"), 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>, src: &mir::Operand<'tcx>,
dst: &mir::Place<'tcx> dst: &mir::Place<'tcx>
) { ) {
if let mir::Place { if let Some(index) = dst.as_local() {
base: mir::PlaceBase::Local(index),
projection: box [],
} = *dst {
match self.locals[index] { match self.locals[index] {
LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place), LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place),
LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"), LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"),

View file

@ -530,10 +530,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
) -> Bx::Value { ) -> Bx::Value {
// ZST are passed as operands and require special handling // ZST are passed as operands and require special handling
// because codegen_place() panics if Local is operand. // because codegen_place() panics if Local is operand.
if let mir::Place { if let Some(index) = place.as_local() {
base: mir::PlaceBase::Local(index),
projection: box [],
} = *place {
if let LocalRef::Operand(Some(op)) = self.locals[index] { if let LocalRef::Operand(Some(op)) = self.locals[index] {
if let ty::Array(_, n) = op.layout.ty.kind { if let ty::Array(_, n) = op.layout.ty.kind {
let n = n.eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all()); let n = n.eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all());

View file

@ -17,11 +17,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.set_debug_loc(&mut bx, statement.source_info); self.set_debug_loc(&mut bx, statement.source_info);
match statement.kind { match statement.kind {
mir::StatementKind::Assign(box(ref place, ref rvalue)) => { mir::StatementKind::Assign(box(ref place, ref rvalue)) => {
if let mir::Place { if let Some(index) = place.as_local() {
base: mir::PlaceBase::Local(index), match self.locals[index] {
projection: box [],
} = place {
match self.locals[*index] {
LocalRef::Place(cg_dest) => { LocalRef::Place(cg_dest) => {
self.codegen_rvalue(bx, cg_dest, rvalue) 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) => { LocalRef::Operand(None) => {
let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue); 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 { match operand.val {
OperandValue::Ref(x, ..) | OperandValue::Ref(x, ..) |
OperandValue::Immediate(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 bx
} }
LocalRef::Operand(Some(op)) => { LocalRef::Operand(Some(op)) => {

View file

@ -1319,6 +1319,7 @@ impl<'a, 'tcx> CrateMetadata {
mut lines, mut lines,
mut multibyte_chars, mut multibyte_chars,
mut non_narrow_chars, mut non_narrow_chars,
mut normalized_pos,
name_hash, name_hash,
.. } = source_file_to_import; .. } = source_file_to_import;
@ -1338,6 +1339,9 @@ impl<'a, 'tcx> CrateMetadata {
for swc in &mut non_narrow_chars { for swc in &mut non_narrow_chars {
*swc = *swc - start_pos; *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, let local_version = local_source_map.new_imported_source_file(name,
name_was_remapped, name_was_remapped,
@ -1347,7 +1351,8 @@ impl<'a, 'tcx> CrateMetadata {
source_length, source_length,
lines, lines,
multibyte_chars, multibyte_chars,
non_narrow_chars); non_narrow_chars,
normalized_pos);
debug!("CrateMetaData::imported_source_files alloc \ debug!("CrateMetaData::imported_source_files alloc \
source_file {:?} original (start_pos {:?} end_pos {:?}) \ source_file {:?} original (start_pos {:?} end_pos {:?}) \
translated (start_pos {:?} end_pos {:?})", translated (start_pos {:?} end_pos {:?})",

View file

@ -315,10 +315,7 @@ impl<'a, 'tcx> GatherBorrows<'a, 'tcx> {
// TEMP = &foo // TEMP = &foo
// //
// so extract `temp`. // so extract `temp`.
let temp = if let &mir::Place { let temp = if let Some(temp) = assigned_place.as_local() {
base: mir::PlaceBase::Local(temp),
projection: box [],
} = assigned_place {
temp temp
} else { } else {
span_bug!( span_bug!(

View file

@ -239,11 +239,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
); );
} }
} }
let span = if let Place { let span = if let Some(local) = place.as_local() {
base: PlaceBase::Local(local), let decl = &self.body.local_decls[local];
projection: box [],
} = place {
let decl = &self.body.local_decls[*local];
Some(decl.source_info.span) Some(decl.source_info.span)
} else { } else {
None None
@ -611,7 +608,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
projection, projection,
} = first_borrowed_place; } = first_borrowed_place;
let mut cursor = &**projection; let mut cursor = projection.as_ref();
while let [proj_base @ .., elem] = cursor { while let [proj_base @ .., elem] = cursor {
cursor = proj_base; cursor = proj_base;
@ -635,7 +632,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
projection, projection,
} = second_borrowed_place; } = second_borrowed_place;
let mut cursor = &**projection; let mut cursor = projection.as_ref();
while let [proj_base @ .., elem] = cursor { while let [proj_base @ .., elem] = cursor {
cursor = proj_base; cursor = proj_base;
@ -710,10 +707,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
_ => drop_span, _ => drop_span,
}; };
let root_place_projection = self.infcx.tcx.intern_place_elems(root_place.projection);
if self.access_place_error_reported if self.access_place_error_reported
.contains(&(Place { .contains(&(Place {
base: root_place.base.clone(), base: root_place.base.clone(),
projection: root_place.projection.to_vec().into_boxed_slice(), projection: root_place_projection,
}, borrow_span)) }, borrow_span))
{ {
debug!( debug!(
@ -726,7 +725,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.access_place_error_reported self.access_place_error_reported
.insert((Place { .insert((Place {
base: root_place.base.clone(), base: root_place.base.clone(),
projection: root_place.projection.to_vec().into_boxed_slice(), projection: root_place_projection,
}, borrow_span)); }, borrow_span));
if let StorageDeadOrDrop::Destructor(dropped_ty) = 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 (place_desc, note) = if let Some(place_desc) = opt_place_desc {
let local_kind = match borrow.borrowed_place { let local_kind = if let Some(local) = borrow.borrowed_place.as_local() {
Place { match self.body.local_kind(local) {
base: PlaceBase::Local(local), LocalKind::ReturnPointer
projection: box [], | LocalKind::Temp => bug!("temporary or return pointer with a name"),
} => { LocalKind::Var => "local variable ",
match self.body.local_kind(local) { LocalKind::Arg
LocalKind::ReturnPointer if !self.upvars.is_empty()
| LocalKind::Temp => bug!("temporary or return pointer with a name"), && local == Local::new(1) => {
LocalKind::Var => "local variable ", "variable captured by `move` "
LocalKind::Arg }
if !self.upvars.is_empty() LocalKind::Arg => {
&& local == Local::new(1) => { "function parameter "
"variable captured by `move` "
}
LocalKind::Arg => {
"function parameter "
}
} }
} }
_ => "local data ", } else {
"local data "
}; };
( (
format!("{}`{}`", local_kind, place_desc), format!("{}`{}`", local_kind, place_desc),
@ -1480,10 +1475,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
assigned_span: Span, assigned_span: Span,
err_place: &Place<'tcx>, err_place: &Place<'tcx>,
) { ) {
let (from_arg, local_decl) = if let Place { let (from_arg, local_decl) = if let Some(local) = err_place.as_local() {
base: PlaceBase::Local(local),
projection: box [],
} = *err_place {
if let LocalKind::Arg = self.body.local_kind(local) { if let LocalKind::Arg = self.body.local_kind(local) {
(true, Some(&self.body.local_decls[local])) (true, Some(&self.body.local_decls[local]))
} else { } else {
@ -1643,11 +1635,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
reservation reservation
); );
// Check that the initial assignment of the reserve location is into a temporary. // Check that the initial assignment of the reserve location is into a temporary.
let mut target = *match reservation { let mut target = match reservation.as_local() {
Place { Some(local) if self.body.local_kind(local) == LocalKind::Temp => local,
base: PlaceBase::Local(local),
projection: box [],
} if self.body.local_kind(*local) == LocalKind::Temp => local,
_ => return None, _ => return None,
}; };
@ -1659,127 +1648,122 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
"annotate_argument_and_return_for_borrow: target={:?} stmt={:?}", "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
target, stmt target, stmt
); );
if let StatementKind::Assign( if let StatementKind::Assign(box(place, rvalue)) = &stmt.kind {
box( if let Some(assigned_to) = place.as_local() {
Place { debug!(
base: PlaceBase::Local(assigned_to), "annotate_argument_and_return_for_borrow: assigned_to={:?} \
projection: box [], rvalue={:?}",
}, assigned_to, rvalue
rvalue );
) // Check if our `target` was captured by a closure.
) = &stmt.kind { if let Rvalue::Aggregate(
debug!( box AggregateKind::Closure(def_id, substs),
"annotate_argument_and_return_for_borrow: assigned_to={:?} \ operands,
rvalue={:?}", ) = rvalue
assigned_to, rvalue {
); for operand in operands {
// Check if our `target` was captured by a closure. let assigned_from = match operand {
if let Rvalue::Aggregate( Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
box AggregateKind::Closure(def_id, substs), assigned_from
operands, }
) = rvalue _ => continue,
{ };
for operand in operands { debug!(
let assigned_from = match operand { "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,
};
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_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;
}
// 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) => { Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
assigned_from assigned_from
} }
_ => continue, _ => continue,
}; },
debug!( _ => continue,
"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 operand. // Find the local from the rvalue.
let assigned_from_local = match assigned_from.local_or_deref_local() { let assigned_from_local = match assigned_from.local_or_deref_local() {
Some(local) => local, Some(local) => local,
None => continue, None => continue,
}; };
debug!(
"annotate_argument_and_return_for_borrow: \
assigned_from_local={:?}",
assigned_from_local,
);
if assigned_from_local != target { // Check if our local matches the target - if so, we've assigned our
continue; // borrow to a new place.
} 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_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 // If we assigned our `target` into a new place, then we should
// statement. // check if it was the return place.
continue; 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;
} }
// 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,
};
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,
);
// 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 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 target, terminator
); );
if let TerminatorKind::Call { if let TerminatorKind::Call {
destination: Some((Place { destination: Some((place, _)),
base: PlaceBase::Local(assigned_to),
projection: box [],
}, _)),
args, args,
.. ..
} = &terminator.kind } = &terminator.kind
{ {
debug!( if let Some(assigned_to) = place.as_local() {
"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,
};
debug!( debug!(
"annotate_argument_and_return_for_borrow: assigned_from={:?}", "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
assigned_from, assigned_to, args
); );
for operand in args {
if let Some(assigned_from_local) = assigned_from.local_or_deref_local() { let assigned_from = match operand {
Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
assigned_from
}
_ => continue,
};
debug!( debug!(
"annotate_argument_and_return_for_borrow: assigned_from_local={:?}", "annotate_argument_and_return_for_borrow: assigned_from={:?}",
assigned_from_local, assigned_from,
); );
if *assigned_to == mir::RETURN_PLACE && assigned_from_local == target { if let Some(assigned_from_local) = assigned_from.local_or_deref_local() {
return annotated_closure.or_else(fallback); 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);
}
} }
} }
} }

View file

@ -838,12 +838,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
.get(location.statement_index) .get(location.statement_index)
{ {
Some(&Statement { Some(&Statement {
kind: StatementKind::Assign(box(Place { kind: StatementKind::Assign(box(ref place, _)),
base: PlaceBase::Local(local),
projection: box [],
}, _)),
.. ..
}) => local, }) => {
if let Some(local) = place.as_local() {
local
} else {
return OtherUse(use_span);
}
}
_ => return OtherUse(use_span), _ => return OtherUse(use_span),
}; };

View file

@ -1133,15 +1133,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// Special case: you can assign a immutable local variable // Special case: you can assign a immutable local variable
// (e.g., `x = ...`) so long as it has never been initialized // (e.g., `x = ...`) so long as it has never been initialized
// before (at this point in the flow). // before (at this point in the flow).
if let Place { if let Some(local) = place_span.0.as_local() {
base: PlaceBase::Local(local), if let Mutability::Not = self.body.local_decls[local].mutability {
projection: box [],
} = place_span.0 {
if let Mutability::Not = self.body.local_decls[*local].mutability {
// check for reassignments to immutable local variables // check for reassignments to immutable local variables
self.check_if_reassignment_to_immutable_state( self.check_if_reassignment_to_immutable_state(
location, location,
*local, local,
place_span, place_span,
flow_state, flow_state,
); );
@ -1288,59 +1285,57 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// captures of a closure are copied/moved directly // captures of a closure are copied/moved directly
// when generating MIR. // when generating MIR.
match *operand { match *operand {
Operand::Move(Place { Operand::Move(ref place) | Operand::Copy(ref place) => {
base: PlaceBase::Local(local), match place.as_local() {
projection: box [], Some(local) if self.body.local_decls[local].is_user_variable.is_none() => {
}) | if self.body.local_decls[local].ty.is_mutable_ptr() {
Operand::Copy(Place { // The variable will be marked as mutable by the borrow.
base: PlaceBase::Local(local), return;
projection: box [], }
}) if self.body.local_decls[local].is_user_variable.is_none() => { // This is an edge case where we have a `move` closure
if self.body.local_decls[local].ty.is_mutable_ptr() { // inside a non-move closure, and the inner closure
// The variable will be marked as mutable by the borrow. // contains a mutation:
return; //
// 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),
} }
// 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) => {
propagate_closure_used_mut_place(self, place);
} }
Operand::Constant(..) => {} Operand::Constant(..) => {}
} }
@ -1702,7 +1697,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
debug!("check_if_assigned_path_is_moved place: {:?}", place); debug!("check_if_assigned_path_is_moved place: {:?}", place);
// None case => assigning to `x` does not require `x` be initialized. // 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 { while let [proj_base @ .., elem] = cursor {
cursor = proj_base; cursor = proj_base;

View file

@ -89,45 +89,41 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// If that ever stops being the case, then the ever initialized // If that ever stops being the case, then the ever initialized
// flow could be used. // flow could be used.
if let Some(StatementKind::Assign( if let Some(StatementKind::Assign(
box( box(place, Rvalue::Use(Operand::Move(move_from)))
Place {
base: PlaceBase::Local(local),
projection: box [],
},
Rvalue::Use(Operand::Move(move_from))
)
)) = self.body.basic_blocks()[location.block] )) = self.body.basic_blocks()[location.block]
.statements .statements
.get(location.statement_index) .get(location.statement_index)
.map(|stmt| &stmt.kind) .map(|stmt| &stmt.kind)
{ {
let local_decl = &self.body.local_decls[*local]; if let Some(local) = place.as_local() {
// opt_match_place is the let local_decl = &self.body.local_decls[local];
// match_span is the span of the expression being matched on // opt_match_place is the
// match *x.y { ... } match_place is Some(*x.y) // match_span is the span of the expression being matched on
// ^^^^ match_span is the span of *x.y // 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 // opt_match_place is None for let [mut] x = ... statements,
if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { // whether or not the right-hand side is a place expression
opt_match_place: Some((ref opt_match_place, match_span)), if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
binding_mode: _, opt_match_place: Some((ref opt_match_place, match_span)),
opt_ty_info: _, binding_mode: _,
pat_span: _, opt_ty_info: _,
}))) = local_decl.is_user_variable pat_span: _,
{ }))) = local_decl.is_user_variable
let stmt_source_info = self.body.source_info(location); {
self.append_binding_error( let stmt_source_info = self.body.source_info(location);
grouped_errors, self.append_binding_error(
kind, grouped_errors,
original_path, kind,
move_from, original_path,
*local, move_from,
opt_match_place, local,
match_span, opt_match_place,
stmt_source_info.span, match_span,
); stmt_source_info.span,
return; );
return;
}
} }
} }
@ -307,11 +303,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All) let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All)
.find_map(|p| self.is_upvar_field_projection(p)); .find_map(|p| self.is_upvar_field_projection(p));
let deref_base = match &deref_target_place.projection { let deref_base = match deref_target_place.projection.as_ref() {
box [proj_base @ .., ProjectionElem::Deref] => { &[ref proj_base @ .., ProjectionElem::Deref] => {
PlaceRef { PlaceRef {
base: &deref_target_place.base, base: &deref_target_place.base,
projection: proj_base, projection: &proj_base,
} }
} }
_ => bug!("deref_target_place is not a deref projection"), _ => bug!("deref_target_place is not a deref projection"),

View file

@ -49,10 +49,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
projection: [], projection: [],
} => { } => {
item_msg = format!("`{}`", access_place_desc.unwrap()); item_msg = format!("`{}`", access_place_desc.unwrap());
if let Place { if access_place.as_local().is_some() {
base: PlaceBase::Local(_),
projection: box [],
} = access_place {
reason = ", as it is not declared as mutable".to_string(); reason = ", as it is not declared as mutable".to_string();
} else { } else {
let name = self.body.local_decls[*local] let name = self.body.local_decls[*local]
@ -153,10 +150,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}), }),
projection: [], projection: [],
} => { } => {
if let Place { if let PlaceRef {
base: PlaceBase::Static(_), base: &PlaceBase::Static(_),
projection: box [], projection: &[],
} = access_place { } = access_place.as_ref() {
item_msg = format!("immutable static item `{}`", access_place_desc.unwrap()); item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
reason = String::new(); reason = String::new();
} else { } else {

View file

@ -8,8 +8,8 @@ use rustc::infer::InferCtxt;
use rustc::mir::visit::TyContext; use rustc::mir::visit::TyContext;
use rustc::mir::visit::Visitor; use rustc::mir::visit::Visitor;
use rustc::mir::{ use rustc::mir::{
BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, ProjectionElem, Rvalue, BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, PlaceRef, ProjectionElem,
SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection, Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
}; };
use rustc::ty::fold::TypeFoldable; use rustc::ty::fold::TypeFoldable;
use rustc::ty::{self, RegionVid, Ty}; 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 // - if it's a deeper projection, we have to filter which
// of the borrows are killed: the ones whose `borrowed_place` // of the borrows are killed: the ones whose `borrowed_place`
// conflicts with the `place`. // conflicts with the `place`.
match place { match place.as_ref() {
Place { PlaceRef {
base: PlaceBase::Local(local), base: &PlaceBase::Local(local),
projection: box [], projection: &[],
} | } |
Place { PlaceRef {
base: PlaceBase::Local(local), base: &PlaceBase::Local(local),
projection: box [ProjectionElem::Deref], projection: &[ProjectionElem::Deref],
} => { } => {
debug!( debug!(
"Recording `killed` facts for borrows of local={:?} at location={:?}", "Recording `killed` facts for borrows of local={:?} at location={:?}",
@ -229,21 +229,21 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
all_facts, all_facts,
self.borrow_set, self.borrow_set,
self.location_table, self.location_table,
local, &local,
location, location,
); );
} }
Place { PlaceRef {
base: PlaceBase::Static(_), base: &PlaceBase::Static(_),
.. ..
} => { } => {
// Ignore kills of static or static mut variables. // Ignore kills of static or static mut variables.
} }
Place { PlaceRef {
base: PlaceBase::Local(local), base: &PlaceBase::Local(local),
projection: box [.., _], projection: &[.., _],
} => { } => {
// Kill conflicting borrows of the innermost local. // Kill conflicting borrows of the innermost local.
debug!( debug!(
@ -252,7 +252,7 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
local, location 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 { for &borrow_index in borrow_indices {
let places_conflict = places_conflict::places_conflict( let places_conflict = places_conflict::places_conflict(
self.infcx.tcx, self.infcx.tcx,

View file

@ -6,8 +6,8 @@ use crate::borrow_check::nll::region_infer::{Cause, RegionName};
use crate::borrow_check::nll::ConstraintDescription; use crate::borrow_check::nll::ConstraintDescription;
use crate::borrow_check::{MirBorrowckCtxt, WriteKind}; use crate::borrow_check::{MirBorrowckCtxt, WriteKind};
use rustc::mir::{ use rustc::mir::{
CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, PlaceBase, CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, Rvalue,
Rvalue, Statement, StatementKind, TerminatorKind, Statement, StatementKind, TerminatorKind,
}; };
use rustc::ty::{self, TyCtxt}; use rustc::ty::{self, TyCtxt};
use rustc::ty::adjustment::{PointerCast}; use rustc::ty::adjustment::{PointerCast};
@ -273,12 +273,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let mut should_note_order = false; let mut should_note_order = false;
if body.local_decls[local].name.is_some() { if body.local_decls[local].name.is_some() {
if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place { if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
if let Place { if let Some(borrowed_local) = place.as_local() {
base: PlaceBase::Local(borrowed_local), if body.local_decls[borrowed_local].name.is_some()
projection: box [], && local != borrowed_local
} = place {
if body.local_decls[*borrowed_local].name.is_some()
&& local != *borrowed_local
{ {
should_note_order = true; 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. // Just point to the function, to reduce the chance of overlapping spans.
let function_span = match func { let function_span = match func {
Operand::Constant(c) => c.span, Operand::Constant(c) => c.span,
Operand::Copy(Place { Operand::Copy(place) |
base: PlaceBase::Local(l), Operand::Move(place) => {
projection: box [], if let Some(l) = place.as_local() {
}) | let local_decl = &self.body.local_decls[l];
Operand::Move(Place { if local_decl.name.is_none() {
base: PlaceBase::Local(l), local_decl.source_info.span
projection: box [], } else {
}) => { span
let local_decl = &self.body.local_decls[*l]; }
if local_decl.name.is_none() {
local_decl.source_info.span
} else { } else {
span span
} }
} }
_ => span,
}; };
return (LaterUseKind::Call, function_span); return (LaterUseKind::Call, function_span);
} else { } else {
@ -542,14 +536,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// it which simplifies the termination logic. // it which simplifies the termination logic.
let mut queue = vec![location]; let mut queue = vec![location];
let mut target = if let Some(&Statement { let mut target = if let Some(&Statement {
kind: StatementKind::Assign(box(Place { kind: StatementKind::Assign(box(ref place, _)),
base: PlaceBase::Local(local),
projection: box [],
}, _)),
.. ..
}) = stmt }) = stmt {
{ if let Some(local) = place.as_local() {
local local
} else {
return false;
}
} else { } else {
return false; 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 // 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. // update the place that we're looking for to that new place.
Rvalue::Use(operand) => match operand { Rvalue::Use(operand) => match operand {
Operand::Copy(Place { Operand::Copy(place)
base: PlaceBase::Local(from), | Operand::Move(place) => {
projection: box [], if let Some(from) = place.as_local() {
}) if from == target {
| Operand::Move(Place { target = into;
base: PlaceBase::Local(from), }
projection: box [], }
})
if *from == target =>
{
target = into;
} }
_ => {} _ => {}
}, },
@ -601,28 +591,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Rvalue::Cast( Rvalue::Cast(
CastKind::Pointer(PointerCast::Unsize), operand, ty CastKind::Pointer(PointerCast::Unsize), operand, ty
) => match operand { ) => match operand {
Operand::Copy(Place { Operand::Copy(place)
base: PlaceBase::Local(from), | Operand::Move(place) => {
projection: box [], if let Some(from) = place.as_local() {
}) if from == target {
| Operand::Move(Place { debug!("was_captured_by_trait_object: ty={:?}", ty);
base: PlaceBase::Local(from), // Check the type for a trait object.
projection: box [], return match ty.kind {
}) // `&dyn Trait`
if *from == target => ty::Ref(_, ty, _) if ty.is_trait() => true,
{ // `Box<dyn Trait>`
debug!("was_captured_by_trait_object: ty={:?}", ty); _ if ty.is_box() && ty.boxed_ty().is_trait() => true,
// Check the type for a trait object. // `dyn Trait`
return match ty.kind { _ if ty.is_trait() => true,
// `&dyn Trait` // Anything else.
ty::Ref(_, ty, _) if ty.is_trait() => true, _ => false,
// `Box<dyn Trait>` };
_ if ty.is_box() && ty.boxed_ty().is_trait() => true, }
// `dyn Trait` }
_ if ty.is_trait() => true, return false;
// 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); debug!("was_captured_by_trait_object: terminator={:?}", terminator);
if let TerminatorKind::Call { if let TerminatorKind::Call {
destination: Some((Place { destination: Some((place, block)),
base: PlaceBase::Local(dest),
projection: box [],
}, block)),
args, args,
.. ..
} = &terminator.kind } = &terminator.kind {
{ if let Some(dest) = place.as_local() {
debug!( debug!(
"was_captured_by_trait_object: target={:?} dest={:?} args={:?}", "was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
target, dest, args target, dest, args
); );
// Check if one of the arguments to this function is the target place. // Check if one of the arguments to this function is the target place.
let found_target = args.iter().any(|arg| { let found_target = args.iter().any(|arg| {
if let Operand::Move(Place { if let Operand::Move(place) = arg {
base: PlaceBase::Local(potential), if let Some(potential) = place.as_local() {
projection: box [], potential == target
}) = arg { } else {
*potential == target false
} else { }
false } else {
} false
}); }
});
// If it is, follow this to the next block and update the target. // If it is, follow this to the next block and update the target.
if found_target { if found_target {
target = *dest; target = dest;
queue.push(block.start_location()); queue.push(block.start_location());
}
} }
} }
} }

View file

@ -1,5 +1,5 @@
use rustc::ty::subst::SubstsRef; 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::{Body, Location, PlaceElem, Promoted};
use rustc::mir::visit::{MutVisitor, TyContext}; use rustc::mir::visit::{MutVisitor, TyContext};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
@ -54,6 +54,10 @@ impl<'a, 'tcx> NLLVisitor<'a, 'tcx> {
} }
impl<'a, 'tcx> MutVisitor<'tcx> for 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) { fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
debug!("visit_ty(ty={:?}, ty_context={:?})", ty, ty_context); debug!("visit_ty(ty={:?}, ty_context={:?})", ty, ty_context);

View file

@ -480,13 +480,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
if place.projection.is_empty() { if place.projection.is_empty() {
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
let is_promoted = match place { let is_promoted = match place.as_ref() {
Place { PlaceRef {
base: PlaceBase::Static(box Static { base: &PlaceBase::Static(box Static {
kind: StaticKind::Promoted(..), kind: StaticKind::Promoted(..),
.. ..
}), }),
projection: box [], projection: &[],
} => true, } => true,
_ => false, _ => false,
}; };
@ -1366,11 +1366,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// they are not caused by the user, but rather artifacts // they are not caused by the user, but rather artifacts
// of lowering. Assignments to other sorts of places *are* interesting // of lowering. Assignments to other sorts of places *are* interesting
// though. // though.
let category = match *place { let category = match place.as_local() {
Place { Some(RETURN_PLACE) => if let BorrowCheckContext {
base: PlaceBase::Local(RETURN_PLACE),
projection: box [],
} => if let BorrowCheckContext {
universal_regions: universal_regions:
UniversalRegions { UniversalRegions {
defining_ty: DefiningTy::Const(def_id, _), defining_ty: DefiningTy::Const(def_id, _),
@ -1386,10 +1383,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
} else { } else {
ConstraintCategory::Return ConstraintCategory::Return
}, },
Place { Some(l) if !body.local_decls[l].is_user_variable.is_some() => {
base: PlaceBase::Local(l),
projection: box [],
} if !body.local_decls[l].is_user_variable.is_some() => {
ConstraintCategory::Boring ConstraintCategory::Boring
} }
_ => ConstraintCategory::Assignment, _ => ConstraintCategory::Assignment,
@ -1675,11 +1669,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Some((ref dest, _target_block)) => { Some((ref dest, _target_block)) => {
let dest_ty = dest.ty(body, tcx).ty; let dest_ty = dest.ty(body, tcx).ty;
let dest_ty = self.normalize(dest_ty, term_location); let dest_ty = self.normalize(dest_ty, term_location);
let category = match *dest { let category = match dest.as_local() {
Place { Some(RETURN_PLACE) => {
base: PlaceBase::Local(RETURN_PLACE),
projection: box [],
} => {
if let BorrowCheckContext { if let BorrowCheckContext {
universal_regions: universal_regions:
UniversalRegions { UniversalRegions {
@ -1698,10 +1689,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ConstraintCategory::Return ConstraintCategory::Return
} }
} }
Place { Some(l) if !body.local_decls[l].is_user_variable.is_some() => {
base: PlaceBase::Local(l),
projection: box [],
} if !body.local_decls[l].is_user_variable.is_some() => {
ConstraintCategory::Boring ConstraintCategory::Boring
} }
_ => ConstraintCategory::Assignment, _ => ConstraintCategory::Assignment,
@ -2432,7 +2420,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
location, borrow_region, borrowed_place 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 { while let [proj_base @ .., elem] = cursor {
cursor = proj_base; cursor = proj_base;

View file

@ -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 // 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. // it's so common that it's a speed win to check for it first.
if let Place { if let Some(l1) = borrow_place.as_local() {
base: PlaceBase::Local(l1), if let Some(l2) = access_place.as_local() {
projection: box [],
} = borrow_place {
if let PlaceRef {
base: PlaceBase::Local(l2),
projection: [],
} = access_place {
return l1 == l2; return l1 == l2;
} }
} }

View file

@ -1,7 +1,5 @@
use rustc::mir::visit::{PlaceContext, Visitor}; use rustc::mir::visit::{PlaceContext, Visitor};
use rustc::mir::{ use rustc::mir::{Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind};
Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind
};
use rustc_data_structures::fx::FxHashSet; 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", "assignment of {:?} to {:?}, adding {:?} to used mutable set",
path.place, local, path.place path.place, local, path.place
); );
if let Place { if let Some(user_local) = path.place.as_local() {
base: PlaceBase::Local(user_local),
projection: box [],
} = path.place {
self.mbcx.used_mut.insert(user_local); self.mbcx.used_mut.insert(user_local);
} }
} }

View file

@ -6,7 +6,7 @@ use crate::build::{BlockAnd, BlockAndExtension, Builder};
use crate::hair::*; use crate::hair::*;
use rustc::mir::interpret::{PanicInfo::BoundsCheck}; use rustc::mir::interpret::{PanicInfo::BoundsCheck};
use rustc::mir::*; use rustc::mir::*;
use rustc::ty::{CanonicalUserTypeAnnotation, Ty, Variance}; use rustc::ty::{CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance};
use rustc_index::vec::Idx; use rustc_index::vec::Idx;
@ -23,10 +23,10 @@ struct PlaceBuilder<'tcx> {
} }
impl PlaceBuilder<'tcx> { impl PlaceBuilder<'tcx> {
fn into_place(self) -> Place<'tcx> { fn into_place(self, tcx: TyCtxt<'tcx>) -> Place<'tcx> {
Place { Place {
base: self.base, 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>>, M: Mirror<'tcx, Output = Expr<'tcx>>,
{ {
let place_builder = unpack!(block = self.as_place_builder(block, expr)); 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 /// 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>>, M: Mirror<'tcx, Output = Expr<'tcx>>,
{ {
let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr)); 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 /// 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, Mutability::Not,
)); ));
let slice = place_builder.clone().into_place(); let slice = place_builder.clone().into_place(this.hir.tcx());
// bounds check: // bounds check:
let (len, lt) = ( let (len, lt) = (
this.temp(usize_ty.clone(), expr_span), 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( this.cfg.push(
block, block,
Statement { Statement {

View file

@ -139,7 +139,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// initialize the box contents: // initialize the box contents:
unpack!( unpack!(
block = this.into( block = this.into(
&Place::from(result).deref(), &this.hir.tcx().mk_place_deref(Place::from(result)),
block, value block, value
) )
); );
@ -296,8 +296,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
.zip(field_types.into_iter()) .zip(field_types.into_iter())
.map(|(n, ty)| match fields_map.get(&n) { .map(|(n, ty)| match fields_map.get(&n) {
Some(v) => v.clone(), Some(v) => v.clone(),
None => this.consume_by_copy_or_move(base.clone().field(n, ty)), None => this.consume_by_copy_or_move(this.hir.tcx().mk_place_field(
}).collect() base.clone(),
n,
ty,
)),
})
.collect()
} else { } else {
field_names field_names
.iter() .iter()
@ -397,8 +402,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let val_fld = Field::new(0); let val_fld = Field::new(0);
let of_fld = Field::new(1); let of_fld = Field::new(1);
let val = result_value.clone().field(val_fld, ty); let tcx = self.hir.tcx();
let of = result_value.field(of_fld, bool_ty); 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); 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 arg_place = unpack!(block = this.as_place(block, arg));
let mutability = match arg_place { let mutability = match arg_place.as_ref() {
Place { PlaceRef {
base: PlaceBase::Local(local), base: &PlaceBase::Local(local),
projection: box [], projection: &[],
} => this.local_decls[local].mutability, } => this.local_decls[local].mutability,
Place { PlaceRef {
base: PlaceBase::Local(local), base: &PlaceBase::Local(local),
projection: box [ProjectionElem::Deref], projection: &[ProjectionElem::Deref],
} => { } => {
debug_assert!( debug_assert!(
this.local_decls[local].is_ref_for_guard(), this.local_decls[local].is_ref_for_guard(),
@ -511,13 +517,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
); );
this.local_decls[local].mutability this.local_decls[local].mutability
} }
Place { PlaceRef {
ref base, ref base,
projection: box [ref proj_base @ .., ProjectionElem::Field(upvar_index, _)], projection: &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _)],
} }
| Place { | PlaceRef {
ref base, ref base,
projection: box [ projection: &[
ref proj_base @ .., ref proj_base @ ..,
ProjectionElem::Field(upvar_index, _), ProjectionElem::Field(upvar_index, _),
ProjectionElem::Deref ProjectionElem::Deref

View file

@ -235,7 +235,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}); });
let ptr_temp = Place::from(ptr_temp); let ptr_temp = Place::from(ptr_temp);
let block = unpack!(this.into(&ptr_temp, block, ptr)); 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 { } else {
let args: Vec<_> = args let args: Vec<_> = args
.into_iter() .into_iter()

View file

@ -948,7 +948,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fake_borrows.insert(Place { fake_borrows.insert(Place {
base: source.base.clone(), 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. // Insert a Shallow borrow of the prefixes of any fake borrows.
for place in 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 { while let [proj_base @ .., elem] = cursor {
cursor = proj_base; cursor = proj_base;
@ -1488,7 +1488,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
BorrowKind::Shallow, BorrowKind::Shallow,
Place { Place {
base: place.base.clone(), base: place.base.clone(),
projection: place.projection.to_vec().into_boxed_slice(), projection: tcx.intern_place_elems(place.projection),
}, },
); );
self.cfg.push_assign( self.cfg.push_assign(

View file

@ -166,7 +166,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
}); });
if irrefutable { 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)); candidate.match_pairs.extend(self.field_match_pairs(place, subpatterns));
Ok(()) Ok(())
} else { } else {
@ -191,7 +191,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
PatKind::Deref { ref subpattern } => { 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)); candidate.match_pairs.push(MatchPair::new(place, subpattern));
Ok(()) Ok(())
} }

View file

@ -743,22 +743,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
candidate: &mut Candidate<'pat, 'tcx>, candidate: &mut Candidate<'pat, 'tcx>,
) { ) {
let match_pair = candidate.match_pairs.remove(match_pair_index); 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)`, // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
// we want to create a set of derived match-patterns like // we want to create a set of derived match-patterns like
// `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`. // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
let elem = ProjectionElem::Downcast( let elem = ProjectionElem::Downcast(
Some(adt_def.variants[variant_index].ident.name), variant_index); Some(adt_def.variants[variant_index].ident.name), variant_index);
let downcast_place = match_pair.place.elem(elem); // `(x as Variant)` let downcast_place = tcx.mk_place_elem(match_pair.place, elem); // `(x as Variant)`
let consequent_match_pairs = let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
subpatterns.iter() // e.g., `(x as Variant).0`
.map(|subpattern| { let place =
// e.g., `(x as Variant).0` tcx.mk_place_field(downcast_place.clone(), subpattern.field, subpattern.pattern.ty);
let place = downcast_place.clone().field(subpattern.field, // e.g., `(x as Variant).0 @ P1`
subpattern.pattern.ty); MatchPair::new(place, &subpattern.pattern)
// e.g., `(x as Variant).0 @ P1` });
MatchPair::new(place, &subpattern.pattern)
});
candidate.match_pairs.extend(consequent_match_pairs); candidate.match_pairs.extend(consequent_match_pairs);
} }

View file

@ -6,17 +6,22 @@ use std::u32;
use std::convert::TryInto; use std::convert::TryInto;
impl<'a, 'tcx> Builder<'a, 'tcx> { impl<'a, 'tcx> Builder<'a, 'tcx> {
pub fn field_match_pairs<'pat>(&mut self, pub fn field_match_pairs<'pat>(
place: Place<'tcx>, &mut self,
subpatterns: &'pat [FieldPat<'tcx>]) place: Place<'tcx>,
-> Vec<MatchPair<'pat, 'tcx>> { subpatterns: &'pat [FieldPat<'tcx>],
subpatterns.iter() ) -> Vec<MatchPair<'pat, 'tcx>> {
.map(|fieldpat| { subpatterns
let place = place.clone().field(fieldpat.field, .iter()
fieldpat.pattern.ty); .map(|fieldpat| {
MatchPair::new(place, &fieldpat.pattern) let place = self.hir.tcx().mk_place_field(
}) place.clone(),
.collect() fieldpat.field,
fieldpat.pattern.ty,
);
MatchPair::new(place, &fieldpat.pattern)
})
.collect()
} }
pub fn prefix_slice_suffix<'pat>(&mut self, pub fn prefix_slice_suffix<'pat>(&mut self,
@ -27,6 +32,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
suffix: &'pat [Pat<'tcx>]) { suffix: &'pat [Pat<'tcx>]) {
let min_length = prefix.len() + suffix.len(); let min_length = prefix.len() + suffix.len();
let min_length = min_length.try_into().unwrap(); let min_length = min_length.try_into().unwrap();
let tcx = self.hir.tcx();
match_pairs.extend( match_pairs.extend(
prefix.iter() prefix.iter()
@ -37,13 +43,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
min_length, min_length,
from_end: false, from_end: false,
}; };
let place = place.clone().elem(elem); let place = tcx.mk_place_elem(place.clone(), elem);
MatchPair::new(place, subpattern) MatchPair::new(place, subpattern)
}) })
); );
if let Some(subslice_pat) = opt_slice { 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, from: prefix.len() as u32,
to: suffix.len() as u32 to: suffix.len() as u32
}); });
@ -60,7 +66,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
min_length, min_length,
from_end: true, from_end: true,
}; };
let place = place.clone().elem(elem); let place = tcx.mk_place_elem(place.clone(), elem);
MatchPair::new(place, subpattern) MatchPair::new(place, subpattern)
}) })
); );

View file

@ -926,46 +926,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// If constants and statics, we don't generate StorageLive for this // If constants and statics, we don't generate StorageLive for this
// temporary, so don't try to generate StorageDead for it either. // temporary, so don't try to generate StorageDead for it either.
_ if self.local_scope().is_none() => (), _ if self.local_scope().is_none() => (),
Operand::Copy(Place { Operand::Copy(place)
base: PlaceBase::Local(cond_temp), | Operand::Move(place) => {
projection: box [], if let Some(cond_temp) = place.as_local() {
}) // Manually drop the condition on both branches.
| Operand::Move(Place { let top_scope = self.scopes.scopes.last_mut().unwrap();
base: PlaceBase::Local(cond_temp), let top_drop_data = top_scope.drops.pop().unwrap();
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 { match top_drop_data.kind {
DropKind::Value { .. } => { DropKind::Value { .. } => {
bug!("Drop scheduled on top of condition variable") bug!("Drop scheduled on top of condition variable")
} }
DropKind::Storage => { DropKind::Storage => {
let source_info = top_scope.source_info(top_drop_data.span); let source_info = top_scope.source_info(top_drop_data.span);
let local = top_drop_data.local; let local = top_drop_data.local;
assert_eq!(local, cond_temp, "Drop scheduled on top of condition"); assert_eq!(local, cond_temp, "Drop scheduled on top of condition");
self.cfg.push( self.cfg.push(
true_block, true_block,
Statement { Statement {
source_info, source_info,
kind: StatementKind::StorageDead(local) kind: StatementKind::StorageDead(local)
}, },
); );
self.cfg.push( self.cfg.push(
false_block, false_block,
Statement { Statement {
source_info, source_info,
kind: StatementKind::StorageDead(local) kind: StatementKind::StorageDead(local)
}, },
); );
}
} }
top_scope.invalidate_cache(true, self.is_generator, true);
} else {
bug!("Expected as_local_operand to produce a temporary");
} }
top_scope.invalidate_cache(true, self.is_generator, true);
} }
_ => bug!("Expected as_local_operand to produce a temporary"),
} }
(true_block, false_block) (true_block, false_block)

View file

@ -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 // Since `propagate_call_unwind` doesn't exist, we have to kill the
// destination here, and then gen it again in `propagate_call_return`. // destination here, and then gen it again in `propagate_call_return`.
if let TerminatorKind::Call { if let TerminatorKind::Call {
destination: Some((Place { base: PlaceBase::Local(local), projection: box [] }, _)), destination: Some((ref place, _)),
.. ..
} = self.body[loc.block].terminator().kind { } = 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); self.check_for_move(sets, loc);
} }

View file

@ -114,7 +114,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
BorrowedContent { BorrowedContent {
target_place: Place { target_place: Place {
base: place.base.clone(), 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), Some(base),
Place { Place {
base: place.base.clone(), base: place.base.clone(),
projection: proj.to_vec().into_boxed_slice(), projection: tcx.intern_place_elems(proj),
}, },
); );
ent.insert(path); ent.insert(path);
@ -274,7 +274,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
// Box starts out uninitialized - need to create a separate // Box starts out uninitialized - need to create a separate
// move-path for the interior so it will be separate from // move-path for the interior so it will be separate from
// the exterior. // 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); self.gather_init(place.as_ref(), InitKind::Shallow);
} else { } else {
self.gather_init(place.as_ref(), InitKind::Deep); self.gather_init(place.as_ref(), InitKind::Deep);

View file

@ -327,7 +327,7 @@ impl<'tcx> MoveData<'tcx> {
pub fn base_local(&self, mut mpi: MovePathIndex) -> Option<Local> { pub fn base_local(&self, mut mpi: MovePathIndex) -> Option<Local> {
loop { loop {
let path = &self.move_paths[mpi]; 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); return Some(l);
} }
if let Some(parent) = path.parent { if let Some(parent) = path.parent {

View file

@ -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, &[ run_passes(tcx, &mut result, instance, None, MirPhase::Const, &[
&add_moves_for_packed_drops::AddMovesForPackedDrops, &add_moves_for_packed_drops::AddMovesForPackedDrops,
&no_landing_pads::NoLandingPads, &no_landing_pads::NoLandingPads::new(tcx),
&remove_noop_landing_pads::RemoveNoopLandingPads, &remove_noop_landing_pads::RemoveNoopLandingPads,
&simplify::SimplifyCfg::new("make_shim"), &simplify::SimplifyCfg::new("make_shim"),
&add_call_guards::CriticalCallEdges, &add_call_guards::CriticalCallEdges,
@ -231,7 +231,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
tcx, tcx,
param_env param_env
}; };
let dropee = dropee_ptr.deref(); let dropee = tcx.mk_place_deref(dropee_ptr);
let resume_block = elaborator.patch.resume_block(); let resume_block = elaborator.patch.resume_block();
elaborate_drops::elaborate_drop( elaborate_drops::elaborate_drop(
&mut elaborator, &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 is_copy = self_ty.is_copy_modulo_regions(tcx, param_env, builder.span);
let dest = Place::return_place(); 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 { match self_ty.kind {
_ if is_copy => builder.copy_shim(), _ if is_copy => builder.copy_shim(),
@ -415,7 +415,7 @@ impl CloneShimBuilder<'tcx> {
} }
fn copy_shim(&mut self) { 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( let ret_statement = self.make_statement(
StatementKind::Assign( StatementKind::Assign(
box( box(
@ -561,8 +561,8 @@ impl CloneShimBuilder<'tcx> {
// BB #2 // BB #2
// `dest[i] = Clone::clone(src[beg])`; // `dest[i] = Clone::clone(src[beg])`;
// Goto #3 if ok, #5 if unwinding happens. // Goto #3 if ok, #5 if unwinding happens.
let dest_field = dest.clone().index(beg); let dest_field = self.tcx.mk_place_index(dest.clone(), beg);
let src_field = src.index(beg); let src_field = self.tcx.mk_place_index(src, beg);
self.make_clone_call(dest_field, src_field, ty, BasicBlock::new(3), self.make_clone_call(dest_field, src_field, ty, BasicBlock::new(3),
BasicBlock::new(5)); BasicBlock::new(5));
@ -616,7 +616,7 @@ impl CloneShimBuilder<'tcx> {
// BB #7 (cleanup) // BB #7 (cleanup)
// `drop(dest[beg])`; // `drop(dest[beg])`;
self.block(vec![], TerminatorKind::Drop { self.block(vec![], TerminatorKind::Drop {
location: dest.index(beg), location: self.tcx.mk_place_index(dest, beg),
target: BasicBlock::new(8), target: BasicBlock::new(8),
unwind: None, unwind: None,
}, true); }, true);
@ -648,9 +648,9 @@ impl CloneShimBuilder<'tcx> {
let mut previous_field = None; let mut previous_field = None;
for (i, ity) in tys.enumerate() { for (i, ity) in tys.enumerate() {
let field = Field::new(i); 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 // #(2i + 1) is the cleanup block for the previous clone operation
let cleanup_block = self.block_index_offset(1); let cleanup_block = self.block_index_offset(1);
@ -721,14 +721,14 @@ fn build_call_shim<'tcx>(
let rcvr = match rcvr_adjustment { let rcvr = match rcvr_adjustment {
Adjustment::Identity => Operand::Move(rcvr_l), 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 => { Adjustment::DerefMove => {
// fn(Self, ...) -> fn(*mut Self, ...) // fn(Self, ...) -> fn(*mut Self, ...)
let arg_ty = local_decls[rcvr_arg].ty; let arg_ty = local_decls[rcvr_arg].ty;
debug_assert!(tcx.generics_of(def_id).has_self && arg_ty == tcx.types.self_param); 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); 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 => { Adjustment::RefMut => {
// let rcvr = &mut rcvr; // let rcvr = &mut rcvr;
@ -772,7 +772,7 @@ fn build_call_shim<'tcx>(
if let Some(untuple_args) = untuple_args { if let Some(untuple_args) = untuple_args {
args.extend(untuple_args.iter().enumerate().map(|(i, ity)| { args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
let arg_place = Place::from(Local::new(1+1)); 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 { } else {
args.extend((1..sig.inputs().len()).map(|i| { 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), AggregateKind::Adt(adt_def, variant_index, substs, None, None),
source_info, source_info,
tcx,
).collect(); ).collect();
let start_block = BasicBlockData { let start_block = BasicBlockData {

View file

@ -164,8 +164,8 @@ pub trait Qualif {
Rvalue::Ref(_, _, ref place) => { Rvalue::Ref(_, _, ref place) => {
// Special-case reborrows to be more like a copy of the reference. // Special-case reborrows to be more like a copy of the reference.
if let box [proj_base @ .., elem] = &place.projection { if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
if ProjectionElem::Deref == *elem { if ProjectionElem::Deref == elem {
let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty; let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty;
if let ty::Ref(..) = base_ty.kind { if let ty::Ref(..) = base_ty.kind {
return Self::in_place(cx, per_local, PlaceRef { return Self::in_place(cx, per_local, PlaceRef {

View file

@ -56,16 +56,16 @@ where
fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) { fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) {
debug_assert!(!place.is_indirect()); debug_assert!(!place.is_indirect());
match (value, place) { match (value, place.as_ref()) {
(true, mir::Place { base: mir::PlaceBase::Local(local), .. }) => { (true, mir::PlaceRef { base: &mir::PlaceBase::Local(local), .. }) => {
self.qualifs_per_local.insert(*local); self.qualifs_per_local.insert(local);
} }
// For now, we do not clear the qualif if a local is overwritten in full by // 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 // an unqualified rvalue (e.g. `y = 5`). This is to be consistent
// with aggregates where we overwrite all fields with assignments, which would not // with aggregates where we overwrite all fields with assignments, which would not
// get this feature. // 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); // 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 // If a local with no projections is moved from (e.g. `x` in `y = x`), record that
// it no longer needs to be dropped. // it no longer needs to be dropped.
if let mir::Operand::Move(mir::Place { if let mir::Operand::Move(place) = operand {
base: mir::PlaceBase::Local(local), if let Some(local) = place.as_local() {
projection: box [], self.qualifs_per_local.remove(local);
}) = *operand { }
self.qualifs_per_local.remove(local);
} }
} }

View file

@ -244,8 +244,8 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
if let Rvalue::Ref(_, kind, ref place) = *rvalue { if let Rvalue::Ref(_, kind, ref place) = *rvalue {
// Special-case reborrows to be more like a copy of a reference. // Special-case reborrows to be more like a copy of a reference.
let mut reborrow_place = None; let mut reborrow_place = None;
if let box [proj_base @ .., elem] = &place.projection { if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
if *elem == ProjectionElem::Deref { if elem == ProjectionElem::Deref {
let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty; let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
if let ty::Ref(..) = base_ty.kind { if let ty::Ref(..) = base_ty.kind {
reborrow_place = Some(proj_base); reborrow_place = Some(proj_base);
@ -376,12 +376,15 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
); );
if rvalue_has_mut_interior { 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 // 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 borrow, suppress this error and mark the result of this borrow as
// illegal as well. // illegal as well.
Place { base: PlaceBase::Local(borrowed_local), projection: box [] } Some(borrowed_local)
if self.derived_from_illegal_borrow.contains(borrowed_local) => true, if self.derived_from_illegal_borrow.contains(borrowed_local) =>
{
true
}
// Otherwise proceed normally: check the legality of a mutable borrow in this // Otherwise proceed normally: check the legality of a mutable borrow in this
// context. // 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 // FIXME: should we also clear `derived_from_illegal_borrow` when a local is
// assigned a new value? // assigned a new value?
if is_derived_from_illegal_borrow { 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); self.derived_from_illegal_borrow.insert(dest);
} }
} }
@ -571,10 +574,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
return; return;
} }
let needs_drop = if let Place { let needs_drop = if let Some(local) = dropped_place.as_local() {
base: PlaceBase::Local(local),
projection: box [],
} = *dropped_place {
// Use the span where the local was declared as the span of the drop error. // 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; err_span = self.body.local_decls[local].source_info.span;
self.qualifs.needs_drop.contains(local) self.qualifs.needs_drop.contains(local)

View file

@ -406,8 +406,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
place: &Place<'tcx>, place: &Place<'tcx>,
is_mut_use: bool, is_mut_use: bool,
) { ) {
let mut cursor = &*place.projection; let mut cursor = place.projection.as_ref();
while let [proj_base @ .., elem] = cursor { while let &[ref proj_base @ .., elem] = cursor {
cursor = proj_base; cursor = proj_base;
match elem { match elem {

View file

@ -24,16 +24,22 @@ use crate::transform::{MirPass, MirSource};
pub struct CleanupNonCodegenStatements; pub struct CleanupNonCodegenStatements;
pub struct DeleteNonCodegenStatements; pub struct DeleteNonCodegenStatements<'tcx> {
tcx: TyCtxt<'tcx>,
}
impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements { impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements {
fn run_pass(&self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) {
let mut delete = DeleteNonCodegenStatements; let mut delete = DeleteNonCodegenStatements { tcx };
delete.visit_body(body); 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, fn visit_statement(&mut self,
statement: &mut Statement<'tcx>, statement: &mut Statement<'tcx>,
location: Location) { location: Location) {

View file

@ -7,10 +7,9 @@ use std::cell::Cell;
use rustc::hir::def::DefKind; use rustc::hir::def::DefKind;
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::mir::{ use rustc::mir::{
AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue, AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue, Local, UnOp,
Local, UnOp, StatementKind, Statement, LocalKind, StatementKind, Statement, LocalKind, TerminatorKind, Terminator, ClearCrossCrate, SourceInfo,
TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp, BinOp, SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock,
SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock,
}; };
use rustc::mir::visit::{ use rustc::mir::visit::{
Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext, 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 // (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 // unknown data is uninitialized, so if e.g. a function argument is unsized
// and has a reference taken, we get an ICE. // and has a reference taken, we get an ICE.
Rvalue::Ref(_, _, Place { base: PlaceBase::Local(local), projection: box [] }) => { Rvalue::Ref(_, _, place_ref) => {
trace!("checking Ref({:?})", place); trace!("checking Ref({:?})", place_ref);
let alive =
if let LocalValue::Live(_) = self.ecx.frame().locals[*local].value {
true
} else {
false
};
if !alive { if let Some(local) = place_ref.as_local() {
trace!("skipping Ref({:?}) to uninitialized local", place); let alive =
return None; 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> { impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn visit_constant( fn visit_constant(
&mut self, &mut self,
constant: &mut Constant<'tcx>, constant: &mut Constant<'tcx>,
@ -706,10 +712,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
.ty(&self.local_decls, self.tcx) .ty(&self.local_decls, self.tcx)
.ty; .ty;
if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) { if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
if let Place { if let Some(local) = place.as_local() {
base: PlaceBase::Local(local),
projection: box [],
} = *place {
let source = statement.source_info; let source = statement.source_info;
if let Some(()) = self.const_prop(rval, place_layout, source, place) { if let Some(()) = self.const_prop(rval, place_layout, source, place) {
if self.can_const_prop[local] { if self.can_const_prop[local] {

View file

@ -19,9 +19,7 @@
//! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the //! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the
//! future. //! future.
use rustc::mir::{ use rustc::mir::{Constant, Local, LocalKind, Location, Place, Body, Operand, Rvalue, StatementKind};
Constant, Local, LocalKind, Location, Place, PlaceBase, Body, Operand, Rvalue, StatementKind
};
use rustc::mir::visit::MutVisitor; use rustc::mir::visit::MutVisitor;
use rustc::ty::TyCtxt; use rustc::ty::TyCtxt;
use crate::transform::{MirPass, MirSource}; use crate::transform::{MirPass, MirSource};
@ -92,28 +90,32 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
}; };
// That use of the source must be an assignment. // That use of the source must be an assignment.
match statement.kind { match &statement.kind {
StatementKind::Assign( StatementKind::Assign(box(place, Rvalue::Use(operand))) => {
box( if let Some(local) = place.as_local() {
Place { if local == dest_local {
base: PlaceBase::Local(local), let maybe_action = match operand {
projection: box [], Operand::Copy(ref src_place) |
}, Operand::Move(ref src_place) => {
Rvalue::Use(ref operand) Action::local_copy(&body, &def_use_analysis, src_place)
) }
) if local == dest_local => { Operand::Constant(ref src_constant) => {
let maybe_action = match *operand { Action::constant(src_constant)
Operand::Copy(ref src_place) | }
Operand::Move(ref src_place) => { };
Action::local_copy(&body, &def_use_analysis, src_place) 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
} }
Operand::Constant(ref src_constant) => { } else {
Action::constant(src_constant) debug!(" Can't copy-propagate local: source use is not an \
} assignment");
}; continue
match maybe_action {
Some(this_action) => action = this_action,
None => 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 // FIXME(pcwalton): Update the use-def chains to delete the instructions instead of
// regenerating the chains. // regenerating the chains.
break break
@ -148,31 +151,20 @@ fn eliminate_self_assignments(
for def in dest_use_info.defs_not_including_drop() { for def in dest_use_info.defs_not_including_drop() {
let location = def.location; let location = def.location;
if let Some(stmt) = body[location.block].statements.get(location.statement_index) { if let Some(stmt) = body[location.block].statements.get(location.statement_index) {
match stmt.kind { match &stmt.kind {
StatementKind::Assign( StatementKind::Assign(box (place, Rvalue::Use(Operand::Copy(src_place))))
box( | StatementKind::Assign(box (place, Rvalue::Use(Operand::Move(src_place)))) => {
Place { if let (Some(local), Some(src_local)) =
base: PlaceBase::Local(local), (place.as_local(), src_place.as_local())
projection: box [], {
}, if local == dest_local && dest_local == src_local {
Rvalue::Use(Operand::Copy(Place { } else {
base: PlaceBase::Local(src_local), continue;
projection: box [], }
})), } else {
) continue;
) | }
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 => {}
_ => { _ => {
continue; continue;
} }
@ -198,10 +190,7 @@ impl<'tcx> Action<'tcx> {
fn local_copy(body: &Body<'tcx>, def_use_analysis: &DefUseAnalysis, src_place: &Place<'tcx>) fn local_copy(body: &Body<'tcx>, def_use_analysis: &DefUseAnalysis, src_place: &Place<'tcx>)
-> Option<Action<'tcx>> { -> Option<Action<'tcx>> {
// The source must be a local. // The source must be a local.
let src_local = if let Place { let src_local = if let Some(local) = src_place.as_local() {
base: PlaceBase::Local(local),
projection: box [],
} = *src_place {
local local
} else { } else {
debug!(" Can't copy-propagate local: source is not a local"); debug!(" Can't copy-propagate local: source is not a local");
@ -256,7 +245,8 @@ impl<'tcx> Action<'tcx> {
body: &mut Body<'tcx>, body: &mut Body<'tcx>,
def_use_analysis: &DefUseAnalysis, def_use_analysis: &DefUseAnalysis,
dest_local: Local, dest_local: Local,
location: Location) location: Location,
tcx: TyCtxt<'tcx>)
-> bool { -> bool {
match self { match self {
Action::PropagateLocalCopy(src_local) => { Action::PropagateLocalCopy(src_local) => {
@ -280,7 +270,7 @@ impl<'tcx> Action<'tcx> {
} }
// Replace all uses of the destination local with the source local. // 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. // Finally, zap the now-useless assignment instruction.
debug!(" Deleting assignment"); debug!(" Deleting assignment");
@ -304,7 +294,8 @@ impl<'tcx> Action<'tcx> {
// Replace all uses of the destination local with the constant. // Replace all uses of the destination local with the constant.
let mut visitor = ConstantPropagationVisitor::new(dest_local, let mut visitor = ConstantPropagationVisitor::new(dest_local,
src_constant); src_constant,
tcx);
for dest_place_use in &dest_local_info.defs_and_uses { for dest_place_use in &dest_local_info.defs_and_uses {
visitor.visit_location(body, dest_place_use.location) visitor.visit_location(body, dest_place_use.location)
} }
@ -336,33 +327,42 @@ impl<'tcx> Action<'tcx> {
struct ConstantPropagationVisitor<'tcx> { struct ConstantPropagationVisitor<'tcx> {
dest_local: Local, dest_local: Local,
constant: Constant<'tcx>, constant: Constant<'tcx>,
tcx: TyCtxt<'tcx>,
uses_replaced: usize, uses_replaced: usize,
} }
impl<'tcx> ConstantPropagationVisitor<'tcx> { 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<'tcx> {
ConstantPropagationVisitor { ConstantPropagationVisitor {
dest_local, dest_local,
constant, constant,
tcx,
uses_replaced: 0, uses_replaced: 0,
} }
} }
} }
impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> { 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) { fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
self.super_operand(operand, location); self.super_operand(operand, location);
match *operand { match operand {
Operand::Copy(Place { Operand::Copy(place) |
base: PlaceBase::Local(local), Operand::Move(place) => {
projection: box [], if let Some(local) = place.as_local() {
}) | if local == self.dest_local {
Operand::Move(Place { } else {
base: PlaceBase::Local(local), return;
projection: box [], }
}) if local == self.dest_local => {} } else {
return;
}
}
_ => return, _ => return,
} }

View file

@ -45,6 +45,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator {
}), }),
*kind, *kind,
source_info, source_info,
tcx,
)) ))
}); });
} }

View file

@ -23,6 +23,10 @@ impl EraseRegionsVisitor<'tcx> {
} }
impl MutVisitor<'tcx> for 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) { fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
*ty = self.tcx.erase_regions(ty); *ty = self.tcx.erase_regions(ty);
} }

View file

@ -74,12 +74,17 @@ use crate::util::liveness;
pub struct StateTransform; pub struct StateTransform;
struct RenameLocalVisitor { struct RenameLocalVisitor<'tcx> {
from: Local, from: Local,
to: 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, fn visit_local(&mut self,
local: &mut Local, local: &mut Local,
_: PlaceContext, _: 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, fn visit_local(&mut self,
local: &mut Local, local: &mut Local,
_: PlaceContext, _: PlaceContext,
@ -119,8 +130,8 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
if place.base == PlaceBase::Local(self_arg()) { if place.base == PlaceBase::Local(self_arg()) {
replace_base(place, Place { replace_base(place, Place {
base: PlaceBase::Local(self_arg()), base: PlaceBase::Local(self_arg()),
projection: Box::new([ProjectionElem::Deref]), projection: self.tcx().intern_place_elems(&vec![ProjectionElem::Deref]),
}); }, self.tcx);
} else { } else {
self.visit_place_base(&mut place.base, context, location); self.visit_place_base(&mut place.base, context, location);
@ -135,9 +146,14 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
struct PinArgVisitor<'tcx> { struct PinArgVisitor<'tcx> {
ref_gen_ty: Ty<'tcx>, ref_gen_ty: Ty<'tcx>,
tcx: TyCtxt<'tcx>,
} }
impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn visit_local(&mut self, fn visit_local(&mut self,
local: &mut Local, local: &mut Local,
_: PlaceContext, _: PlaceContext,
@ -145,15 +161,19 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
assert_ne!(*local, self_arg()); assert_ne!(*local, self_arg());
} }
fn visit_place(&mut self, fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
place: &mut Place<'tcx>,
context: PlaceContext,
location: Location) {
if place.base == PlaceBase::Local(self_arg()) { if place.base == PlaceBase::Local(self_arg()) {
replace_base(place, Place { replace_base(
base: PlaceBase::Local(self_arg()), place,
projection: Box::new([ProjectionElem::Field(Field::new(0), self.ref_gen_ty)]), 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 { } else {
self.visit_place_base(&mut place.base, context, location); 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; place.base = new_base.base;
let mut new_projection = new_base.projection.to_vec(); let mut new_projection = new_base.projection.to_vec();
new_projection.append(&mut place.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 { fn self_arg() -> Local {
@ -226,13 +246,13 @@ impl TransformVisitor<'tcx> {
// Create a Place referencing a generator struct field // Create a Place referencing a generator struct field
fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> { fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> {
let self_place = Place::from(self_arg()); 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(); let mut projection = base.projection.to_vec();
projection.push(ProjectionElem::Field(Field::new(idx), ty)); projection.push(ProjectionElem::Field(Field::new(idx), ty));
Place { Place {
base: base.base, 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> { impl MutVisitor<'tcx> for TransformVisitor<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn visit_local(&mut self, fn visit_local(&mut self,
local: &mut Local, local: &mut Local,
_: PlaceContext, _: PlaceContext,
@ -280,7 +304,7 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> {
if let PlaceBase::Local(l) = place.base { if let PlaceBase::Local(l) = place.base {
// Replace an Local in the remap with a generator struct access // Replace an Local in the remap with a generator struct access
if let Some(&(ty, variant_index, idx)) = self.remap.get(&l) { 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 { } else {
self.visit_place_base(&mut place.base, context, location); 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; body.local_decls.raw[1].ty = ref_gen_ty;
// Add a deref to accesses of the generator state // 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>) { 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; body.local_decls.raw[1].ty = pin_ref_gen_ty;
// Add the Pin field access to accesses of the generator state // 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>( fn replace_result_variable<'tcx>(
ret_ty: Ty<'tcx>, ret_ty: Ty<'tcx>,
body: &mut Body<'tcx>, body: &mut Body<'tcx>,
tcx: TyCtxt<'tcx>,
) -> Local { ) -> Local {
let source_info = source_info(body); let source_info = source_info(body);
let new_ret = LocalDecl { let new_ret = LocalDecl {
@ -416,6 +441,7 @@ fn replace_result_variable<'tcx>(
RenameLocalVisitor { RenameLocalVisitor {
from: RETURN_PLACE, from: RETURN_PLACE,
to: new_ret_local, to: new_ret_local,
tcx,
}.visit_body(body); }.visit_body(body);
new_ret_local 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() { for (block, block_data) in body.basic_blocks().iter_enumerated() {
let (target, unwind, source_info) = match block_data.terminator() { let (target, unwind, source_info) = match block_data.terminator() {
&Terminator { Terminator {
source_info, source_info,
kind: TerminatorKind::Drop { kind: TerminatorKind::Drop {
location: Place { location,
base: PlaceBase::Local(local),
projection: box [],
},
target, target,
unwind 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, _ => continue,
}; };
let unwind = if block_data.is_cleanup { 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( elaborate_drop(
&mut elaborator, &mut elaborator,
source_info, *source_info,
&Place::from(gen), &Place::from(gen),
(), (),
target, *target,
unwind, unwind,
block, 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 // 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. // 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` // Extract locals which are live across suspension point into `layout`
// `remap` gives a mapping from local indices onto generator struct indices // `remap` gives a mapping from local indices onto generator struct indices

View file

@ -461,7 +461,7 @@ impl Inliner<'tcx> {
}; };
caller_body[callsite.bb] caller_body[callsite.bb]
.statements.push(stmt); .statements.push(stmt);
tmp.deref() self.tcx.mk_place_deref(tmp)
} else { } else {
destination.0 destination.0
}; };
@ -481,6 +481,7 @@ impl Inliner<'tcx> {
return_block, return_block,
cleanup_block: cleanup, cleanup_block: cleanup,
in_cleanup_block: false, in_cleanup_block: false,
tcx: self.tcx,
}; };
@ -559,7 +560,8 @@ impl Inliner<'tcx> {
let tuple_tmp_args = let tuple_tmp_args =
tuple_tys.iter().enumerate().map(|(i, ty)| { tuple_tys.iter().enumerate().map(|(i, ty)| {
// This is e.g., `tuple_tmp.0` in our example above. // 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), Field::new(i),
ty.expect_ty(), ty.expect_ty(),
)); ));
@ -587,13 +589,12 @@ impl Inliner<'tcx> {
// FIXME: Analysis of the usage of the arguments to avoid // FIXME: Analysis of the usage of the arguments to avoid
// unnecessary temporaries. // unnecessary temporaries.
if let Operand::Move(Place { if let Operand::Move(place) = &arg {
base: PlaceBase::Local(local), if let Some(local) = place.as_local() {
projection: box [], if caller_body.local_kind(local) == LocalKind::Temp {
}) = arg { // Reuse the operand if it's a temporary already
if caller_body.local_kind(local) == LocalKind::Temp { return local;
// Reuse the operand if it's a temporary already }
return local;
} }
} }
@ -639,6 +640,7 @@ struct Integrator<'a, 'tcx> {
return_block: BasicBlock, return_block: BasicBlock,
cleanup_block: Option<BasicBlock>, cleanup_block: Option<BasicBlock>,
in_cleanup_block: bool, in_cleanup_block: bool,
tcx: TyCtxt<'tcx>,
} }
impl<'a, 'tcx> Integrator<'a, '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 { fn make_integrate_local(&self, local: &Local) -> Local {
if *local == RETURN_PLACE { if *local == RETURN_PLACE {
match self.destination { match self.destination.as_local() {
Place { Some(l) => return l,
base: PlaceBase::Local(l), ref place => bug!("Return place is {:?}, not local", place),
projection: box [],
} => {
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> { impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn visit_local( fn visit_local(
&mut self, &mut self,
local: &mut Local, local: &mut Local,
@ -686,17 +687,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
context: PlaceContext, context: PlaceContext,
location: Location, location: Location,
) { ) {
match place { if let Some(RETURN_PLACE) = place.as_local() {
Place { // Return pointer; update the place itself
base: PlaceBase::Local(RETURN_PLACE), *place = self.destination.clone();
projection: box [], } else {
} => { self.super_place(place, context, location);
// Return pointer; update the place itself
*place = self.destination.clone();
},
_ => {
self.super_place(place, context, location);
}
} }
} }

View file

@ -1,7 +1,8 @@
//! Performs various peephole optimizations. //! Performs various peephole optimizations.
use rustc::mir::{Constant, Location, Place, PlaceBase, Body, Operand, ProjectionElem, Rvalue, use rustc::mir::{
Local}; Constant, Location, Place, PlaceBase, PlaceRef, Body, Operand, ProjectionElem, Rvalue, Local
};
use rustc::mir::visit::{MutVisitor, Visitor}; use rustc::mir::visit::{MutVisitor, Visitor};
use rustc::ty::{self, TyCtxt}; use rustc::ty::{self, TyCtxt};
use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc::util::nodemap::{FxHashMap, FxHashSet};
@ -28,32 +29,33 @@ impl<'tcx> MirPass<'tcx> for InstCombine {
}; };
// Then carry out those optimizations. // Then carry out those optimizations.
MutVisitor::visit_body(&mut InstCombineVisitor { optimizations }, body); MutVisitor::visit_body(&mut InstCombineVisitor { optimizations, tcx }, body);
} }
} }
pub struct InstCombineVisitor<'tcx> { pub struct InstCombineVisitor<'tcx> {
optimizations: OptimizationList<'tcx>, optimizations: OptimizationList<'tcx>,
tcx: TyCtxt<'tcx>,
} }
impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'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) { fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
if self.optimizations.and_stars.remove(&location) { if self.optimizations.and_stars.remove(&location) {
debug!("replacing `&*`: {:?}", rvalue); debug!("replacing `&*`: {:?}", rvalue);
let new_place = match *rvalue { let new_place = match rvalue {
Rvalue::Ref(_, _, Place { Rvalue::Ref(_, _, place) => {
ref mut base, if let &[ref proj_l @ .., proj_r] = place.projection.as_ref() {
projection: ref mut projection @ box [.., _], place.projection = self.tcx().intern_place_elems(&vec![proj_r.clone()]);
}) => {
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();
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 { } else {
unreachable!(); unreachable!();
} }
@ -91,12 +93,14 @@ impl OptimizationFinder<'b, 'tcx> {
impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> { impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> {
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
if let Rvalue::Ref(_, _, Place { if let Rvalue::Ref(_, _, place) = rvalue {
base, if let PlaceRef {
projection: box [proj_base @ .., ProjectionElem::Deref], base,
}) = rvalue { projection: &[ref proj_base @ .., ProjectionElem::Deref],
if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() { } = place.as_ref() {
self.optimizations.and_stars.insert(location); if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() {
self.optimizations.and_stars.insert(location);
}
} }
} }

View file

@ -228,7 +228,7 @@ fn run_optimization_passes<'tcx>(
) { ) {
run_passes(tcx, body, InstanceDef::Item(def_id), promoted, MirPhase::Optimized, &[ run_passes(tcx, body, InstanceDef::Item(def_id), promoted, MirPhase::Optimized, &[
// Remove all things only needed by analysis // Remove all things only needed by analysis
&no_landing_pads::NoLandingPads, &no_landing_pads::NoLandingPads::new(tcx),
&simplify_branches::SimplifyBranches::new("initial"), &simplify_branches::SimplifyBranches::new("initial"),
&remove_noop_landing_pads::RemoveNoopLandingPads, &remove_noop_landing_pads::RemoveNoopLandingPads,
&cleanup_post_borrowck::CleanupNonCodegenStatements, &cleanup_post_borrowck::CleanupNonCodegenStatements,
@ -238,7 +238,7 @@ fn run_optimization_passes<'tcx>(
// These next passes must be executed together // These next passes must be executed together
&add_call_guards::CriticalCallEdges, &add_call_guards::CriticalCallEdges,
&elaborate_drops::ElaborateDrops, &elaborate_drops::ElaborateDrops,
&no_landing_pads::NoLandingPads, &no_landing_pads::NoLandingPads::new(tcx),
// AddMovesForPackedDrops needs to run after drop // AddMovesForPackedDrops needs to run after drop
// elaboration. // elaboration.
&add_moves_for_packed_drops::AddMovesForPackedDrops, &add_moves_for_packed_drops::AddMovesForPackedDrops,
@ -257,7 +257,7 @@ fn run_optimization_passes<'tcx>(
// Optimizations begin. // Optimizations begin.
&uniform_array_move_out::RestoreSubsliceArrayMoveOut, &uniform_array_move_out::RestoreSubsliceArrayMoveOut::new(tcx),
&inline::Inline, &inline::Inline,
// Lowering generator control-flow and variables // Lowering generator control-flow and variables

View file

@ -6,9 +6,17 @@ use rustc::mir::*;
use rustc::mir::visit::MutVisitor; use rustc::mir::visit::MutVisitor;
use crate::transform::{MirPass, MirSource}; use crate::transform::{MirPass, MirSource};
pub struct NoLandingPads; pub struct NoLandingPads<'tcx> {
tcx: TyCtxt<'tcx>,
}
impl<'tcx> MirPass<'tcx> for NoLandingPads { impl<'tcx> NoLandingPads<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>) -> Self {
NoLandingPads { tcx }
}
}
impl<'tcx> MirPass<'tcx> for NoLandingPads<'tcx> {
fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) {
no_landing_pads(tcx, body) 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>) { pub fn no_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
if tcx.sess.no_landing_pads() { 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, fn visit_terminator_kind(&mut self,
kind: &mut TerminatorKind<'tcx>, kind: &mut TerminatorKind<'tcx>,
location: Location) { location: Location) {

View file

@ -17,7 +17,7 @@ use rustc::mir::*;
use rustc::mir::visit::{PlaceContext, MutatingUseContext, MutVisitor, Visitor}; use rustc::mir::visit::{PlaceContext, MutatingUseContext, MutVisitor, Visitor};
use rustc::mir::traversal::ReversePostorder; use rustc::mir::traversal::ReversePostorder;
use rustc::ty::subst::InternalSubsts; use rustc::ty::subst::InternalSubsts;
use rustc::ty::TyCtxt; use rustc::ty::{List, TyCtxt};
use syntax_pos::Span; use syntax_pos::Span;
use rustc_index::vec::{IndexVec, Idx}; use rustc_index::vec::{IndexVec, Idx};
@ -321,7 +321,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
ty, ty,
def_id, def_id,
}), }),
projection: box [], projection: List::empty(),
} }
}; };
let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut(); 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, &mut place.base,
promoted_place(ty, span).base, promoted_place(ty, span).base,
), ),
projection: box [], projection: List::empty(),
}) })
} }
_ => bug!() _ => bug!()
@ -396,6 +396,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
/// Replaces all temporaries with their promoted counterparts. /// Replaces all temporaries with their promoted counterparts.
impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn visit_local(&mut self, fn visit_local(&mut self,
local: &mut Local, local: &mut Local,
_: PlaceContext, _: PlaceContext,
@ -434,14 +438,13 @@ pub fn promote_candidates<'tcx>(
match candidate { match candidate {
Candidate::Repeat(Location { block, statement_index }) | Candidate::Repeat(Location { block, statement_index }) |
Candidate::Ref(Location { block, statement_index }) => { Candidate::Ref(Location { block, statement_index }) => {
match body[block].statements[statement_index].kind { match &body[block].statements[statement_index].kind {
StatementKind::Assign(box(Place { StatementKind::Assign(box(place, _)) => {
base: PlaceBase::Local(local), if let Some(local) = place.as_local() {
projection: box [], if temps[local] == TempState::PromotedOut {
}, _)) => { // Already promoted.
if temps[local] == TempState::PromotedOut { continue;
// Already promoted. }
continue;
} }
} }
_ => {} _ => {}
@ -487,28 +490,30 @@ pub fn promote_candidates<'tcx>(
let promoted = |index: Local| temps[index] == TempState::PromotedOut; let promoted = |index: Local| temps[index] == TempState::PromotedOut;
for block in body.basic_blocks_mut() { for block in body.basic_blocks_mut() {
block.statements.retain(|statement| { block.statements.retain(|statement| {
match statement.kind { match &statement.kind {
StatementKind::Assign(box(Place { StatementKind::Assign(box(place, _)) => {
base: PlaceBase::Local(index), if let Some(index) = place.as_local() {
projection: box [], !promoted(index)
}, _)) | } else {
true
}
}
StatementKind::StorageLive(index) | StatementKind::StorageLive(index) |
StatementKind::StorageDead(index) => { StatementKind::StorageDead(index) => {
!promoted(index) !promoted(*index)
} }
_ => true _ => true
} }
}); });
let terminator = block.terminator_mut(); let terminator = block.terminator_mut();
match terminator.kind { match &terminator.kind {
TerminatorKind::Drop { location: Place { TerminatorKind::Drop { location: place, target, .. } => {
base: PlaceBase::Local(index), if let Some(index) = place.as_local() {
projection: box [], if promoted(index) {
}, target, .. } => { terminator.kind = TerminatorKind::Goto {
if promoted(index) { target: *target,
terminator.kind = TerminatorKind::Goto { };
target, }
};
} }
} }
_ => {} _ => {}

View file

@ -292,8 +292,8 @@ trait Qualif {
Rvalue::Ref(_, _, ref place) => { Rvalue::Ref(_, _, ref place) => {
// Special-case reborrows to be more like a copy of the reference. // Special-case reborrows to be more like a copy of the reference.
if let box [proj_base @ .., elem] = &place.projection { if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
if ProjectionElem::Deref == *elem { if ProjectionElem::Deref == elem {
let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty; let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty;
if let ty::Ref(..) = base_ty.kind { if let ty::Ref(..) = base_ty.kind {
return Self::in_place(cx, PlaceRef { return Self::in_place(cx, PlaceRef {
@ -1041,26 +1041,24 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
match *candidate { match *candidate {
Candidate::Repeat(Location { block: bb, statement_index: stmt_idx }) => { Candidate::Repeat(Location { block: bb, statement_index: stmt_idx }) => {
if let StatementKind::Assign(box(_, Rvalue::Repeat( if let StatementKind::Assign(box(_, Rvalue::Repeat(
Operand::Move(Place { Operand::Move(place),
base: PlaceBase::Local(index),
projection: box [],
}),
_ _
))) = self.body[bb].statements[stmt_idx].kind { ))) = &self.body[bb].statements[stmt_idx].kind {
promoted_temps.insert(index); if let Some(index) = place.as_local() {
promoted_temps.insert(index);
}
} }
} }
Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => { Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
if let StatementKind::Assign( if let StatementKind::Assign(
box( box(
_, _,
Rvalue::Ref(_, _, Place { Rvalue::Ref(_, _, place)
base: PlaceBase::Local(index),
projection: box [],
})
) )
) = self.body[bb].statements[stmt_idx].kind { ) = &self.body[bb].statements[stmt_idx].kind {
promoted_temps.insert(index); if let Some(index) = place.as_local() {
promoted_temps.insert(index);
}
} }
} }
Candidate::Argument { .. } => {} Candidate::Argument { .. } => {}
@ -1237,10 +1235,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
match *operand { match *operand {
Operand::Move(ref place) => { Operand::Move(ref place) => {
// Mark the consumed locals to indicate later drops are noops. // Mark the consumed locals to indicate later drops are noops.
if let Place { if let Some(local) = place.as_local() {
base: PlaceBase::Local(local),
projection: box [],
} = *place {
self.cx.per_local[NeedsDrop].remove(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 { if let Rvalue::Ref(_, kind, ref place) = *rvalue {
// Special-case reborrows. // Special-case reborrows.
let mut reborrow_place = None; let mut reborrow_place = None;
if let box [proj_base @ .., elem] = &place.projection { if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
if *elem == ProjectionElem::Deref { if elem == ProjectionElem::Deref {
let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty; let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
if let ty::Ref(..) = base_ty.kind { if let ty::Ref(..) = base_ty.kind {
reborrow_place = Some(proj_base); reborrow_place = Some(proj_base);
@ -1568,10 +1563,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
unleash_miri!(self); unleash_miri!(self);
// HACK(eddyb): emulate a bit of dataflow analysis, // HACK(eddyb): emulate a bit of dataflow analysis,
// conservatively, that drop elaboration will do. // conservatively, that drop elaboration will do.
let needs_drop = if let Place { let needs_drop = if let Some(local) = place.as_local() {
base: PlaceBase::Local(local),
projection: box [],
} = *place {
if NeedsDrop::in_local(self, local) { if NeedsDrop::in_local(self, local) {
Some(self.body.local_decls[local].source_info.span) Some(self.body.local_decls[local].source_info.span)
} else { } else {
@ -1817,16 +1809,17 @@ fn remove_drop_and_storage_dead_on_promoted_locals(
} }
}); });
let terminator = block.terminator_mut(); let terminator = block.terminator_mut();
match terminator.kind { match &terminator.kind {
TerminatorKind::Drop { TerminatorKind::Drop {
location: Place { location,
base: PlaceBase::Local(index),
projection: box [],
},
target, 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 };
}
}
} }
_ => {} _ => {}
} }

View file

@ -259,8 +259,8 @@ fn check_place(
def_id: DefId, def_id: DefId,
body: &Body<'tcx> body: &Body<'tcx>
) -> McfResult { ) -> McfResult {
let mut cursor = &*place.projection; let mut cursor = place.projection.as_ref();
while let [proj_base @ .., elem] = cursor { while let &[ref proj_base @ .., elem] = cursor {
cursor = proj_base; cursor = proj_base;
match elem { match elem {
ProjectionElem::Downcast(..) => { ProjectionElem::Downcast(..) => {

View file

@ -32,7 +32,7 @@ impl RemoveNoopLandingPads {
nop_landing_pads: &BitSet<BasicBlock>, nop_landing_pads: &BitSet<BasicBlock>,
) -> bool { ) -> bool {
for stmt in &body[bb].statements { for stmt in &body[bb].statements {
match stmt.kind { match &stmt.kind {
StatementKind::FakeRead(..) | StatementKind::FakeRead(..) |
StatementKind::StorageLive(_) | StatementKind::StorageLive(_) |
StatementKind::StorageDead(_) | StatementKind::StorageDead(_) |
@ -41,12 +41,13 @@ impl RemoveNoopLandingPads {
// These are all nops in a landing pad // These are all nops in a landing pad
} }
StatementKind::Assign(box(Place { StatementKind::Assign(box(place, Rvalue::Use(_))) => {
base: PlaceBase::Local(_), if place.as_local().is_some() {
projection: box [], // Writing to a local (e.g., a drop flag) does not
}, Rvalue::Use(_))) => { // turn a landing pad to a non-nop
// Writing to a local (e.g., a drop flag) does not } else {
// turn a landing pad to a non-nop return false;
}
} }
StatementKind::Assign { .. } | StatementKind::Assign { .. } |

View file

@ -155,8 +155,8 @@ fn value_assigned_to_local<'a, 'tcx>(
local: Local, local: Local,
) -> Option<&'a mir::Rvalue<'tcx>> { ) -> Option<&'a mir::Rvalue<'tcx>> {
if let mir::StatementKind::Assign(box (place, rvalue)) = &stmt.kind { if let mir::StatementKind::Assign(box (place, rvalue)) = &stmt.kind {
if let mir::Place { base: mir::PlaceBase::Local(l), projection: box [] } = place { if let Some(l) = place.as_local() {
if local == *l { if local == l {
return Some(&*rvalue); return Some(&*rvalue);
} }
} }
@ -192,7 +192,7 @@ impl PeekCall {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
terminator: &mir::Terminator<'tcx>, terminator: &mir::Terminator<'tcx>,
) -> Option<Self> { ) -> Option<Self> {
use mir::{Operand, Place, PlaceBase}; use mir::Operand;
let span = terminator.source_info.span; let span = terminator.source_info.span;
if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } = if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } =
@ -207,14 +207,23 @@ impl PeekCall {
assert_eq!(args.len(), 1); assert_eq!(args.len(), 1);
let kind = PeekCallKind::from_arg_ty(substs.type_at(0)); let kind = PeekCallKind::from_arg_ty(substs.type_at(0));
let arg = match args[0] { let arg = match &args[0] {
| Operand::Copy(Place { base: PlaceBase::Local(local), projection: box [] }) Operand::Copy(place) | Operand::Move(place) => {
| Operand::Move(Place { base: PlaceBase::Local(local), projection: box [] }) if let Some(local) = place.as_local() {
=> 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( 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; return None;
} }
}; };
@ -277,12 +286,11 @@ impl<'tcx> RustcPeekAt<'tcx> for IndirectlyMutableLocals<'_, 'tcx> {
call: PeekCall, call: PeekCall,
) { ) {
warn!("peek_at: place={:?}", place); warn!("peek_at: place={:?}", place);
let local = match place { let local = if let Some(l) = place.as_local() {
mir::Place { base: mir::PlaceBase::Local(l), projection: box [] } => *l, l
_ => { } else {
tcx.sess.span_err(call.span, "rustc_peek: argument was not a local"); tcx.sess.span_err(call.span, "rustc_peek: argument was not a local");
return; return;
}
}; };
if !flow_state.contains(local) { if !flow_state.contains(local) {

View file

@ -319,7 +319,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyLocals {
let map = make_local_map(&mut body.local_decls, locals); let map = make_local_map(&mut body.local_decls, locals);
// Update references to all vars and tmps now // 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(); 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<Local, Option<Local>>, map: IndexVec<Local, Option<Local>>,
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>) { fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
// Remove unnecessary StorageLive and StorageDead annotations. // Remove unnecessary StorageLive and StorageDead annotations.
data.statements.retain(|stmt| { data.statements.retain(|stmt| {

View file

@ -61,7 +61,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
rvalue: &Rvalue<'tcx>, rvalue: &Rvalue<'tcx>,
location: Location) { location: Location) {
if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue { 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: _, if let ProjectionElem::ConstantIndex{offset: _,
min_length: _, min_length: _,
from_end: false} = elem { from_end: false} = elem {
@ -116,16 +116,13 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
min_length: size, min_length: size,
from_end: false, from_end: false,
}); });
self.patch.add_assign(location, self.patch.add_assign(
Place::from(temp), location,
Rvalue::Use( Place::from(temp),
Operand::Move( Rvalue::Use(Operand::Move(Place {
Place { base: base.clone(),
base: base.clone(), projection: self.tcx.intern_place_elems(&projection),
projection: projection.into_boxed_slice(), })),
}
)
)
); );
temp temp
}).collect(); }).collect();
@ -153,16 +150,13 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
min_length: size, min_length: size,
from_end: false, from_end: false,
}); });
self.patch.add_assign(location, self.patch.add_assign(
dst_place.clone(), location,
Rvalue::Use( dst_place.clone(),
Operand::Move( Rvalue::Use(Operand::Move(Place {
Place { base: base.clone(),
base: base.clone(), projection: self.tcx.intern_place_elems(&projection),
projection: projection.into_boxed_slice(), })),
}
)
)
); );
} }
_ => {} _ => {}
@ -185,9 +179,11 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
// //
// replaced by _10 = move _2[:-1]; // 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>) { fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
let mut patch = MirPatch::new(body); let mut patch = MirPatch::new(body);
let param_env = tcx.param_env(src.def_id()); 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 StatementKind::Assign(box(ref dst_place, ref rval)) = statement.kind {
if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval { if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval {
let items : Vec<_> = items.iter().map(|item| { let items : Vec<_> = items.iter().map(|item| {
if let Operand::Move(Place { if let Operand::Move(place) = item {
base: PlaceBase::Local(local), if let Some(local) = place.as_local() {
projection: box [], let local_use = &visitor.locals_use[local];
}) = item { let opt_index_and_place =
let local_use = &visitor.locals_use[*local]; Self::try_get_item_source(local_use, body);
let opt_index_and_place = // each local should be used twice:
Self::try_get_item_source(local_use, body); // in assign and in aggregate statements
// each local should be used twice: if local_use.use_count == 2 && opt_index_and_place.is_some() {
// in assign and in aggregate statements let (index, src_place) = opt_index_and_place.unwrap();
if local_use.use_count == 2 && opt_index_and_place.is_some() { return Some((local_use, index, src_place));
let (index, src_place) = opt_index_and_place.unwrap(); }
return Some((local_use, index, src_place));
} }
} }
None None
@ -230,7 +225,9 @@ impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut {
None 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 // 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. // indices is an integer interval. If all checks pass do the replacent.
// items are Vec<Option<LocalUse, index in source array, source place for init local>> // items are Vec<Option<LocalUse, index in source array, source place for init local>>
fn check_and_patch<'tcx>(candidate: Location, fn check_and_patch(&self,
items: &[Option<(&LocalUse, u32, PlaceRef<'_, 'tcx>)>], candidate: Location,
opt_size: Option<u64>, items: &[Option<(&LocalUse, u32, PlaceRef<'_, 'tcx>)>],
patch: &mut MirPatch<'tcx>, opt_size: Option<u64>,
dst_place: &Place<'tcx>) { patch: &mut MirPatch<'tcx>,
dst_place: &Place<'tcx>) {
let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2); let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2);
if opt_size.is_some() && items.iter().all( if opt_size.is_some() && items.iter().all(
@ -280,46 +282,40 @@ impl RestoreSubsliceArrayMoveOut {
dst_place.clone(), dst_place.clone(),
Rvalue::Use(Operand::Move(Place { Rvalue::Use(Operand::Move(Place {
base: src_place.base.clone(), 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, fn try_get_item_source<'a>(local_use: &LocalUse,
body: &'a Body<'tcx>) -> Option<(u32, PlaceRef<'a, 'tcx>)> { body: &'a Body<'tcx>) -> Option<(u32, PlaceRef<'a, 'tcx>)> {
if let Some(location) = local_use.first_use { if let Some(location) = local_use.first_use {
let block = &body[location.block]; let block = &body[location.block];
if block.statements.len() > location.statement_index { if block.statements.len() > location.statement_index {
let statement = &block.statements[location.statement_index]; let statement = &block.statements[location.statement_index];
if let StatementKind::Assign( if let StatementKind::Assign(
box( box(place, Rvalue::Use(Operand::Move(src_place)))
Place {
base: PlaceBase::Local(_),
projection: box [],
},
Rvalue::Use(Operand::Move(Place {
base: _,
projection: box [.., ProjectionElem::ConstantIndex {
offset, min_length: _, from_end: false
}],
})),
)
) = &statement.kind { ) = &statement.kind {
// FIXME remove once we can use slices patterns if let (Some(_), PlaceRef {
if let StatementKind::Assign( base: _,
box( projection: &[.., ProjectionElem::ConstantIndex {
_, offset, min_length: _, from_end: false
Rvalue::Use(Operand::Move(Place { }],
}) = (place.as_local(), src_place.as_ref()) {
if let StatementKind::Assign(
box(_, Rvalue::Use(Operand::Move(place)))
) = &statement.kind {
if let PlaceRef {
base, base,
projection: box [proj_base @ .., _], projection: &[ref proj_base @ .., _],
})), } = place.as_ref() {
) return Some((offset, PlaceRef {
) = &statement.kind { base,
return Some((*offset, PlaceRef { projection: proj_base,
base, }))
projection: proj_base, }
})) }
} }
} }
} }

View file

@ -1,5 +1,5 @@
use rustc::mir::*; use rustc::mir::*;
use rustc::ty::Ty; use rustc::ty::{Ty, TyCtxt};
use rustc::ty::layout::VariantIdx; use rustc::ty::layout::VariantIdx;
use rustc_index::vec::Idx; use rustc_index::vec::Idx;
@ -17,6 +17,7 @@ pub fn expand_aggregate<'tcx>(
operands: impl Iterator<Item=(Operand<'tcx>, Ty<'tcx>)> + TrustedLen, operands: impl Iterator<Item=(Operand<'tcx>, Ty<'tcx>)> + TrustedLen,
kind: AggregateKind<'tcx>, kind: AggregateKind<'tcx>,
source_info: SourceInfo, source_info: SourceInfo,
tcx: TyCtxt<'tcx>,
) -> impl Iterator<Item=Statement<'tcx>> + TrustedLen { ) -> impl Iterator<Item=Statement<'tcx>> + TrustedLen {
let mut set_discriminant = None; let mut set_discriminant = None;
let active_field_index = match kind { let active_field_index = match kind {
@ -29,7 +30,7 @@ pub fn expand_aggregate<'tcx>(
}, },
source_info, source_info,
}); });
lhs = lhs.downcast(adt_def, variant_index); lhs = tcx.mk_place_downcast(lhs, adt_def, variant_index);
} }
active_field_index active_field_index
} }
@ -58,7 +59,7 @@ pub fn expand_aggregate<'tcx>(
// FIXME(eddyb) `offset` should be u64. // FIXME(eddyb) `offset` should be u64.
let offset = i as u32; let offset = i as u32;
assert_eq!(offset as usize, i); assert_eq!(offset as usize, i);
lhs.clone().elem(ProjectionElem::ConstantIndex { tcx.mk_place_elem(lhs.clone(), ProjectionElem::ConstantIndex {
offset, offset,
// FIXME(eddyb) `min_length` doesn't appear to be used. // FIXME(eddyb) `min_length` doesn't appear to be used.
min_length: offset + 1, min_length: offset + 1,
@ -66,7 +67,7 @@ pub fn expand_aggregate<'tcx>(
}) })
} else { } else {
let field = Field::new(active_field_index.unwrap_or(i)); let field = Field::new(active_field_index.unwrap_or(i));
lhs.clone().field(field, ty) tcx.mk_place_field(lhs.clone(), field, ty)
}; };
Statement { Statement {
source_info, source_info,

View file

@ -38,8 +38,8 @@ fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: &Place<'
where where
L: HasLocalDecls<'tcx>, L: HasLocalDecls<'tcx>,
{ {
let mut cursor = &*place.projection; let mut cursor = place.projection.as_ref();
while let [proj_base @ .., elem] = cursor { while let &[ref proj_base @ .., elem] = cursor {
cursor = proj_base; cursor = proj_base;
match elem { match elem {

View file

@ -2,6 +2,7 @@
use rustc::mir::{Body, Local, Location, PlaceElem}; use rustc::mir::{Body, Local, Location, PlaceElem};
use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor}; use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
use rustc::ty::TyCtxt;
use rustc_index::vec::IndexVec; use rustc_index::vec::IndexVec;
use std::mem; use std::mem;
@ -47,20 +48,26 @@ impl DefUseAnalysis {
&self.info[local] &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 { for place_use in &self.info[local].defs_and_uses {
MutateUseVisitor::new(local, MutateUseVisitor::new(local, new_local, body, tcx)
new_local, .visit_location(body, place_use.location)
body).visit_location(body, place_use.location)
} }
} }
// FIXME(pcwalton): this should update the def-use chains. // FIXME(pcwalton): this should update the def-use chains.
pub fn replace_all_defs_and_uses_with(&self, pub fn replace_all_defs_and_uses_with(&self,
local: Local, local: Local,
body: &mut Body<'_>, body: &mut Body<'tcx>,
new_local: Local) { new_local: Local,
self.mutate_defs_and_uses(local, body, new_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, query: Local,
new_local: Local, new_local: Local,
tcx: TyCtxt<'tcx>,
} }
impl MutateUseVisitor { impl MutateUseVisitor<'tcx> {
fn new(query: Local, new_local: Local, _: &Body<'_>) -> MutateUseVisitor { fn new(
MutateUseVisitor { query: Local,
query, new_local: Local,
new_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, fn visit_local(&mut self,
local: &mut Local, local: &mut Local,
_context: PlaceContext, _context: PlaceContext,

View file

@ -200,13 +200,14 @@ where
variant.fields.iter().enumerate().map(|(i, f)| { variant.fields.iter().enumerate().map(|(i, f)| {
let field = Field::new(i); let field = Field::new(i);
let subpath = self.elaborator.field_subpath(variant_path, field); let subpath = self.elaborator.field_subpath(variant_path, field);
let tcx = self.tcx();
assert_eq!(self.elaborator.param_env().reveal, Reveal::All); 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(), 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() }).collect()
} }
@ -323,7 +324,7 @@ where
debug!("open_drop_for_tuple({:?}, {:?})", self, tys); debug!("open_drop_for_tuple({:?}, {:?})", self, tys);
let fields = tys.iter().enumerate().map(|(i, &ty)| { 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))) self.elaborator.field_subpath(self.path, Field::new(i)))
}).collect(); }).collect();
@ -334,7 +335,7 @@ where
fn open_drop_for_box(&mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>) -> BasicBlock { fn open_drop_for_box(&mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>) -> BasicBlock {
debug!("open_drop_for_box({:?}, {:?}, {:?})", self, adt, substs); 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 interior_path = self.elaborator.deref_subpath(self.path);
let succ = self.succ; // FIXME(#43234) let succ = self.succ; // FIXME(#43234)
@ -406,14 +407,19 @@ where
}; };
let mut have_otherwise = false; 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( let subpath = self.elaborator.downcast_subpath(
self.path, variant_index); self.path, variant_index);
if let Some(variant_path) = subpath { if let Some(variant_path) = subpath {
let base_place = self.place.clone().elem( let base_place = tcx.mk_place_elem(
ProjectionElem::Downcast(Some(adt.variants[variant_index].ident.name), self.place.clone(),
variant_index)); ProjectionElem::Downcast(
Some(adt.variants[variant_index].ident.name),
variant_index,
),
);
let fields = self.move_paths_for_fields( let fields = self.move_paths_for_fields(
&base_place, &base_place,
variant_path, variant_path,
@ -586,7 +592,7 @@ where
BorrowKind::Mut { allow_two_phase_borrow: false }, BorrowKind::Mut { allow_two_phase_borrow: false },
Place { Place {
base: PlaceBase::Local(cur), 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)) Rvalue::BinaryOp(BinOp::Offset, move_(&Place::from(cur)), one))
@ -594,7 +600,7 @@ where
(Rvalue::Ref( (Rvalue::Ref(
tcx.lifetimes.re_erased, tcx.lifetimes.re_erased,
BorrowKind::Mut { allow_two_phase_borrow: false }, 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)) Rvalue::BinaryOp(BinOp::Add, move_(&Place::from(cur)), one))
}; };
@ -627,7 +633,7 @@ where
let loop_block = self.elaborator.patch().new_block(loop_block); let loop_block = self.elaborator.patch().new_block(loop_block);
self.elaborator.patch().patch_terminator(drop_block, TerminatorKind::Drop { self.elaborator.patch().patch_terminator(drop_block, TerminatorKind::Drop {
location: ptr.clone().deref(), location: tcx.mk_place_deref(ptr.clone()),
target: loop_block, target: loop_block,
unwind: unwind.into_option() unwind: unwind.into_option()
}); });
@ -644,18 +650,27 @@ where
// ptr_based_loop // ptr_based_loop
// } // }
let tcx = self.tcx();
if let Some(size) = opt_size { if let Some(size) = opt_size {
let size: u32 = size.try_into().unwrap_or_else(|_| { let size: u32 = size.try_into().unwrap_or_else(|_| {
bug!("move out check isn't implemented for array sizes bigger than u32::MAX"); bug!("move out check isn't implemented for array sizes bigger than u32::MAX");
}); });
let fields: Vec<(Place<'tcx>, Option<D::Path>)> = (0..size).map(|i| { let fields: Vec<(Place<'tcx>, Option<D::Path>)> = (0..size)
(self.place.clone().elem(ProjectionElem::ConstantIndex{ .map(|i| {
offset: i, (
min_length: size, tcx.mk_place_elem(
from_end: false self.place.clone(),
}), ProjectionElem::ConstantIndex {
self.elaborator.array_subpath(self.path, i, size)) offset: i,
}).collect(); min_length: size,
from_end: false,
},
),
self.elaborator.array_subpath(self.path, i, size),
)
})
.collect();
if fields.iter().any(|(_,path)| path.is_some()) { if fields.iter().any(|(_,path)| path.is_some()) {
let (succ, unwind) = self.drop_ladder_bottom(); let (succ, unwind) = self.drop_ladder_bottom();
@ -664,7 +679,6 @@ where
} }
let move_ = |place: &Place<'tcx>| Operand::Move(place.clone()); 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 elem_size = &Place::from(self.new_temp(tcx.types.usize));
let len = &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 args = adt.variants[VariantIdx::new(0)].fields.iter().enumerate().map(|(i, f)| {
let field = Field::new(i); let field = Field::new(i);
let field_ty = f.ty(self.tcx(), substs); let field_ty = f.ty(tcx, substs);
Operand::Move(self.place.clone().field(field, field_ty)) Operand::Move(tcx.mk_place_field(self.place.clone(), field, field_ty))
}).collect(); }).collect();
let call = TerminatorKind::Call { let call = TerminatorKind::Call {

View file

@ -26,9 +26,10 @@ use rustc::ty::{self, DefIdTree, TyCtxt, Region, RegionVid, Ty, AdtKind};
use rustc::ty::fold::TypeFolder; use rustc::ty::fold::TypeFolder;
use rustc::ty::layout::VariantIdx; use rustc::ty::layout::VariantIdx;
use rustc::util::nodemap::{FxHashMap, FxHashSet}; 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::attr;
use syntax_expand::base::MacroKind; use syntax_expand::base::MacroKind;
use syntax::parse::lexer::comments;
use syntax::source_map::DUMMY_SP; use syntax::source_map::DUMMY_SP;
use syntax::symbol::{Symbol, kw, sym}; use syntax::symbol::{Symbol, kw, sym};
use syntax_pos::{self, Pos, FileName}; use syntax_pos::{self, Pos, FileName};
@ -858,8 +859,31 @@ impl Attributes {
let mut cfg = Cfg::True; let mut cfg = Cfg::True;
let mut doc_line = 0; 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<T>(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| { 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 attr.check_name(sym::doc) {
if let Some(mi) = attr.meta() { if let Some(mi) = attr.meta() {
if let Some(value) = mi.value_str() { if let Some(value) = mi.value_str() {

View file

@ -79,7 +79,7 @@ function getSearchElement() {
"derive", "derive",
"traitalias"]; "traitalias"];
var disableShortcuts = getCurrentValue("rustdoc-disable-shortcuts") !== "true"; var disableShortcuts = getCurrentValue("rustdoc-disable-shortcuts") === "true";
var search_input = getSearchInput(); var search_input = getSearchInput();
// On the search screen, so you remain on the last tab you opened. // On the search screen, so you remain on the last tab you opened.

View file

@ -283,7 +283,7 @@
#![feature(needs_panic_runtime)] #![feature(needs_panic_runtime)]
#![feature(never_type)] #![feature(never_type)]
#![feature(nll)] #![feature(nll)]
#![feature(non_exhaustive)] #![cfg_attr(bootstrap, feature(non_exhaustive))]
#![feature(on_unimplemented)] #![feature(on_unimplemented)]
#![feature(optin_builtin_traits)] #![feature(optin_builtin_traits)]
#![feature(panic_info_message)] #![feature(panic_info_message)]

View file

@ -1363,20 +1363,24 @@ impl PathBuf {
} }
fn _set_extension(&mut self, extension: &OsStr) -> bool { fn _set_extension(&mut self, extension: &OsStr) -> bool {
if self.file_name().is_none() { let file_stem = match self.file_stem() {
return false; None => return false,
} Some(f) => os_str_as_u8_slice(f),
let mut stem = match self.file_stem() {
Some(stem) => stem.to_os_string(),
None => OsString::new(),
}; };
if !os_str_as_u8_slice(extension).is_empty() { // truncate until right after the file stem
stem.push("."); let end_file_stem = file_stem[file_stem.len()..].as_ptr() as usize;
stem.push(extension); 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 true
} }

View file

@ -105,11 +105,14 @@ cfg_has_statx! {{
flags: i32, flags: i32,
mask: u32, mask: u32,
) -> Option<io::Result<FileAttr>> { ) -> Option<io::Result<FileAttr>> {
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` // 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 // We store the availability in global to avoid unnecessary syscalls.
static HAS_STATX: AtomicBool = AtomicBool::new(true); // 0: Unknown
// 1: Not available
// 2: Available
static STATX_STATE: AtomicU8 = AtomicU8::new(0);
syscall! { syscall! {
fn statx( fn statx(
fd: c_int, fd: c_int,
@ -120,50 +123,60 @@ cfg_has_statx! {{
) -> c_int ) -> c_int
} }
if !HAS_STATX.load(Ordering::Relaxed) { match STATX_STATE.load(Ordering::Relaxed) {
return None; 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;
}
STATX_STATE.store(2, Ordering::Relaxed);
}
1 => return None,
_ => {}
} }
let mut buf: libc::statx = mem::zeroed(); let mut buf: libc::statx = mem::zeroed();
let ret = cvt(statx(fd, path, flags, mask, &mut buf)); if let Err(err) = cvt(statx(fd, path, flags, mask, &mut buf)) {
match ret { return Some(Err(err));
Err(err) => match err.raw_os_error() {
Some(libc::ENOSYS) => {
HAS_STATX.store(false, Ordering::Relaxed);
return None;
}
_ => return Some(Err(err)),
}
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,
};
Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) }))
}
} }
// 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 { } else {

View file

@ -13,8 +13,8 @@ use crate::ast::{AttrItem, AttrId, AttrStyle, Name, Ident, Path, PathSegment};
use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem}; use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem};
use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam}; use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam};
use crate::mut_visit::visit_clobber; use crate::mut_visit::visit_clobber;
use crate::source_map::{BytePos, Spanned, DUMMY_SP}; use crate::source_map::{BytePos, Spanned};
use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use crate::parse::lexer::comments::doc_comment_style;
use crate::parse::parser::Parser; use crate::parse::parser::Parser;
use crate::parse::PResult; use crate::parse::PResult;
use crate::parse::token::{self, Token}; use crate::parse::token::{self, Token};
@ -312,31 +312,6 @@ impl Attribute {
span: self.span, 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<T, F>(&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 */ /* Constructors */

View file

@ -245,8 +245,10 @@ declare_features! (
(accepted, bind_by_move_pattern_guards, "1.39.0", Some(15287), None), (accepted, bind_by_move_pattern_guards, "1.39.0", Some(15287), None),
/// Allows attributes in formal function parameters. /// Allows attributes in formal function parameters.
(accepted, param_attrs, "1.39.0", Some(60406), None), (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), (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 // feature-group-end: accepted features

View file

@ -383,9 +383,6 @@ declare_features! (
/// Allows `#[doc(include = "some-file")]`. /// Allows `#[doc(include = "some-file")]`.
(active, external_doc, "1.22.0", Some(44732), None), (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)`. /// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`.
(active, crate_visibility_modifier, "1.23.0", Some(53120), None), (active, crate_visibility_modifier, "1.23.0", Some(53120), None),

View file

@ -252,6 +252,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
ungated!(path, Normal, template!(NameValueStr: "file")), ungated!(path, Normal, template!(NameValueStr: "file")),
ungated!(no_std, CrateLevel, template!(Word)), ungated!(no_std, CrateLevel, template!(Word)),
ungated!(no_implicit_prelude, Normal, template!(Word)), ungated!(no_implicit_prelude, Normal, template!(Word)),
ungated!(non_exhaustive, Whitelisted, template!(Word)),
// Runtime // Runtime
ungated!(windows_subsystem, Whitelisted, template!(NameValueStr: "windows|console")), 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, test_runner, CrateLevel, template!(List: "path"), custom_test_frameworks,
"custom test frameworks are an unstable feature", "custom test frameworks are an unstable feature",
), ),
// RFC #2008
gated!(non_exhaustive, Whitelisted, template!(Word), experimental!(non_exhaustive)),
// RFC #1268 // RFC #1268
gated!(marker, Normal, template!(Word), marker_trait_attr, experimental!(marker)), gated!(marker, Normal, template!(Word), marker_trait_attr, experimental!(marker)),
gated!( gated!(

View file

@ -25,6 +25,9 @@ use std::sync::{Arc, Mutex};
use rustc_serialize::json::{as_json, as_pretty_json}; use rustc_serialize::json::{as_json, as_pretty_json};
#[cfg(test)]
mod tests;
pub struct JsonEmitter { pub struct JsonEmitter {
dst: Box<dyn Write + Send>, dst: Box<dyn Write + Send>,
registry: Option<Registry>, registry: Option<Registry>,
@ -336,8 +339,8 @@ impl DiagnosticSpan {
DiagnosticSpan { DiagnosticSpan {
file_name: start.file.name.to_string(), file_name: start.file.name.to_string(),
byte_start: span.lo().0 - start.file.start_pos.0, byte_start: start.file.original_relative_byte_pos(span.lo()).0,
byte_end: span.hi().0 - start.file.start_pos.0, byte_end: start.file.original_relative_byte_pos(span.hi()).0,
line_start: start.line, line_start: start.line,
line_end: end.line, line_end: end.line,
column_start: start.col.0 + 1, column_start: start.col.0 + 1,

186
src/libsyntax/json/tests.rs Normal file
View file

@ -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<SpanTestData>,
}
#[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,
},
)
}

View file

@ -31,23 +31,6 @@ mod tests;
pub const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments"); pub const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments");
// A variant of 'panictry!' that works on a Vec<Diagnostic> 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_export]
macro_rules! unwrap_or { macro_rules! unwrap_or {
($opt:expr, $default:expr) => { ($opt:expr, $default:expr) => {

View file

@ -176,7 +176,7 @@ fn split_block_comment_into_lines(
// it appears this function is called only from pprust... that's // it appears this function is called only from pprust... that's
// probably not a good thing. // probably not a good thing.
pub fn gather_comments(sess: &ParseSess, path: FileName, src: String) -> Vec<Comment> { crate fn gather_comments(sess: &ParseSess, path: FileName, src: String) -> Vec<Comment> {
let cm = SourceMap::new(sess.source_map().path_mapping().clone()); let cm = SourceMap::new(sess.source_map().path_mapping().clone());
let source_file = cm.new_source_file(path, src); let source_file = cm.new_source_file(path, src);
let text = (*source_file.src.as_ref().unwrap()).clone(); let text = (*source_file.src.as_ref().unwrap()).clone();

View file

@ -1,8 +1,9 @@
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use syntax_pos::Span; use syntax_pos::Span;
use super::{StringReader, UnmatchedBrace};
use crate::print::pprust::token_to_string; use crate::print::pprust::token_to_string;
use crate::parse::lexer::{StringReader, UnmatchedBrace};
use crate::parse::token::{self, Token}; use crate::parse::token::{self, Token};
use crate::parse::PResult; use crate::parse::PResult;
use crate::tokenstream::{DelimSpan, IsJoint::{self, *}, TokenStream, TokenTree, TreeAndJoint}; use crate::tokenstream::{DelimSpan, IsJoint::{self, *}, TokenStream, TokenTree, TreeAndJoint};

View file

@ -59,6 +59,23 @@ pub enum DirectoryOwnership {
// uses a HOF to parse anything, and <source> includes file and // uses a HOF to parse anything, and <source> includes file and
// `source_str`. // `source_str`.
/// A variant of 'panictry!' that works on a Vec<Diagnostic> 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> { 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); let mut parser = new_parser_from_file(sess, input);
parser.parse_crate_mod() parser.parse_crate_mod()

View file

@ -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<UnmatchedBrace>, handler: &errors::Handler) { pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedBrace>, handler: &errors::Handler) {

View file

@ -19,6 +19,7 @@ use log::debug;
use std::mem; use std::mem;
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use errors::{Applicability, DiagnosticBuilder, DiagnosticId, StashKey}; 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. /// Whether the type alias or associated type is a concrete type or an opaque type.
#[derive(Debug)] #[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, fn mk_item(&self, span: Span, ident: Ident, kind: ItemKind, vis: Visibility,
attrs: Vec<Attribute>) -> P<Item> { attrs: Vec<Attribute>) -> P<Item> {
P(Item { P(Item {

View file

@ -283,6 +283,7 @@ impl SourceMap {
mut file_local_lines: Vec<BytePos>, mut file_local_lines: Vec<BytePos>,
mut file_local_multibyte_chars: Vec<MultiByteChar>, mut file_local_multibyte_chars: Vec<MultiByteChar>,
mut file_local_non_narrow_chars: Vec<NonNarrowChar>, mut file_local_non_narrow_chars: Vec<NonNarrowChar>,
mut file_local_normalized_pos: Vec<NormalizedPos>,
) -> Lrc<SourceFile> { ) -> Lrc<SourceFile> {
let start_pos = self.next_start_pos(); let start_pos = self.next_start_pos();
@ -301,6 +302,10 @@ impl SourceMap {
*swc = *swc + start_pos; *swc = *swc + start_pos;
} }
for nc in &mut file_local_normalized_pos {
nc.pos = nc.pos + start_pos;
}
let source_file = Lrc::new(SourceFile { let source_file = Lrc::new(SourceFile {
name: filename, name: filename,
name_was_remapped, name_was_remapped,
@ -314,6 +319,7 @@ impl SourceMap {
lines: file_local_lines, lines: file_local_lines,
multibyte_chars: file_local_multibyte_chars, multibyte_chars: file_local_multibyte_chars,
non_narrow_chars: file_local_non_narrow_chars, non_narrow_chars: file_local_non_narrow_chars,
normalized_pos: file_local_normalized_pos,
name_hash, name_hash,
}); });

View file

@ -111,8 +111,8 @@ struct SpanLabel {
label: &'static str, label: &'static str,
} }
struct Shared<T: Write> { crate struct Shared<T: Write> {
data: Arc<Mutex<T>>, pub data: Arc<Mutex<T>>,
} }
impl<T: Write> Write for Shared<T> { impl<T: Write> Write for Shared<T> {

View file

@ -9,7 +9,7 @@
#![feature(const_fn)] #![feature(const_fn)]
#![feature(crate_visibility_modifier)] #![feature(crate_visibility_modifier)]
#![feature(nll)] #![feature(nll)]
#![feature(non_exhaustive)] #![cfg_attr(bootstrap, feature(non_exhaustive))]
#![feature(optin_builtin_traits)] #![feature(optin_builtin_traits)]
#![feature(rustc_attrs)] #![feature(rustc_attrs)]
#![cfg_attr(bootstrap, feature(proc_macro_hygiene))] #![cfg_attr(bootstrap, feature(proc_macro_hygiene))]
@ -855,6 +855,15 @@ impl Sub<BytePos> 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`. /// The state of the lazy external source loading mechanism of a `SourceFile`.
#[derive(PartialEq, Eq, Clone)] #[derive(PartialEq, Eq, Clone)]
pub enum ExternalSource { pub enum ExternalSource {
@ -918,6 +927,8 @@ pub struct SourceFile {
pub multibyte_chars: Vec<MultiByteChar>, pub multibyte_chars: Vec<MultiByteChar>,
/// Width of characters that are not narrow in the source code. /// Width of characters that are not narrow in the source code.
pub non_narrow_chars: Vec<NonNarrowChar>, pub non_narrow_chars: Vec<NonNarrowChar>,
/// Locations of characters removed during normalization.
pub normalized_pos: Vec<NormalizedPos>,
/// A hash of the filename, used for speeding up hashing in incremental compilation. /// A hash of the filename, used for speeding up hashing in incremental compilation.
pub name_hash: u128, pub name_hash: u128,
} }
@ -984,6 +995,9 @@ impl Encodable for SourceFile {
})?; })?;
s.emit_struct_field("name_hash", 8, |s| { s.emit_struct_field("name_hash", 8, |s| {
self.name_hash.encode(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))?; d.read_struct_field("non_narrow_chars", 7, |d| Decodable::decode(d))?;
let name_hash: u128 = let name_hash: u128 =
d.read_struct_field("name_hash", 8, |d| Decodable::decode(d))?; d.read_struct_field("name_hash", 8, |d| Decodable::decode(d))?;
let normalized_pos: Vec<NormalizedPos> =
d.read_struct_field("normalized_pos", 9, |d| Decodable::decode(d))?;
Ok(SourceFile { Ok(SourceFile {
name, name,
name_was_remapped, name_was_remapped,
@ -1050,6 +1066,7 @@ impl Decodable for SourceFile {
lines, lines,
multibyte_chars, multibyte_chars,
non_narrow_chars, non_narrow_chars,
normalized_pos,
name_hash, name_hash,
}) })
}) })
@ -1068,8 +1085,7 @@ impl SourceFile {
unmapped_path: FileName, unmapped_path: FileName,
mut src: String, mut src: String,
start_pos: BytePos) -> Result<SourceFile, OffsetOverflowError> { start_pos: BytePos) -> Result<SourceFile, OffsetOverflowError> {
remove_bom(&mut src); let normalized_pos = normalize_src(&mut src, start_pos);
normalize_newlines(&mut src);
let src_hash = { let src_hash = {
let mut hasher: StableHasher = StableHasher::new(); let mut hasher: StableHasher = StableHasher::new();
@ -1102,6 +1118,7 @@ impl SourceFile {
lines, lines,
multibyte_chars, multibyte_chars,
non_narrow_chars, non_narrow_chars,
normalized_pos,
name_hash, name_hash,
}) })
} }
@ -1228,12 +1245,44 @@ impl SourceFile {
pub fn contains(&self, byte_pos: BytePos) -> bool { pub fn contains(&self, byte_pos: BytePos) -> bool {
byte_pos >= self.start_pos && byte_pos <= self.end_pos 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<NormalizedPos> {
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. /// Removes UTF-8 BOM, if any.
fn remove_bom(src: &mut String) { fn remove_bom(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
if src.starts_with("\u{feff}") { if src.starts_with("\u{feff}") {
src.drain(..3); 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`. /// Replaces `\r\n` with `\n` in-place in `src`.
/// ///
/// Returns error if there's a lone `\r` in the string /// 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<NormalizedPos>) {
if !src.as_bytes().contains(&b'\r') { if !src.as_bytes().contains(&b'\r') {
return; return;
} }
@ -1254,6 +1303,8 @@ fn normalize_newlines(src: &mut String) {
let mut buf = std::mem::replace(src, String::new()).into_bytes(); let mut buf = std::mem::replace(src, String::new()).into_bytes();
let mut gap_len = 0; let mut gap_len = 0;
let mut tail = buf.as_mut_slice(); let mut tail = buf.as_mut_slice();
let mut cursor = 0;
let original_gap = normalized_pos.last().map_or(0, |l| l.diff);
loop { loop {
let idx = match find_crlf(&tail[gap_len..]) { let idx = match find_crlf(&tail[gap_len..]) {
None => tail.len(), None => tail.len(),
@ -1264,7 +1315,12 @@ fn normalize_newlines(src: &mut String) {
if tail.len() == gap_len { if tail.len() == gap_len {
break; break;
} }
cursor += idx - gap_len;
gap_len += 1; gap_len += 1;
normalized_pos.push(NormalizedPos {
pos: BytePos::from_usize(cursor + 1),
diff: original_gap + gap_len as u32,
});
} }
// Account for removed `\r`. // Account for removed `\r`.

View file

@ -19,20 +19,25 @@ fn test_lookup_line() {
#[test] #[test]
fn test_normalize_newlines() { 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(); 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.as_str(), after);
assert_eq!(actual_positions, expected_positions);
} }
check("", ""); check("", "", &[]);
check("\n", "\n"); check("\n", "\n", &[]);
check("\r", "\r"); check("\r", "\r", &[]);
check("\r\r", "\r\r"); check("\r\r", "\r\r", &[]);
check("\r\n", "\n"); check("\r\n", "\n", &[1]);
check("hello world", "hello world"); check("hello world", "hello world", &[]);
check("hello\nworld", "hello\nworld"); check("hello\nworld", "hello\nworld", &[]);
check("hello\r\nworld", "hello\nworld"); check("hello\r\nworld", "hello\nworld", &[6]);
check("\r\nhello\r\nworld\r\n", "\nhello\nworld\n"); check("\r\nhello\r\nworld\r\n", "\nhello\nworld\n", &[1, 7, 13]);
check("\r\r\n", "\r\n"); check("\r\r\n", "\r\n", &[2]);
check("hello\rworld", "hello\rworld"); check("hello\rworld", "hello\rworld", &[]);
} }

View file

@ -1,3 +1,6 @@
lexer-crlf-line-endings-string-literal-doc-comment.rs -text 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 trailing-carriage-return-in-string.rs -text
*.bin -text *.bin -text

View file

@ -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() { }

View file

@ -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`.

View file

@ -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.
}

View file

@ -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();
}

View file

@ -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
"}

View file

@ -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.
}

View file

@ -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
"}

View file

@ -1,5 +1,4 @@
#![crate_type = "rlib"] #![crate_type = "rlib"]
#![feature(non_exhaustive)]
#[non_exhaustive] #[non_exhaustive]
pub enum NonExhaustiveEnum { pub enum NonExhaustiveEnum {

View file

@ -1,5 +1,3 @@
#![feature(non_exhaustive)]
#[non_exhaustive] #[non_exhaustive]
pub struct NormalStruct { pub struct NormalStruct {
pub first_field: u16, pub first_field: u16,

View file

@ -1,5 +1,4 @@
#![crate_type = "rlib"] #![crate_type = "rlib"]
#![feature(non_exhaustive)]
pub enum NonExhaustiveVariants { pub enum NonExhaustiveVariants {
#[non_exhaustive] Unit, #[non_exhaustive] Unit,

View file

@ -1,7 +1,5 @@
// run-pass // run-pass
#![feature(non_exhaustive)]
#[non_exhaustive] #[non_exhaustive]
pub enum NonExhaustiveEnum { pub enum NonExhaustiveEnum {
Unit, Unit,

View file

@ -1,5 +1,3 @@
#![feature(non_exhaustive)]
#[non_exhaustive] #[non_exhaustive]
#[repr(C)] #[repr(C)]
pub enum NonExhaustiveEnum { pub enum NonExhaustiveEnum {

View file

@ -1,5 +1,4 @@
// check-pass // check-pass
#![feature(non_exhaustive)]
#![deny(improper_ctypes)] #![deny(improper_ctypes)]
// This test checks that non-exhaustive types with `#[repr(C)]` are considered proper within // This test checks that non-exhaustive types with `#[repr(C)]` are considered proper within

View file

@ -1,5 +1,3 @@
#![feature(non_exhaustive)]
#[non_exhaustive(anything)] #[non_exhaustive(anything)]
//~^ ERROR malformed `non_exhaustive` attribute //~^ ERROR malformed `non_exhaustive` attribute
struct Foo; struct Foo;

Some files were not shown because too many files have changed in this diff Show more