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:
commit
23f890f102
117 changed files with 1862 additions and 1358 deletions
|
@ -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;
|
||||
```
|
|
@ -121,7 +121,7 @@
|
|||
#![feature(hexagon_target_feature)]
|
||||
#![feature(const_int_conversion)]
|
||||
#![feature(const_transmute)]
|
||||
#![feature(non_exhaustive)]
|
||||
#![cfg_attr(bootstrap, feature(non_exhaustive))]
|
||||
#![feature(structural_match)]
|
||||
#![feature(abi_unadjusted)]
|
||||
#![feature(adx_target_feature)]
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#![feature(extern_types)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(optin_builtin_traits)]
|
||||
#![feature(non_exhaustive)]
|
||||
#![cfg_attr(bootstrap, feature(non_exhaustive))]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(specialization)]
|
||||
|
||||
|
|
|
@ -2105,8 +2105,6 @@ on something other than a struct or enum.
|
|||
Examples of erroneous code:
|
||||
|
||||
```compile_fail,E0701
|
||||
# #![feature(non_exhaustive)]
|
||||
|
||||
#[non_exhaustive]
|
||||
trait Foo { }
|
||||
```
|
||||
|
|
|
@ -425,6 +425,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
|
|||
ref lines,
|
||||
ref multibyte_chars,
|
||||
ref non_narrow_chars,
|
||||
ref normalized_pos,
|
||||
} = *self;
|
||||
|
||||
(name_hash as u64).hash_stable(hcx, hasher);
|
||||
|
@ -453,6 +454,12 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
|
|||
for &char_pos in non_narrow_chars.iter() {
|
||||
stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher);
|
||||
}
|
||||
|
||||
normalized_pos.len().hash_stable(hcx, hasher);
|
||||
for &char_pos in normalized_pos.iter() {
|
||||
stable_normalized_pos(char_pos, start_pos).hash_stable(hcx, hasher);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -482,6 +489,18 @@ fn stable_non_narrow_char(swc: ::syntax_pos::NonNarrowChar,
|
|||
(pos.0 - source_file_start.0, width as u32)
|
||||
}
|
||||
|
||||
fn stable_normalized_pos(np: ::syntax_pos::NormalizedPos,
|
||||
source_file_start: ::syntax_pos::BytePos)
|
||||
-> (u32, u32) {
|
||||
let ::syntax_pos::NormalizedPos {
|
||||
pos,
|
||||
diff
|
||||
} = np;
|
||||
|
||||
(pos.0 - source_file_start.0, diff)
|
||||
}
|
||||
|
||||
|
||||
impl<'tcx> HashStable<StableHashingContext<'tcx>> for feature_gate::Features {
|
||||
fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
|
||||
// Unfortunately we cannot exhaustively list fields here, since the
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
#![feature(overlapping_marker_traits)]
|
||||
#![feature(extern_types)]
|
||||
#![feature(nll)]
|
||||
#![feature(non_exhaustive)]
|
||||
#![cfg_attr(bootstrap, feature(non_exhaustive))]
|
||||
#![feature(optin_builtin_traits)]
|
||||
#![feature(option_expect_none)]
|
||||
#![feature(range_is_empty)]
|
||||
|
|
|
@ -15,8 +15,7 @@ use crate::ty::layout::VariantIdx;
|
|||
use crate::ty::print::{FmtPrinter, Printer};
|
||||
use crate::ty::subst::{Subst, SubstsRef};
|
||||
use crate::ty::{
|
||||
self, AdtDef, CanonicalUserTypeAnnotations, Region, Ty, TyCtxt,
|
||||
UserTypeAnnotationIndex,
|
||||
self, AdtDef, CanonicalUserTypeAnnotations, List, Region, Ty, TyCtxt, UserTypeAnnotationIndex,
|
||||
};
|
||||
|
||||
use polonius_engine::Atom;
|
||||
|
@ -1712,15 +1711,17 @@ impl Debug for Statement<'_> {
|
|||
/// A path to a value; something that can be evaluated without
|
||||
/// changing or disturbing program state.
|
||||
#[derive(
|
||||
Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
|
||||
Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, HashStable,
|
||||
)]
|
||||
pub struct Place<'tcx> {
|
||||
pub base: PlaceBase<'tcx>,
|
||||
|
||||
/// projection out of a place (access a field, deref a pointer, etc)
|
||||
pub projection: Box<[PlaceElem<'tcx>]>,
|
||||
pub projection: &'tcx List<PlaceElem<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_serialize::UseSpecializedDecodable for Place<'tcx> {}
|
||||
|
||||
#[derive(
|
||||
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.
|
||||
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.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
static_assert_size!(PlaceElem<'_>, 16);
|
||||
|
@ -1846,50 +1849,11 @@ pub struct PlaceRef<'a, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> Place<'tcx> {
|
||||
// FIXME change this back to a const when projection is a shared slice.
|
||||
//
|
||||
// pub const RETURN_PLACE: Place<'tcx> = Place {
|
||||
// base: PlaceBase::Local(RETURN_PLACE),
|
||||
// projection: &[],
|
||||
// };
|
||||
// FIXME change this to a const fn by also making List::empty a const fn.
|
||||
pub fn return_place() -> Place<'tcx> {
|
||||
Place {
|
||||
base: PlaceBase::Local(RETURN_PLACE),
|
||||
projection: Box::new([]),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn field(self, f: Field, ty: Ty<'tcx>) -> Place<'tcx> {
|
||||
self.elem(ProjectionElem::Field(f, ty))
|
||||
}
|
||||
|
||||
pub fn deref(self) -> Place<'tcx> {
|
||||
self.elem(ProjectionElem::Deref)
|
||||
}
|
||||
|
||||
pub fn downcast(self, adt_def: &'tcx AdtDef, variant_index: VariantIdx) -> Place<'tcx> {
|
||||
self.elem(ProjectionElem::Downcast(
|
||||
Some(adt_def.variants[variant_index].ident.name),
|
||||
variant_index,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn downcast_unnamed(self, variant_index: VariantIdx) -> Place<'tcx> {
|
||||
self.elem(ProjectionElem::Downcast(None, variant_index))
|
||||
}
|
||||
|
||||
pub fn index(self, index: Local) -> Place<'tcx> {
|
||||
self.elem(ProjectionElem::Index(index))
|
||||
}
|
||||
|
||||
pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> {
|
||||
// FIXME(spastorino): revisit this again once projection is not a Box<[T]> anymore
|
||||
let mut projection = self.projection.into_vec();
|
||||
projection.push(elem);
|
||||
|
||||
Place {
|
||||
base: self.base,
|
||||
projection: projection.into_boxed_slice(),
|
||||
projection: List::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1906,15 +1870,15 @@ impl<'tcx> Place<'tcx> {
|
|||
//
|
||||
// FIXME: can we safely swap the semantics of `fn base_local` below in here instead?
|
||||
pub fn local_or_deref_local(&self) -> Option<Local> {
|
||||
match self {
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
match self.as_ref() {
|
||||
PlaceRef {
|
||||
base: &PlaceBase::Local(local),
|
||||
projection: &[],
|
||||
} |
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [ProjectionElem::Deref],
|
||||
} => Some(*local),
|
||||
PlaceRef {
|
||||
base: &PlaceBase::Local(local),
|
||||
projection: &[ProjectionElem::Deref],
|
||||
} => Some(local),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -1922,10 +1886,7 @@ impl<'tcx> Place<'tcx> {
|
|||
/// If this place represents a local variable like `_X` with no
|
||||
/// projections, return `Some(_X)`.
|
||||
pub fn as_local(&self) -> Option<Local> {
|
||||
match self {
|
||||
Place { projection: box [], base: PlaceBase::Local(l) } => Some(*l),
|
||||
_ => None,
|
||||
}
|
||||
self.as_ref().as_local()
|
||||
}
|
||||
|
||||
pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> {
|
||||
|
@ -1940,7 +1901,7 @@ impl From<Local> for Place<'_> {
|
|||
fn from(local: Local) -> Self {
|
||||
Place {
|
||||
base: local.into(),
|
||||
projection: Box::new([]),
|
||||
projection: List::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1969,6 +1930,15 @@ impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// If this place represents a local variable like `_X` with no
|
||||
/// projections, return `Some(_X)`.
|
||||
pub fn as_local(&self) -> Option<Local> {
|
||||
match self {
|
||||
PlaceRef { base: PlaceBase::Local(l), projection: [] } => Some(*l),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Place<'_> {
|
||||
|
@ -3182,6 +3152,17 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceBase<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<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> {
|
||||
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
|
||||
Static {
|
||||
|
|
|
@ -784,6 +784,8 @@ macro_rules! make_mir_visitor {
|
|||
|
||||
macro_rules! visit_place_fns {
|
||||
(mut) => (
|
||||
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
|
||||
|
||||
fn super_place(
|
||||
&mut self,
|
||||
place: &mut Place<'tcx>,
|
||||
|
@ -793,19 +795,21 @@ macro_rules! visit_place_fns {
|
|||
self.visit_place_base(&mut place.base, context, location);
|
||||
|
||||
if let Some(new_projection) = self.process_projection(&place.projection) {
|
||||
place.projection = new_projection;
|
||||
place.projection = self.tcx().intern_place_elems(&new_projection);
|
||||
}
|
||||
}
|
||||
|
||||
fn process_projection(
|
||||
&mut self,
|
||||
projection: &'a [PlaceElem<'tcx>],
|
||||
) -> Option<Box<[PlaceElem<'tcx>]>> {
|
||||
) -> Option<Vec<PlaceElem<'tcx>>> {
|
||||
let mut projection = Cow::Borrowed(projection);
|
||||
|
||||
for i in 0..projection.len() {
|
||||
if let Some(elem) = projection.get(i) {
|
||||
if let Some(elem) = self.process_projection_elem(elem) {
|
||||
// This converts the borrowed projection into `Cow::Owned(_)` and returns a
|
||||
// clone of the projection so we can mutate and reintern later.
|
||||
let vec = projection.to_mut();
|
||||
vec[i] = elem;
|
||||
}
|
||||
|
@ -814,7 +818,7 @@ macro_rules! visit_place_fns {
|
|||
|
||||
match projection {
|
||||
Cow::Borrowed(_) => None,
|
||||
Cow::Owned(vec) => Some(vec.into_boxed_slice()),
|
||||
Cow::Owned(vec) => Some(vec),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,9 +13,9 @@ use rustc_data_structures::fx::FxHashMap;
|
|||
use rustc_serialize::{Decodable, Decoder, Encoder, Encodable, opaque};
|
||||
use std::hash::Hash;
|
||||
use std::intrinsics;
|
||||
use crate::ty::{self, Ty, TyCtxt};
|
||||
use crate::ty::{self, List, Ty, TyCtxt};
|
||||
use crate::ty::subst::SubstsRef;
|
||||
use crate::mir::interpret::Allocation;
|
||||
use crate::mir::{self, interpret::Allocation};
|
||||
use syntax_pos::Span;
|
||||
|
||||
/// The shorthand encoding uses an enum's variant index `usize`
|
||||
|
@ -218,6 +218,18 @@ where
|
|||
Ok(tcx.mk_substs((0..len).map(|_| Decodable::decode(decoder)))?)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn decode_place<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]
|
||||
pub fn decode_region<D>(decoder: &mut D) -> Result<ty::Region<'tcx>, D::Error>
|
||||
where
|
||||
|
@ -413,6 +425,15 @@ macro_rules! implement_ty_decoder {
|
|||
}
|
||||
}
|
||||
|
||||
impl<$($typaram),*> SpecializedDecoder<$crate::mir::Place<'tcx>>
|
||||
for $DecoderName<$($typaram),*> {
|
||||
fn specialized_decode(
|
||||
&mut self
|
||||
) -> Result<$crate::mir::Place<'tcx>, Self::Error> {
|
||||
decode_place(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<$($typaram),*> SpecializedDecoder<ty::Region<'tcx>>
|
||||
for $DecoderName<$($typaram),*> {
|
||||
fn specialized_decode(&mut self) -> Result<ty::Region<'tcx>, Self::Error> {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// ignore-tidy-filelength
|
||||
//! Type context book-keeping.
|
||||
|
||||
use crate::arena::Arena;
|
||||
|
@ -21,7 +22,7 @@ use crate::middle::cstore::EncodedMetadata;
|
|||
use crate::middle::lang_items;
|
||||
use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault};
|
||||
use crate::middle::stability;
|
||||
use crate::mir::{Body, interpret, ProjectionKind, Promoted};
|
||||
use crate::mir::{Body, Field, interpret, Local, Place, PlaceElem, ProjectionKind, Promoted};
|
||||
use crate::mir::interpret::{ConstValue, Allocation, Scalar};
|
||||
use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef, Subst};
|
||||
use crate::ty::ReprOptions;
|
||||
|
@ -106,6 +107,7 @@ pub struct CtxtInterners<'tcx> {
|
|||
goal: InternedSet<'tcx, GoalKind<'tcx>>,
|
||||
goal_list: InternedSet<'tcx, List<Goal<'tcx>>>,
|
||||
projs: InternedSet<'tcx, List<ProjectionKind>>,
|
||||
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
|
||||
const_: InternedSet<'tcx, Const<'tcx>>,
|
||||
}
|
||||
|
||||
|
@ -124,6 +126,7 @@ impl<'tcx> CtxtInterners<'tcx> {
|
|||
goal: Default::default(),
|
||||
goal_list: Default::default(),
|
||||
projs: Default::default(),
|
||||
place_elems: Default::default(),
|
||||
const_: Default::default(),
|
||||
}
|
||||
}
|
||||
|
@ -2142,6 +2145,13 @@ impl<'tcx> Borrow<[ProjectionKind]>
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Borrow<[PlaceElem<'tcx>]>
|
||||
for Interned<'tcx, List<PlaceElem<'tcx>>> {
|
||||
fn borrow(&self) -> &[PlaceElem<'tcx>] {
|
||||
&self.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Borrow<RegionKind> for Interned<'tcx, RegionKind> {
|
||||
fn borrow(&self) -> &RegionKind {
|
||||
&self.0
|
||||
|
@ -2242,7 +2252,8 @@ slice_interners!(
|
|||
predicates: _intern_predicates(Predicate<'tcx>),
|
||||
clauses: _intern_clauses(Clause<'tcx>),
|
||||
goal_list: _intern_goals(Goal<'tcx>),
|
||||
projs: _intern_projs(ProjectionKind)
|
||||
projs: _intern_projs(ProjectionKind),
|
||||
place_elems: _intern_place_elems(PlaceElem<'tcx>)
|
||||
);
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
|
@ -2584,6 +2595,48 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self.mk_ty(Opaque(def_id, substs))
|
||||
}
|
||||
|
||||
pub fn mk_place_field(self, place: Place<'tcx>, f: Field, ty: Ty<'tcx>) -> Place<'tcx> {
|
||||
self.mk_place_elem(place, PlaceElem::Field(f, ty))
|
||||
}
|
||||
|
||||
pub fn mk_place_deref(self, place: Place<'tcx>) -> Place<'tcx> {
|
||||
self.mk_place_elem(place, PlaceElem::Deref)
|
||||
}
|
||||
|
||||
pub fn mk_place_downcast(
|
||||
self,
|
||||
place: Place<'tcx>,
|
||||
adt_def: &'tcx AdtDef,
|
||||
variant_index: VariantIdx,
|
||||
) -> Place<'tcx> {
|
||||
self.mk_place_elem(
|
||||
place,
|
||||
PlaceElem::Downcast(Some(adt_def.variants[variant_index].ident.name), variant_index),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn mk_place_downcast_unnamed(
|
||||
self,
|
||||
place: Place<'tcx>,
|
||||
variant_index: VariantIdx,
|
||||
) -> Place<'tcx> {
|
||||
self.mk_place_elem(place, PlaceElem::Downcast(None, variant_index))
|
||||
}
|
||||
|
||||
pub fn mk_place_index(self, place: Place<'tcx>, index: Local) -> Place<'tcx> {
|
||||
self.mk_place_elem(place, PlaceElem::Index(index))
|
||||
}
|
||||
|
||||
/// This method copies `Place`'s projection, add an element and reintern it. Should not be used
|
||||
/// to build a full `Place` it's just a convenient way to grab a projection and modify it in
|
||||
/// flight.
|
||||
pub fn mk_place_elem(self, place: Place<'tcx>, elem: PlaceElem<'tcx>) -> Place<'tcx> {
|
||||
let mut projection = place.projection.to_vec();
|
||||
projection.push(elem);
|
||||
|
||||
Place { base: place.base, projection: self.intern_place_elems(&projection) }
|
||||
}
|
||||
|
||||
pub fn intern_existential_predicates(self, eps: &[ExistentialPredicate<'tcx>])
|
||||
-> &'tcx List<ExistentialPredicate<'tcx>> {
|
||||
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> {
|
||||
if ts.len() == 0 {
|
||||
List::empty()
|
||||
|
@ -2690,6 +2751,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
iter.intern_with(|xs| self.intern_substs(xs))
|
||||
}
|
||||
|
||||
pub fn mk_place_elems<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,
|
||||
self_ty: Ty<'tcx>,
|
||||
rest: &[GenericArg<'tcx>])
|
||||
|
|
|
@ -191,10 +191,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
|
|||
location: Location) {
|
||||
debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue);
|
||||
|
||||
if let mir::Place {
|
||||
base: mir::PlaceBase::Local(index),
|
||||
projection: box [],
|
||||
} = *place {
|
||||
if let Some(index) = place.as_local() {
|
||||
self.assign(index, location);
|
||||
let decl_span = self.fx.mir.local_decls[index].source_info.span;
|
||||
if !self.fx.rvalue_creates_operand(rvalue, decl_span) {
|
||||
|
|
|
@ -2,7 +2,7 @@ use rustc_index::vec::Idx;
|
|||
use rustc::middle::lang_items;
|
||||
use rustc::ty::{self, Ty, TypeFoldable, Instance};
|
||||
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt};
|
||||
use rustc::mir::{self, Place, PlaceBase, Static, StaticKind};
|
||||
use rustc::mir::{self, PlaceBase, Static, StaticKind};
|
||||
use rustc::mir::interpret::PanicInfo;
|
||||
use rustc_target::abi::call::{ArgType, FnType, PassMode};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
@ -630,30 +630,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
// checked by const-qualification, which also
|
||||
// promotes any complex rvalues to constants.
|
||||
if i == 2 && intrinsic.unwrap().starts_with("simd_shuffle") {
|
||||
match *arg {
|
||||
match arg {
|
||||
// The shuffle array argument is usually not an explicit constant,
|
||||
// but specified directly in the code. This means it gets promoted
|
||||
// and we can then extract the value by evaluating the promoted.
|
||||
mir::Operand::Copy(
|
||||
Place {
|
||||
base: PlaceBase::Static(box Static {
|
||||
mir::Operand::Copy(place) | mir::Operand::Move(place) => {
|
||||
if let mir::PlaceRef {
|
||||
base:
|
||||
&PlaceBase::Static(box Static {
|
||||
kind: StaticKind::Promoted(promoted, _),
|
||||
ty,
|
||||
def_id: _,
|
||||
}),
|
||||
projection: box [],
|
||||
}
|
||||
) |
|
||||
mir::Operand::Move(
|
||||
Place {
|
||||
base: PlaceBase::Static(box Static {
|
||||
kind: StaticKind::Promoted(promoted, _),
|
||||
ty,
|
||||
def_id: _,
|
||||
}),
|
||||
projection: box [],
|
||||
}
|
||||
) => {
|
||||
projection: &[],
|
||||
} = place.as_ref()
|
||||
{
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
let cid = mir::interpret::GlobalId {
|
||||
instance: self.instance,
|
||||
|
@ -670,13 +661,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
val: Immediate(llval),
|
||||
layout: bx.layout_of(ty),
|
||||
};
|
||||
|
||||
}
|
||||
mir::Operand::Copy(_) |
|
||||
mir::Operand::Move(_) => {
|
||||
} else {
|
||||
span_bug!(span, "shuffle indices must be constant");
|
||||
}
|
||||
mir::Operand::Constant(ref constant) => {
|
||||
}
|
||||
|
||||
mir::Operand::Constant(constant) => {
|
||||
let c = self.eval_mir_constant(constant);
|
||||
let (llval, ty) = self.simd_shuffle_indices(
|
||||
&bx,
|
||||
|
@ -1117,10 +1107,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
if fn_ret.is_ignore() {
|
||||
return ReturnDest::Nothing;
|
||||
}
|
||||
let dest = if let mir::Place {
|
||||
base: mir::PlaceBase::Local(index),
|
||||
projection: box [],
|
||||
} = *dest {
|
||||
let dest = if let Some(index) = dest.as_local() {
|
||||
match self.locals[index] {
|
||||
LocalRef::Place(dest) => dest,
|
||||
LocalRef::UnsizedPlace(_) => bug!("return type must be sized"),
|
||||
|
@ -1178,10 +1165,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
src: &mir::Operand<'tcx>,
|
||||
dst: &mir::Place<'tcx>
|
||||
) {
|
||||
if let mir::Place {
|
||||
base: mir::PlaceBase::Local(index),
|
||||
projection: box [],
|
||||
} = *dst {
|
||||
if let Some(index) = dst.as_local() {
|
||||
match self.locals[index] {
|
||||
LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place),
|
||||
LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"),
|
||||
|
|
|
@ -530,10 +530,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
) -> Bx::Value {
|
||||
// ZST are passed as operands and require special handling
|
||||
// because codegen_place() panics if Local is operand.
|
||||
if let mir::Place {
|
||||
base: mir::PlaceBase::Local(index),
|
||||
projection: box [],
|
||||
} = *place {
|
||||
if let Some(index) = place.as_local() {
|
||||
if let LocalRef::Operand(Some(op)) = self.locals[index] {
|
||||
if let ty::Array(_, n) = op.layout.ty.kind {
|
||||
let n = n.eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all());
|
||||
|
|
|
@ -17,11 +17,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
self.set_debug_loc(&mut bx, statement.source_info);
|
||||
match statement.kind {
|
||||
mir::StatementKind::Assign(box(ref place, ref rvalue)) => {
|
||||
if let mir::Place {
|
||||
base: mir::PlaceBase::Local(index),
|
||||
projection: box [],
|
||||
} = place {
|
||||
match self.locals[*index] {
|
||||
if let Some(index) = place.as_local() {
|
||||
match self.locals[index] {
|
||||
LocalRef::Place(cg_dest) => {
|
||||
self.codegen_rvalue(bx, cg_dest, rvalue)
|
||||
}
|
||||
|
@ -30,7 +27,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
LocalRef::Operand(None) => {
|
||||
let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue);
|
||||
if let Some(name) = self.mir.local_decls[*index].name {
|
||||
if let Some(name) = self.mir.local_decls[index].name {
|
||||
match operand.val {
|
||||
OperandValue::Ref(x, ..) |
|
||||
OperandValue::Immediate(x) => {
|
||||
|
@ -44,7 +41,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
self.locals[*index] = LocalRef::Operand(Some(operand));
|
||||
self.locals[index] = LocalRef::Operand(Some(operand));
|
||||
bx
|
||||
}
|
||||
LocalRef::Operand(Some(op)) => {
|
||||
|
|
|
@ -1319,6 +1319,7 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
mut lines,
|
||||
mut multibyte_chars,
|
||||
mut non_narrow_chars,
|
||||
mut normalized_pos,
|
||||
name_hash,
|
||||
.. } = source_file_to_import;
|
||||
|
||||
|
@ -1338,6 +1339,9 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
for swc in &mut non_narrow_chars {
|
||||
*swc = *swc - start_pos;
|
||||
}
|
||||
for np in &mut normalized_pos {
|
||||
np.pos = np.pos - start_pos;
|
||||
}
|
||||
|
||||
let local_version = local_source_map.new_imported_source_file(name,
|
||||
name_was_remapped,
|
||||
|
@ -1347,7 +1351,8 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
source_length,
|
||||
lines,
|
||||
multibyte_chars,
|
||||
non_narrow_chars);
|
||||
non_narrow_chars,
|
||||
normalized_pos);
|
||||
debug!("CrateMetaData::imported_source_files alloc \
|
||||
source_file {:?} original (start_pos {:?} end_pos {:?}) \
|
||||
translated (start_pos {:?} end_pos {:?})",
|
||||
|
|
|
@ -315,10 +315,7 @@ impl<'a, 'tcx> GatherBorrows<'a, 'tcx> {
|
|||
// TEMP = &foo
|
||||
//
|
||||
// so extract `temp`.
|
||||
let temp = if let &mir::Place {
|
||||
base: mir::PlaceBase::Local(temp),
|
||||
projection: box [],
|
||||
} = assigned_place {
|
||||
let temp = if let Some(temp) = assigned_place.as_local() {
|
||||
temp
|
||||
} else {
|
||||
span_bug!(
|
||||
|
|
|
@ -239,11 +239,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
);
|
||||
}
|
||||
}
|
||||
let span = if let Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
} = place {
|
||||
let decl = &self.body.local_decls[*local];
|
||||
let span = if let Some(local) = place.as_local() {
|
||||
let decl = &self.body.local_decls[local];
|
||||
Some(decl.source_info.span)
|
||||
} else {
|
||||
None
|
||||
|
@ -611,7 +608,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
projection,
|
||||
} = first_borrowed_place;
|
||||
|
||||
let mut cursor = &**projection;
|
||||
let mut cursor = projection.as_ref();
|
||||
while let [proj_base @ .., elem] = cursor {
|
||||
cursor = proj_base;
|
||||
|
||||
|
@ -635,7 +632,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
projection,
|
||||
} = second_borrowed_place;
|
||||
|
||||
let mut cursor = &**projection;
|
||||
let mut cursor = projection.as_ref();
|
||||
while let [proj_base @ .., elem] = cursor {
|
||||
cursor = proj_base;
|
||||
|
||||
|
@ -710,10 +707,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
_ => drop_span,
|
||||
};
|
||||
|
||||
let root_place_projection = self.infcx.tcx.intern_place_elems(root_place.projection);
|
||||
|
||||
if self.access_place_error_reported
|
||||
.contains(&(Place {
|
||||
base: root_place.base.clone(),
|
||||
projection: root_place.projection.to_vec().into_boxed_slice(),
|
||||
projection: root_place_projection,
|
||||
}, borrow_span))
|
||||
{
|
||||
debug!(
|
||||
|
@ -726,7 +725,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
self.access_place_error_reported
|
||||
.insert((Place {
|
||||
base: root_place.base.clone(),
|
||||
projection: root_place.projection.to_vec().into_boxed_slice(),
|
||||
projection: root_place_projection,
|
||||
}, borrow_span));
|
||||
|
||||
if let StorageDeadOrDrop::Destructor(dropped_ty) =
|
||||
|
@ -1124,11 +1123,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
};
|
||||
|
||||
let (place_desc, note) = if let Some(place_desc) = opt_place_desc {
|
||||
let local_kind = match borrow.borrowed_place {
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
} => {
|
||||
let local_kind = if let Some(local) = borrow.borrowed_place.as_local() {
|
||||
match self.body.local_kind(local) {
|
||||
LocalKind::ReturnPointer
|
||||
| LocalKind::Temp => bug!("temporary or return pointer with a name"),
|
||||
|
@ -1142,8 +1137,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
"function parameter "
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => "local data ",
|
||||
} else {
|
||||
"local data "
|
||||
};
|
||||
(
|
||||
format!("{}`{}`", local_kind, place_desc),
|
||||
|
@ -1480,10 +1475,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
assigned_span: Span,
|
||||
err_place: &Place<'tcx>,
|
||||
) {
|
||||
let (from_arg, local_decl) = if let Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
} = *err_place {
|
||||
let (from_arg, local_decl) = if let Some(local) = err_place.as_local() {
|
||||
if let LocalKind::Arg = self.body.local_kind(local) {
|
||||
(true, Some(&self.body.local_decls[local]))
|
||||
} else {
|
||||
|
@ -1643,11 +1635,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
reservation
|
||||
);
|
||||
// Check that the initial assignment of the reserve location is into a temporary.
|
||||
let mut target = *match reservation {
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
} if self.body.local_kind(*local) == LocalKind::Temp => local,
|
||||
let mut target = match reservation.as_local() {
|
||||
Some(local) if self.body.local_kind(local) == LocalKind::Temp => local,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
|
@ -1659,15 +1648,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
"annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
|
||||
target, stmt
|
||||
);
|
||||
if let StatementKind::Assign(
|
||||
box(
|
||||
Place {
|
||||
base: PlaceBase::Local(assigned_to),
|
||||
projection: box [],
|
||||
},
|
||||
rvalue
|
||||
)
|
||||
) = &stmt.kind {
|
||||
if let StatementKind::Assign(box(place, rvalue)) = &stmt.kind {
|
||||
if let Some(assigned_to) = place.as_local() {
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_to={:?} \
|
||||
rvalue={:?}",
|
||||
|
@ -1692,7 +1674,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
);
|
||||
|
||||
// Find the local from the operand.
|
||||
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,
|
||||
None => continue,
|
||||
};
|
||||
|
@ -1715,13 +1698,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
annotated_closure, assigned_from_local, assigned_to
|
||||
);
|
||||
|
||||
if *assigned_to == mir::RETURN_PLACE {
|
||||
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;
|
||||
target = assigned_to;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1771,7 +1754,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
assigned_from_local={:?} assigned_to={:?}",
|
||||
assigned_from_local, assigned_to
|
||||
);
|
||||
if *assigned_to == mir::RETURN_PLACE {
|
||||
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);
|
||||
|
@ -1779,7 +1762,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
// If we didn't assign into the return place, then we just update
|
||||
// the target.
|
||||
target = *assigned_to;
|
||||
target = assigned_to;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1790,14 +1774,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
target, terminator
|
||||
);
|
||||
if let TerminatorKind::Call {
|
||||
destination: Some((Place {
|
||||
base: PlaceBase::Local(assigned_to),
|
||||
projection: box [],
|
||||
}, _)),
|
||||
destination: Some((place, _)),
|
||||
args,
|
||||
..
|
||||
} = &terminator.kind
|
||||
{
|
||||
if let Some(assigned_to) = place.as_local() {
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
|
||||
assigned_to, args
|
||||
|
@ -1820,13 +1802,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
assigned_from_local,
|
||||
);
|
||||
|
||||
if *assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
|
||||
if assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
|
||||
return annotated_closure.or_else(fallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we haven't found an assignment into the return place, then we need not add
|
||||
// any annotations.
|
||||
|
|
|
@ -838,12 +838,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
.get(location.statement_index)
|
||||
{
|
||||
Some(&Statement {
|
||||
kind: StatementKind::Assign(box(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
}, _)),
|
||||
kind: StatementKind::Assign(box(ref place, _)),
|
||||
..
|
||||
}) => local,
|
||||
}) => {
|
||||
if let Some(local) = place.as_local() {
|
||||
local
|
||||
} else {
|
||||
return OtherUse(use_span);
|
||||
}
|
||||
}
|
||||
_ => return OtherUse(use_span),
|
||||
};
|
||||
|
||||
|
|
|
@ -1133,15 +1133,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// Special case: you can assign a immutable local variable
|
||||
// (e.g., `x = ...`) so long as it has never been initialized
|
||||
// before (at this point in the flow).
|
||||
if let Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
} = place_span.0 {
|
||||
if let Mutability::Not = self.body.local_decls[*local].mutability {
|
||||
if let Some(local) = place_span.0.as_local() {
|
||||
if let Mutability::Not = self.body.local_decls[local].mutability {
|
||||
// check for reassignments to immutable local variables
|
||||
self.check_if_reassignment_to_immutable_state(
|
||||
location,
|
||||
*local,
|
||||
local,
|
||||
place_span,
|
||||
flow_state,
|
||||
);
|
||||
|
@ -1288,14 +1285,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// captures of a closure are copied/moved directly
|
||||
// when generating MIR.
|
||||
match *operand {
|
||||
Operand::Move(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
}) |
|
||||
Operand::Copy(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
}) if self.body.local_decls[local].is_user_variable.is_none() => {
|
||||
Operand::Move(ref place) | Operand::Copy(ref place) => {
|
||||
match place.as_local() {
|
||||
Some(local) if self.body.local_decls[local].is_user_variable.is_none() => {
|
||||
if self.body.local_decls[local].ty.is_mutable_ptr() {
|
||||
// The variable will be marked as mutable by the borrow.
|
||||
return;
|
||||
|
@ -1331,16 +1323,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let stmt = &bbd.statements[loc.statement_index];
|
||||
debug!("temporary assigned in: stmt={:?}", stmt);
|
||||
|
||||
if let StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref source))) = stmt.kind {
|
||||
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");
|
||||
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);
|
||||
_ => propagate_closure_used_mut_place(self, place),
|
||||
}
|
||||
}
|
||||
Operand::Constant(..) => {}
|
||||
}
|
||||
|
@ -1702,7 +1697,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
debug!("check_if_assigned_path_is_moved place: {:?}", place);
|
||||
|
||||
// None case => assigning to `x` does not require `x` be initialized.
|
||||
let mut cursor = &*place.projection;
|
||||
let mut cursor = &*place.projection.as_ref();
|
||||
while let [proj_base @ .., elem] = cursor {
|
||||
cursor = proj_base;
|
||||
|
||||
|
|
|
@ -89,19 +89,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
// If that ever stops being the case, then the ever initialized
|
||||
// flow could be used.
|
||||
if let Some(StatementKind::Assign(
|
||||
box(
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
},
|
||||
Rvalue::Use(Operand::Move(move_from))
|
||||
)
|
||||
box(place, Rvalue::Use(Operand::Move(move_from)))
|
||||
)) = self.body.basic_blocks()[location.block]
|
||||
.statements
|
||||
.get(location.statement_index)
|
||||
.map(|stmt| &stmt.kind)
|
||||
{
|
||||
let local_decl = &self.body.local_decls[*local];
|
||||
if let Some(local) = place.as_local() {
|
||||
let local_decl = &self.body.local_decls[local];
|
||||
// opt_match_place is the
|
||||
// match_span is the span of the expression being matched on
|
||||
// match *x.y { ... } match_place is Some(*x.y)
|
||||
|
@ -122,7 +117,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
kind,
|
||||
original_path,
|
||||
move_from,
|
||||
*local,
|
||||
local,
|
||||
opt_match_place,
|
||||
match_span,
|
||||
stmt_source_info.span,
|
||||
|
@ -130,6 +125,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let move_spans = self.move_spans(original_path.as_ref(), location);
|
||||
grouped_errors.push(GroupedMoveError::OtherIllegalMove {
|
||||
|
@ -307,11 +303,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All)
|
||||
.find_map(|p| self.is_upvar_field_projection(p));
|
||||
|
||||
let deref_base = match &deref_target_place.projection {
|
||||
box [proj_base @ .., ProjectionElem::Deref] => {
|
||||
let deref_base = match deref_target_place.projection.as_ref() {
|
||||
&[ref proj_base @ .., ProjectionElem::Deref] => {
|
||||
PlaceRef {
|
||||
base: &deref_target_place.base,
|
||||
projection: proj_base,
|
||||
projection: &proj_base,
|
||||
}
|
||||
}
|
||||
_ => bug!("deref_target_place is not a deref projection"),
|
||||
|
|
|
@ -49,10 +49,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
projection: [],
|
||||
} => {
|
||||
item_msg = format!("`{}`", access_place_desc.unwrap());
|
||||
if let Place {
|
||||
base: PlaceBase::Local(_),
|
||||
projection: box [],
|
||||
} = access_place {
|
||||
if access_place.as_local().is_some() {
|
||||
reason = ", as it is not declared as mutable".to_string();
|
||||
} else {
|
||||
let name = self.body.local_decls[*local]
|
||||
|
@ -153,10 +150,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}),
|
||||
projection: [],
|
||||
} => {
|
||||
if let Place {
|
||||
base: PlaceBase::Static(_),
|
||||
projection: box [],
|
||||
} = access_place {
|
||||
if let PlaceRef {
|
||||
base: &PlaceBase::Static(_),
|
||||
projection: &[],
|
||||
} = access_place.as_ref() {
|
||||
item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
|
||||
reason = String::new();
|
||||
} else {
|
||||
|
|
|
@ -8,8 +8,8 @@ use rustc::infer::InferCtxt;
|
|||
use rustc::mir::visit::TyContext;
|
||||
use rustc::mir::visit::Visitor;
|
||||
use rustc::mir::{
|
||||
BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, ProjectionElem, Rvalue,
|
||||
SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
|
||||
BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, PlaceRef, ProjectionElem,
|
||||
Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
|
||||
};
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::{self, RegionVid, Ty};
|
||||
|
@ -211,14 +211,14 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
|
|||
// - if it's a deeper projection, we have to filter which
|
||||
// of the borrows are killed: the ones whose `borrowed_place`
|
||||
// conflicts with the `place`.
|
||||
match place {
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
match place.as_ref() {
|
||||
PlaceRef {
|
||||
base: &PlaceBase::Local(local),
|
||||
projection: &[],
|
||||
} |
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [ProjectionElem::Deref],
|
||||
PlaceRef {
|
||||
base: &PlaceBase::Local(local),
|
||||
projection: &[ProjectionElem::Deref],
|
||||
} => {
|
||||
debug!(
|
||||
"Recording `killed` facts for borrows of local={:?} at location={:?}",
|
||||
|
@ -229,21 +229,21 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
|
|||
all_facts,
|
||||
self.borrow_set,
|
||||
self.location_table,
|
||||
local,
|
||||
&local,
|
||||
location,
|
||||
);
|
||||
}
|
||||
|
||||
Place {
|
||||
base: PlaceBase::Static(_),
|
||||
PlaceRef {
|
||||
base: &PlaceBase::Static(_),
|
||||
..
|
||||
} => {
|
||||
// Ignore kills of static or static mut variables.
|
||||
}
|
||||
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [.., _],
|
||||
PlaceRef {
|
||||
base: &PlaceBase::Local(local),
|
||||
projection: &[.., _],
|
||||
} => {
|
||||
// Kill conflicting borrows of the innermost local.
|
||||
debug!(
|
||||
|
@ -252,7 +252,7 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
|
|||
local, location
|
||||
);
|
||||
|
||||
if let Some(borrow_indices) = self.borrow_set.local_map.get(local) {
|
||||
if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) {
|
||||
for &borrow_index in borrow_indices {
|
||||
let places_conflict = places_conflict::places_conflict(
|
||||
self.infcx.tcx,
|
||||
|
|
|
@ -6,8 +6,8 @@ use crate::borrow_check::nll::region_infer::{Cause, RegionName};
|
|||
use crate::borrow_check::nll::ConstraintDescription;
|
||||
use crate::borrow_check::{MirBorrowckCtxt, WriteKind};
|
||||
use rustc::mir::{
|
||||
CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, PlaceBase,
|
||||
Rvalue, Statement, StatementKind, TerminatorKind,
|
||||
CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, Rvalue,
|
||||
Statement, StatementKind, TerminatorKind,
|
||||
};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::ty::adjustment::{PointerCast};
|
||||
|
@ -273,12 +273,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let mut should_note_order = false;
|
||||
if body.local_decls[local].name.is_some() {
|
||||
if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
|
||||
if let Place {
|
||||
base: PlaceBase::Local(borrowed_local),
|
||||
projection: box [],
|
||||
} = place {
|
||||
if body.local_decls[*borrowed_local].name.is_some()
|
||||
&& local != *borrowed_local
|
||||
if let Some(borrowed_local) = place.as_local() {
|
||||
if body.local_decls[borrowed_local].name.is_some()
|
||||
&& local != borrowed_local
|
||||
{
|
||||
should_note_order = true;
|
||||
}
|
||||
|
@ -494,22 +491,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// Just point to the function, to reduce the chance of overlapping spans.
|
||||
let function_span = match func {
|
||||
Operand::Constant(c) => c.span,
|
||||
Operand::Copy(Place {
|
||||
base: PlaceBase::Local(l),
|
||||
projection: box [],
|
||||
}) |
|
||||
Operand::Move(Place {
|
||||
base: PlaceBase::Local(l),
|
||||
projection: box [],
|
||||
}) => {
|
||||
let local_decl = &self.body.local_decls[*l];
|
||||
Operand::Copy(place) |
|
||||
Operand::Move(place) => {
|
||||
if let Some(l) = place.as_local() {
|
||||
let local_decl = &self.body.local_decls[l];
|
||||
if local_decl.name.is_none() {
|
||||
local_decl.source_info.span
|
||||
} else {
|
||||
span
|
||||
}
|
||||
} else {
|
||||
span
|
||||
}
|
||||
}
|
||||
_ => span,
|
||||
};
|
||||
return (LaterUseKind::Call, function_span);
|
||||
} else {
|
||||
|
@ -542,16 +536,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// it which simplifies the termination logic.
|
||||
let mut queue = vec![location];
|
||||
let mut target = if let Some(&Statement {
|
||||
kind: StatementKind::Assign(box(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
}, _)),
|
||||
kind: StatementKind::Assign(box(ref place, _)),
|
||||
..
|
||||
}) = stmt
|
||||
{
|
||||
}) = stmt {
|
||||
if let Some(local) = place.as_local() {
|
||||
local
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
|
||||
debug!(
|
||||
|
@ -582,18 +576,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// If we see a use, we should check whether it is our data, and if so
|
||||
// update the place that we're looking for to that new place.
|
||||
Rvalue::Use(operand) => match operand {
|
||||
Operand::Copy(Place {
|
||||
base: PlaceBase::Local(from),
|
||||
projection: box [],
|
||||
})
|
||||
| Operand::Move(Place {
|
||||
base: PlaceBase::Local(from),
|
||||
projection: box [],
|
||||
})
|
||||
if *from == target =>
|
||||
{
|
||||
Operand::Copy(place)
|
||||
| Operand::Move(place) => {
|
||||
if let Some(from) = place.as_local() {
|
||||
if from == target {
|
||||
target = into;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
// If we see a unsized cast, then if it is our data we should check
|
||||
|
@ -601,16 +591,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
Rvalue::Cast(
|
||||
CastKind::Pointer(PointerCast::Unsize), operand, ty
|
||||
) => match operand {
|
||||
Operand::Copy(Place {
|
||||
base: PlaceBase::Local(from),
|
||||
projection: box [],
|
||||
})
|
||||
| Operand::Move(Place {
|
||||
base: PlaceBase::Local(from),
|
||||
projection: box [],
|
||||
})
|
||||
if *from == target =>
|
||||
{
|
||||
Operand::Copy(place)
|
||||
| Operand::Move(place) => {
|
||||
if let Some(from) = place.as_local() {
|
||||
if from == target {
|
||||
debug!("was_captured_by_trait_object: ty={:?}", ty);
|
||||
// Check the type for a trait object.
|
||||
return match ty.kind {
|
||||
|
@ -624,6 +608,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
_ => false,
|
||||
};
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
_ => return false,
|
||||
},
|
||||
_ => {}
|
||||
|
@ -638,25 +625,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
debug!("was_captured_by_trait_object: terminator={:?}", terminator);
|
||||
|
||||
if let TerminatorKind::Call {
|
||||
destination: Some((Place {
|
||||
base: PlaceBase::Local(dest),
|
||||
projection: box [],
|
||||
}, block)),
|
||||
destination: Some((place, block)),
|
||||
args,
|
||||
..
|
||||
} = &terminator.kind
|
||||
{
|
||||
} = &terminator.kind {
|
||||
if let Some(dest) = place.as_local() {
|
||||
debug!(
|
||||
"was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
|
||||
target, dest, args
|
||||
);
|
||||
// Check if one of the arguments to this function is the target place.
|
||||
let found_target = args.iter().any(|arg| {
|
||||
if let Operand::Move(Place {
|
||||
base: PlaceBase::Local(potential),
|
||||
projection: box [],
|
||||
}) = arg {
|
||||
*potential == target
|
||||
if let Operand::Move(place) = arg {
|
||||
if let Some(potential) = place.as_local() {
|
||||
potential == target
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
@ -664,11 +649,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
// If it is, follow this to the next block and update the target.
|
||||
if found_target {
|
||||
target = *dest;
|
||||
target = dest;
|
||||
queue.push(block.start_location());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("was_captured_by_trait: queue={:?}", queue);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use rustc::ty::subst::SubstsRef;
|
||||
use rustc::ty::{self, Ty, TypeFoldable};
|
||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc::mir::{Body, Location, PlaceElem, Promoted};
|
||||
use rustc::mir::visit::{MutVisitor, TyContext};
|
||||
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
|
||||
|
@ -54,6 +54,10 @@ impl<'a, 'tcx> NLLVisitor<'a, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
|
||||
debug!("visit_ty(ty={:?}, ty_context={:?})", ty, ty_context);
|
||||
|
||||
|
|
|
@ -480,13 +480,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
|
||||
if place.projection.is_empty() {
|
||||
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
|
||||
let is_promoted = match place {
|
||||
Place {
|
||||
base: PlaceBase::Static(box Static {
|
||||
let is_promoted = match place.as_ref() {
|
||||
PlaceRef {
|
||||
base: &PlaceBase::Static(box Static {
|
||||
kind: StaticKind::Promoted(..),
|
||||
..
|
||||
}),
|
||||
projection: box [],
|
||||
projection: &[],
|
||||
} => true,
|
||||
_ => false,
|
||||
};
|
||||
|
@ -1366,11 +1366,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
// they are not caused by the user, but rather artifacts
|
||||
// of lowering. Assignments to other sorts of places *are* interesting
|
||||
// though.
|
||||
let category = match *place {
|
||||
Place {
|
||||
base: PlaceBase::Local(RETURN_PLACE),
|
||||
projection: box [],
|
||||
} => if let BorrowCheckContext {
|
||||
let category = match place.as_local() {
|
||||
Some(RETURN_PLACE) => if let BorrowCheckContext {
|
||||
universal_regions:
|
||||
UniversalRegions {
|
||||
defining_ty: DefiningTy::Const(def_id, _),
|
||||
|
@ -1386,10 +1383,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
} else {
|
||||
ConstraintCategory::Return
|
||||
},
|
||||
Place {
|
||||
base: PlaceBase::Local(l),
|
||||
projection: box [],
|
||||
} if !body.local_decls[l].is_user_variable.is_some() => {
|
||||
Some(l) if !body.local_decls[l].is_user_variable.is_some() => {
|
||||
ConstraintCategory::Boring
|
||||
}
|
||||
_ => ConstraintCategory::Assignment,
|
||||
|
@ -1675,11 +1669,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
Some((ref dest, _target_block)) => {
|
||||
let dest_ty = dest.ty(body, tcx).ty;
|
||||
let dest_ty = self.normalize(dest_ty, term_location);
|
||||
let category = match *dest {
|
||||
Place {
|
||||
base: PlaceBase::Local(RETURN_PLACE),
|
||||
projection: box [],
|
||||
} => {
|
||||
let category = match dest.as_local() {
|
||||
Some(RETURN_PLACE) => {
|
||||
if let BorrowCheckContext {
|
||||
universal_regions:
|
||||
UniversalRegions {
|
||||
|
@ -1698,10 +1689,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
ConstraintCategory::Return
|
||||
}
|
||||
}
|
||||
Place {
|
||||
base: PlaceBase::Local(l),
|
||||
projection: box [],
|
||||
} if !body.local_decls[l].is_user_variable.is_some() => {
|
||||
Some(l) if !body.local_decls[l].is_user_variable.is_some() => {
|
||||
ConstraintCategory::Boring
|
||||
}
|
||||
_ => ConstraintCategory::Assignment,
|
||||
|
@ -2432,7 +2420,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
location, borrow_region, borrowed_place
|
||||
);
|
||||
|
||||
let mut cursor = &*borrowed_place.projection;
|
||||
let mut cursor = borrowed_place.projection.as_ref();
|
||||
while let [proj_base @ .., elem] = cursor {
|
||||
cursor = proj_base;
|
||||
|
||||
|
|
|
@ -64,14 +64,8 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
|
|||
|
||||
// This Local/Local case is handled by the more general code below, but
|
||||
// it's so common that it's a speed win to check for it first.
|
||||
if let Place {
|
||||
base: PlaceBase::Local(l1),
|
||||
projection: box [],
|
||||
} = borrow_place {
|
||||
if let PlaceRef {
|
||||
base: PlaceBase::Local(l2),
|
||||
projection: [],
|
||||
} = access_place {
|
||||
if let Some(l1) = borrow_place.as_local() {
|
||||
if let Some(l2) = access_place.as_local() {
|
||||
return l1 == l2;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
use rustc::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc::mir::{
|
||||
Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind
|
||||
};
|
||||
use rustc::mir::{Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind};
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
||||
|
@ -118,10 +116,7 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc
|
|||
"assignment of {:?} to {:?}, adding {:?} to used mutable set",
|
||||
path.place, local, path.place
|
||||
);
|
||||
if let Place {
|
||||
base: PlaceBase::Local(user_local),
|
||||
projection: box [],
|
||||
} = path.place {
|
||||
if let Some(user_local) = path.place.as_local() {
|
||||
self.mbcx.used_mut.insert(user_local);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::build::{BlockAnd, BlockAndExtension, Builder};
|
|||
use crate::hair::*;
|
||||
use rustc::mir::interpret::{PanicInfo::BoundsCheck};
|
||||
use rustc::mir::*;
|
||||
use rustc::ty::{CanonicalUserTypeAnnotation, Ty, Variance};
|
||||
use rustc::ty::{CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance};
|
||||
|
||||
use rustc_index::vec::Idx;
|
||||
|
||||
|
@ -23,10 +23,10 @@ struct PlaceBuilder<'tcx> {
|
|||
}
|
||||
|
||||
impl PlaceBuilder<'tcx> {
|
||||
fn into_place(self) -> Place<'tcx> {
|
||||
fn into_place(self, tcx: TyCtxt<'tcx>) -> Place<'tcx> {
|
||||
Place {
|
||||
base: self.base,
|
||||
projection: self.projection.into_boxed_slice(),
|
||||
projection: tcx.intern_place_elems(&self.projection),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
||||
{
|
||||
let place_builder = unpack!(block = self.as_place_builder(block, expr));
|
||||
block.and(place_builder.into_place())
|
||||
block.and(place_builder.into_place(self.hir.tcx()))
|
||||
}
|
||||
|
||||
/// This is used when constructing a compound `Place`, so that we can avoid creating
|
||||
|
@ -96,7 +96,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
||||
{
|
||||
let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
|
||||
block.and(place_builder.into_place())
|
||||
block.and(place_builder.into_place(self.hir.tcx()))
|
||||
}
|
||||
|
||||
/// This is used when constructing a compound `Place`, so that we can avoid creating
|
||||
|
@ -165,7 +165,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
Mutability::Not,
|
||||
));
|
||||
|
||||
let slice = place_builder.clone().into_place();
|
||||
let slice = place_builder.clone().into_place(this.hir.tcx());
|
||||
// bounds check:
|
||||
let (len, lt) = (
|
||||
this.temp(usize_ty.clone(), expr_span),
|
||||
|
@ -225,7 +225,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
);
|
||||
|
||||
let place = place_builder.clone().into_place();
|
||||
let place = place_builder.clone().into_place(this.hir.tcx());
|
||||
this.cfg.push(
|
||||
block,
|
||||
Statement {
|
||||
|
|
|
@ -139,7 +139,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
// initialize the box contents:
|
||||
unpack!(
|
||||
block = this.into(
|
||||
&Place::from(result).deref(),
|
||||
&this.hir.tcx().mk_place_deref(Place::from(result)),
|
||||
block, value
|
||||
)
|
||||
);
|
||||
|
@ -296,8 +296,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
.zip(field_types.into_iter())
|
||||
.map(|(n, ty)| match fields_map.get(&n) {
|
||||
Some(v) => v.clone(),
|
||||
None => this.consume_by_copy_or_move(base.clone().field(n, ty)),
|
||||
}).collect()
|
||||
None => this.consume_by_copy_or_move(this.hir.tcx().mk_place_field(
|
||||
base.clone(),
|
||||
n,
|
||||
ty,
|
||||
)),
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
field_names
|
||||
.iter()
|
||||
|
@ -397,8 +402,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let val_fld = Field::new(0);
|
||||
let of_fld = Field::new(1);
|
||||
|
||||
let val = result_value.clone().field(val_fld, ty);
|
||||
let of = result_value.field(of_fld, bool_ty);
|
||||
let tcx = self.hir.tcx();
|
||||
let val = tcx.mk_place_field(result_value.clone(), val_fld, ty);
|
||||
let of = tcx.mk_place_field(result_value, of_fld, bool_ty);
|
||||
|
||||
let err = PanicInfo::Overflow(op);
|
||||
|
||||
|
@ -496,14 +502,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
let arg_place = unpack!(block = this.as_place(block, arg));
|
||||
|
||||
let mutability = match arg_place {
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
let mutability = match arg_place.as_ref() {
|
||||
PlaceRef {
|
||||
base: &PlaceBase::Local(local),
|
||||
projection: &[],
|
||||
} => this.local_decls[local].mutability,
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [ProjectionElem::Deref],
|
||||
PlaceRef {
|
||||
base: &PlaceBase::Local(local),
|
||||
projection: &[ProjectionElem::Deref],
|
||||
} => {
|
||||
debug_assert!(
|
||||
this.local_decls[local].is_ref_for_guard(),
|
||||
|
@ -511,13 +517,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
);
|
||||
this.local_decls[local].mutability
|
||||
}
|
||||
Place {
|
||||
PlaceRef {
|
||||
ref base,
|
||||
projection: box [ref proj_base @ .., ProjectionElem::Field(upvar_index, _)],
|
||||
projection: &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _)],
|
||||
}
|
||||
| Place {
|
||||
| PlaceRef {
|
||||
ref base,
|
||||
projection: box [
|
||||
projection: &[
|
||||
ref proj_base @ ..,
|
||||
ProjectionElem::Field(upvar_index, _),
|
||||
ProjectionElem::Deref
|
||||
|
|
|
@ -235,7 +235,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
});
|
||||
let ptr_temp = Place::from(ptr_temp);
|
||||
let block = unpack!(this.into(&ptr_temp, block, ptr));
|
||||
this.into(&ptr_temp.deref(), block, val)
|
||||
this.into(&this.hir.tcx().mk_place_deref(ptr_temp), block, val)
|
||||
} else {
|
||||
let args: Vec<_> = args
|
||||
.into_iter()
|
||||
|
|
|
@ -948,7 +948,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
fake_borrows.insert(Place {
|
||||
base: source.base.clone(),
|
||||
projection: proj_base.to_vec().into_boxed_slice(),
|
||||
projection: self.hir.tcx().intern_place_elems(proj_base),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1293,7 +1293,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
// Insert a Shallow borrow of the prefixes of any fake borrows.
|
||||
for place in fake_borrows
|
||||
{
|
||||
let mut cursor = &*place.projection;
|
||||
let mut cursor = place.projection.as_ref();
|
||||
while let [proj_base @ .., elem] = cursor {
|
||||
cursor = proj_base;
|
||||
|
||||
|
@ -1488,7 +1488,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
BorrowKind::Shallow,
|
||||
Place {
|
||||
base: place.base.clone(),
|
||||
projection: place.projection.to_vec().into_boxed_slice(),
|
||||
projection: tcx.intern_place_elems(place.projection),
|
||||
},
|
||||
);
|
||||
self.cfg.push_assign(
|
||||
|
|
|
@ -166,7 +166,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
});
|
||||
if irrefutable {
|
||||
let place = match_pair.place.downcast(adt_def, variant_index);
|
||||
let place = tcx.mk_place_downcast(match_pair.place, adt_def, variant_index);
|
||||
candidate.match_pairs.extend(self.field_match_pairs(place, subpatterns));
|
||||
Ok(())
|
||||
} else {
|
||||
|
@ -191,7 +191,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
|
||||
PatKind::Deref { ref subpattern } => {
|
||||
let place = match_pair.place.deref();
|
||||
let place = tcx.mk_place_deref(match_pair.place);
|
||||
candidate.match_pairs.push(MatchPair::new(place, subpattern));
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -743,19 +743,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
candidate: &mut Candidate<'pat, 'tcx>,
|
||||
) {
|
||||
let match_pair = candidate.match_pairs.remove(match_pair_index);
|
||||
let tcx = self.hir.tcx();
|
||||
|
||||
// So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
|
||||
// we want to create a set of derived match-patterns like
|
||||
// `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
|
||||
let elem = ProjectionElem::Downcast(
|
||||
Some(adt_def.variants[variant_index].ident.name), variant_index);
|
||||
let downcast_place = match_pair.place.elem(elem); // `(x as Variant)`
|
||||
let consequent_match_pairs =
|
||||
subpatterns.iter()
|
||||
.map(|subpattern| {
|
||||
let downcast_place = tcx.mk_place_elem(match_pair.place, elem); // `(x as Variant)`
|
||||
let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
|
||||
// e.g., `(x as Variant).0`
|
||||
let place = downcast_place.clone().field(subpattern.field,
|
||||
subpattern.pattern.ty);
|
||||
let place =
|
||||
tcx.mk_place_field(downcast_place.clone(), subpattern.field, subpattern.pattern.ty);
|
||||
// e.g., `(x as Variant).0 @ P1`
|
||||
MatchPair::new(place, &subpattern.pattern)
|
||||
});
|
||||
|
|
|
@ -6,14 +6,19 @@ use std::u32;
|
|||
use std::convert::TryInto;
|
||||
|
||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
pub fn field_match_pairs<'pat>(&mut self,
|
||||
pub fn field_match_pairs<'pat>(
|
||||
&mut self,
|
||||
place: Place<'tcx>,
|
||||
subpatterns: &'pat [FieldPat<'tcx>])
|
||||
-> Vec<MatchPair<'pat, 'tcx>> {
|
||||
subpatterns.iter()
|
||||
subpatterns: &'pat [FieldPat<'tcx>],
|
||||
) -> Vec<MatchPair<'pat, 'tcx>> {
|
||||
subpatterns
|
||||
.iter()
|
||||
.map(|fieldpat| {
|
||||
let place = place.clone().field(fieldpat.field,
|
||||
fieldpat.pattern.ty);
|
||||
let place = self.hir.tcx().mk_place_field(
|
||||
place.clone(),
|
||||
fieldpat.field,
|
||||
fieldpat.pattern.ty,
|
||||
);
|
||||
MatchPair::new(place, &fieldpat.pattern)
|
||||
})
|
||||
.collect()
|
||||
|
@ -27,6 +32,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
suffix: &'pat [Pat<'tcx>]) {
|
||||
let min_length = prefix.len() + suffix.len();
|
||||
let min_length = min_length.try_into().unwrap();
|
||||
let tcx = self.hir.tcx();
|
||||
|
||||
match_pairs.extend(
|
||||
prefix.iter()
|
||||
|
@ -37,13 +43,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
min_length,
|
||||
from_end: false,
|
||||
};
|
||||
let place = place.clone().elem(elem);
|
||||
let place = tcx.mk_place_elem(place.clone(), elem);
|
||||
MatchPair::new(place, subpattern)
|
||||
})
|
||||
);
|
||||
|
||||
if let Some(subslice_pat) = opt_slice {
|
||||
let subslice = place.clone().elem(ProjectionElem::Subslice {
|
||||
let subslice = tcx.mk_place_elem(place.clone(),ProjectionElem::Subslice {
|
||||
from: prefix.len() as u32,
|
||||
to: suffix.len() as u32
|
||||
});
|
||||
|
@ -60,7 +66,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
min_length,
|
||||
from_end: true,
|
||||
};
|
||||
let place = place.clone().elem(elem);
|
||||
let place = tcx.mk_place_elem(place.clone(), elem);
|
||||
MatchPair::new(place, subpattern)
|
||||
})
|
||||
);
|
||||
|
|
|
@ -926,14 +926,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
// If constants and statics, we don't generate StorageLive for this
|
||||
// temporary, so don't try to generate StorageDead for it either.
|
||||
_ if self.local_scope().is_none() => (),
|
||||
Operand::Copy(Place {
|
||||
base: PlaceBase::Local(cond_temp),
|
||||
projection: box [],
|
||||
})
|
||||
| Operand::Move(Place {
|
||||
base: PlaceBase::Local(cond_temp),
|
||||
projection: box [],
|
||||
}) => {
|
||||
Operand::Copy(place)
|
||||
| Operand::Move(place) => {
|
||||
if let Some(cond_temp) = place.as_local() {
|
||||
// Manually drop the condition on both branches.
|
||||
let top_scope = self.scopes.scopes.last_mut().unwrap();
|
||||
let top_drop_data = top_scope.drops.pop().unwrap();
|
||||
|
@ -964,8 +959,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
|
||||
top_scope.invalidate_cache(true, self.is_generator, true);
|
||||
} else {
|
||||
bug!("Expected as_local_operand to produce a temporary");
|
||||
}
|
||||
}
|
||||
_ => bug!("Expected as_local_operand to produce a temporary"),
|
||||
}
|
||||
|
||||
(true_block, false_block)
|
||||
|
|
|
@ -157,11 +157,13 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
|
|||
// Since `propagate_call_unwind` doesn't exist, we have to kill the
|
||||
// destination here, and then gen it again in `propagate_call_return`.
|
||||
if let TerminatorKind::Call {
|
||||
destination: Some((Place { base: PlaceBase::Local(local), projection: box [] }, _)),
|
||||
destination: Some((ref place, _)),
|
||||
..
|
||||
} = self.body[loc.block].terminator().kind {
|
||||
if let Some(local) = place.as_local() {
|
||||
sets.kill(local);
|
||||
}
|
||||
}
|
||||
self.check_for_move(sets, loc);
|
||||
}
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
BorrowedContent {
|
||||
target_place: Place {
|
||||
base: place.base.clone(),
|
||||
projection: proj.to_vec().into_boxed_slice(),
|
||||
projection: tcx.intern_place_elems(proj),
|
||||
},
|
||||
},
|
||||
));
|
||||
|
@ -172,7 +172,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
Some(base),
|
||||
Place {
|
||||
base: place.base.clone(),
|
||||
projection: proj.to_vec().into_boxed_slice(),
|
||||
projection: tcx.intern_place_elems(proj),
|
||||
},
|
||||
);
|
||||
ent.insert(path);
|
||||
|
@ -274,7 +274,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
// Box starts out uninitialized - need to create a separate
|
||||
// move-path for the interior so it will be separate from
|
||||
// the exterior.
|
||||
self.create_move_path(&place.clone().deref());
|
||||
self.create_move_path(&self.builder.tcx.mk_place_deref(place.clone()));
|
||||
self.gather_init(place.as_ref(), InitKind::Shallow);
|
||||
} else {
|
||||
self.gather_init(place.as_ref(), InitKind::Deep);
|
||||
|
|
|
@ -327,7 +327,7 @@ impl<'tcx> MoveData<'tcx> {
|
|||
pub fn base_local(&self, mut mpi: MovePathIndex) -> Option<Local> {
|
||||
loop {
|
||||
let path = &self.move_paths[mpi];
|
||||
if let Place { base: PlaceBase::Local(l), projection: box [] } = path.place {
|
||||
if let Some(l) = path.place.as_local() {
|
||||
return Some(l);
|
||||
}
|
||||
if let Some(parent) = path.parent {
|
||||
|
|
|
@ -117,7 +117,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx
|
|||
|
||||
run_passes(tcx, &mut result, instance, None, MirPhase::Const, &[
|
||||
&add_moves_for_packed_drops::AddMovesForPackedDrops,
|
||||
&no_landing_pads::NoLandingPads,
|
||||
&no_landing_pads::NoLandingPads::new(tcx),
|
||||
&remove_noop_landing_pads::RemoveNoopLandingPads,
|
||||
&simplify::SimplifyCfg::new("make_shim"),
|
||||
&add_call_guards::CriticalCallEdges,
|
||||
|
@ -231,7 +231,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
|
|||
tcx,
|
||||
param_env
|
||||
};
|
||||
let dropee = dropee_ptr.deref();
|
||||
let dropee = tcx.mk_place_deref(dropee_ptr);
|
||||
let resume_block = elaborator.patch.resume_block();
|
||||
elaborate_drops::elaborate_drop(
|
||||
&mut elaborator,
|
||||
|
@ -312,7 +312,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -
|
|||
let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env, builder.span);
|
||||
|
||||
let dest = Place::return_place();
|
||||
let src = Place::from(Local::new(1+0)).deref();
|
||||
let src = tcx.mk_place_deref(Place::from(Local::new(1+0)));
|
||||
|
||||
match self_ty.kind {
|
||||
_ if is_copy => builder.copy_shim(),
|
||||
|
@ -415,7 +415,7 @@ impl CloneShimBuilder<'tcx> {
|
|||
}
|
||||
|
||||
fn copy_shim(&mut self) {
|
||||
let rcvr = Place::from(Local::new(1+0)).deref();
|
||||
let rcvr = self.tcx.mk_place_deref(Place::from(Local::new(1+0)));
|
||||
let ret_statement = self.make_statement(
|
||||
StatementKind::Assign(
|
||||
box(
|
||||
|
@ -561,8 +561,8 @@ impl CloneShimBuilder<'tcx> {
|
|||
// BB #2
|
||||
// `dest[i] = Clone::clone(src[beg])`;
|
||||
// Goto #3 if ok, #5 if unwinding happens.
|
||||
let dest_field = dest.clone().index(beg);
|
||||
let src_field = src.index(beg);
|
||||
let dest_field = self.tcx.mk_place_index(dest.clone(), beg);
|
||||
let src_field = self.tcx.mk_place_index(src, beg);
|
||||
self.make_clone_call(dest_field, src_field, ty, BasicBlock::new(3),
|
||||
BasicBlock::new(5));
|
||||
|
||||
|
@ -616,7 +616,7 @@ impl CloneShimBuilder<'tcx> {
|
|||
// BB #7 (cleanup)
|
||||
// `drop(dest[beg])`;
|
||||
self.block(vec![], TerminatorKind::Drop {
|
||||
location: dest.index(beg),
|
||||
location: self.tcx.mk_place_index(dest, beg),
|
||||
target: BasicBlock::new(8),
|
||||
unwind: None,
|
||||
}, true);
|
||||
|
@ -648,9 +648,9 @@ impl CloneShimBuilder<'tcx> {
|
|||
let mut previous_field = None;
|
||||
for (i, ity) in tys.enumerate() {
|
||||
let field = Field::new(i);
|
||||
let src_field = src.clone().field(field, ity);
|
||||
let src_field = self.tcx.mk_place_field(src.clone(), field, ity);
|
||||
|
||||
let dest_field = dest.clone().field(field, ity);
|
||||
let dest_field = self.tcx.mk_place_field(dest.clone(), field, ity);
|
||||
|
||||
// #(2i + 1) is the cleanup block for the previous clone operation
|
||||
let cleanup_block = self.block_index_offset(1);
|
||||
|
@ -721,14 +721,14 @@ fn build_call_shim<'tcx>(
|
|||
|
||||
let rcvr = match rcvr_adjustment {
|
||||
Adjustment::Identity => Operand::Move(rcvr_l),
|
||||
Adjustment::Deref => Operand::Copy(rcvr_l.deref()),
|
||||
Adjustment::Deref => Operand::Copy(tcx.mk_place_deref(rcvr_l)),
|
||||
Adjustment::DerefMove => {
|
||||
// fn(Self, ...) -> fn(*mut Self, ...)
|
||||
let arg_ty = local_decls[rcvr_arg].ty;
|
||||
debug_assert!(tcx.generics_of(def_id).has_self && arg_ty == tcx.types.self_param);
|
||||
local_decls[rcvr_arg].ty = tcx.mk_mut_ptr(arg_ty);
|
||||
|
||||
Operand::Move(rcvr_l.deref())
|
||||
Operand::Move(tcx.mk_place_deref(rcvr_l))
|
||||
}
|
||||
Adjustment::RefMut => {
|
||||
// let rcvr = &mut rcvr;
|
||||
|
@ -772,7 +772,7 @@ fn build_call_shim<'tcx>(
|
|||
if let Some(untuple_args) = untuple_args {
|
||||
args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
|
||||
let arg_place = Place::from(Local::new(1+1));
|
||||
Operand::Move(arg_place.field(Field::new(i), *ity))
|
||||
Operand::Move(tcx.mk_place_field(arg_place, Field::new(i), *ity))
|
||||
}));
|
||||
} else {
|
||||
args.extend((1..sig.inputs().len()).map(|i| {
|
||||
|
@ -901,6 +901,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &Body<'_> {
|
|||
)),
|
||||
AggregateKind::Adt(adt_def, variant_index, substs, None, None),
|
||||
source_info,
|
||||
tcx,
|
||||
).collect();
|
||||
|
||||
let start_block = BasicBlockData {
|
||||
|
|
|
@ -164,8 +164,8 @@ pub trait Qualif {
|
|||
|
||||
Rvalue::Ref(_, _, ref place) => {
|
||||
// Special-case reborrows to be more like a copy of the reference.
|
||||
if let box [proj_base @ .., elem] = &place.projection {
|
||||
if ProjectionElem::Deref == *elem {
|
||||
if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
|
||||
if ProjectionElem::Deref == elem {
|
||||
let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty;
|
||||
if let ty::Ref(..) = base_ty.kind {
|
||||
return Self::in_place(cx, per_local, PlaceRef {
|
||||
|
|
|
@ -56,16 +56,16 @@ where
|
|||
fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) {
|
||||
debug_assert!(!place.is_indirect());
|
||||
|
||||
match (value, place) {
|
||||
(true, mir::Place { base: mir::PlaceBase::Local(local), .. }) => {
|
||||
self.qualifs_per_local.insert(*local);
|
||||
match (value, place.as_ref()) {
|
||||
(true, mir::PlaceRef { base: &mir::PlaceBase::Local(local), .. }) => {
|
||||
self.qualifs_per_local.insert(local);
|
||||
}
|
||||
|
||||
// For now, we do not clear the qualif if a local is overwritten in full by
|
||||
// an unqualified rvalue (e.g. `y = 5`). This is to be consistent
|
||||
// with aggregates where we overwrite all fields with assignments, which would not
|
||||
// get this feature.
|
||||
(false, mir::Place { base: mir::PlaceBase::Local(_local), projection: box [] }) => {
|
||||
(false, mir::PlaceRef { base: &mir::PlaceBase::Local(_local), projection: &[] }) => {
|
||||
// self.qualifs_per_local.remove(*local);
|
||||
}
|
||||
|
||||
|
@ -101,13 +101,12 @@ where
|
|||
|
||||
// If a local with no projections is moved from (e.g. `x` in `y = x`), record that
|
||||
// it no longer needs to be dropped.
|
||||
if let mir::Operand::Move(mir::Place {
|
||||
base: mir::PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
}) = *operand {
|
||||
if let mir::Operand::Move(place) = operand {
|
||||
if let Some(local) = place.as_local() {
|
||||
self.qualifs_per_local.remove(local);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_assign(
|
||||
&mut self,
|
||||
|
|
|
@ -244,8 +244,8 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
|||
if let Rvalue::Ref(_, kind, ref place) = *rvalue {
|
||||
// Special-case reborrows to be more like a copy of a reference.
|
||||
let mut reborrow_place = None;
|
||||
if let box [proj_base @ .., elem] = &place.projection {
|
||||
if *elem == ProjectionElem::Deref {
|
||||
if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
|
||||
if elem == ProjectionElem::Deref {
|
||||
let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
|
||||
if let ty::Ref(..) = base_ty.kind {
|
||||
reborrow_place = Some(proj_base);
|
||||
|
@ -376,12 +376,15 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
|||
);
|
||||
|
||||
if rvalue_has_mut_interior {
|
||||
let is_derived_from_illegal_borrow = match *borrowed_place {
|
||||
let is_derived_from_illegal_borrow = match borrowed_place.as_local() {
|
||||
// If an unprojected local was borrowed and its value was the result of an
|
||||
// illegal borrow, suppress this error and mark the result of this borrow as
|
||||
// illegal as well.
|
||||
Place { base: PlaceBase::Local(borrowed_local), projection: box [] }
|
||||
if self.derived_from_illegal_borrow.contains(borrowed_local) => true,
|
||||
Some(borrowed_local)
|
||||
if self.derived_from_illegal_borrow.contains(borrowed_local) =>
|
||||
{
|
||||
true
|
||||
}
|
||||
|
||||
// Otherwise proceed normally: check the legality of a mutable borrow in this
|
||||
// context.
|
||||
|
@ -394,7 +397,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
|||
// FIXME: should we also clear `derived_from_illegal_borrow` when a local is
|
||||
// assigned a new value?
|
||||
if is_derived_from_illegal_borrow {
|
||||
if let Place { base: PlaceBase::Local(dest), projection: box [] } = *dest {
|
||||
if let Some(dest) = dest.as_local() {
|
||||
self.derived_from_illegal_borrow.insert(dest);
|
||||
}
|
||||
}
|
||||
|
@ -571,10 +574,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
let needs_drop = if let Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
} = *dropped_place {
|
||||
let needs_drop = if let Some(local) = dropped_place.as_local() {
|
||||
// Use the span where the local was declared as the span of the drop error.
|
||||
err_span = self.body.local_decls[local].source_info.span;
|
||||
self.qualifs.needs_drop.contains(local)
|
||||
|
|
|
@ -406,8 +406,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
|||
place: &Place<'tcx>,
|
||||
is_mut_use: bool,
|
||||
) {
|
||||
let mut cursor = &*place.projection;
|
||||
while let [proj_base @ .., elem] = cursor {
|
||||
let mut cursor = place.projection.as_ref();
|
||||
while let &[ref proj_base @ .., elem] = cursor {
|
||||
cursor = proj_base;
|
||||
|
||||
match elem {
|
||||
|
|
|
@ -24,16 +24,22 @@ use crate::transform::{MirPass, MirSource};
|
|||
|
||||
pub struct CleanupNonCodegenStatements;
|
||||
|
||||
pub struct DeleteNonCodegenStatements;
|
||||
pub struct DeleteNonCodegenStatements<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements {
|
||||
fn run_pass(&self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) {
|
||||
let mut delete = DeleteNonCodegenStatements;
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) {
|
||||
let mut delete = DeleteNonCodegenStatements { tcx };
|
||||
delete.visit_body(body);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for DeleteNonCodegenStatements {
|
||||
impl<'tcx> MutVisitor<'tcx> for DeleteNonCodegenStatements<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_statement(&mut self,
|
||||
statement: &mut Statement<'tcx>,
|
||||
location: Location) {
|
||||
|
|
|
@ -7,10 +7,9 @@ use std::cell::Cell;
|
|||
use rustc::hir::def::DefKind;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::mir::{
|
||||
AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue,
|
||||
Local, UnOp, StatementKind, Statement, LocalKind,
|
||||
TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp,
|
||||
SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock,
|
||||
AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue, Local, UnOp,
|
||||
StatementKind, Statement, LocalKind, TerminatorKind, Terminator, ClearCrossCrate, SourceInfo,
|
||||
BinOp, SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock,
|
||||
};
|
||||
use rustc::mir::visit::{
|
||||
Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext,
|
||||
|
@ -525,10 +524,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
// (e.g. for CTFE) it can never happen. But here in const_prop
|
||||
// unknown data is uninitialized, so if e.g. a function argument is unsized
|
||||
// and has a reference taken, we get an ICE.
|
||||
Rvalue::Ref(_, _, Place { base: PlaceBase::Local(local), projection: box [] }) => {
|
||||
trace!("checking Ref({:?})", place);
|
||||
Rvalue::Ref(_, _, place_ref) => {
|
||||
trace!("checking Ref({:?})", place_ref);
|
||||
|
||||
if let Some(local) = place_ref.as_local() {
|
||||
let alive =
|
||||
if let LocalValue::Live(_) = self.ecx.frame().locals[*local].value {
|
||||
if let LocalValue::Live(_) = self.ecx.frame().locals[local].value {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
@ -539,6 +540,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => { }
|
||||
}
|
||||
|
@ -685,6 +687,10 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
|
|||
}
|
||||
|
||||
impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_constant(
|
||||
&mut self,
|
||||
constant: &mut Constant<'tcx>,
|
||||
|
@ -706,10 +712,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
|
|||
.ty(&self.local_decls, self.tcx)
|
||||
.ty;
|
||||
if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
|
||||
if let Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
} = *place {
|
||||
if let Some(local) = place.as_local() {
|
||||
let source = statement.source_info;
|
||||
if let Some(()) = self.const_prop(rval, place_layout, source, place) {
|
||||
if self.can_const_prop[local] {
|
||||
|
|
|
@ -19,9 +19,7 @@
|
|||
//! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the
|
||||
//! future.
|
||||
|
||||
use rustc::mir::{
|
||||
Constant, Local, LocalKind, Location, Place, PlaceBase, Body, Operand, Rvalue, StatementKind
|
||||
};
|
||||
use rustc::mir::{Constant, Local, LocalKind, Location, Place, Body, Operand, Rvalue, StatementKind};
|
||||
use rustc::mir::visit::MutVisitor;
|
||||
use rustc::ty::TyCtxt;
|
||||
use crate::transform::{MirPass, MirSource};
|
||||
|
@ -92,17 +90,11 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
|
|||
};
|
||||
|
||||
// That use of the source must be an assignment.
|
||||
match statement.kind {
|
||||
StatementKind::Assign(
|
||||
box(
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
},
|
||||
Rvalue::Use(ref operand)
|
||||
)
|
||||
) if local == dest_local => {
|
||||
let maybe_action = match *operand {
|
||||
match &statement.kind {
|
||||
StatementKind::Assign(box(place, Rvalue::Use(operand))) => {
|
||||
if let Some(local) = place.as_local() {
|
||||
if local == dest_local {
|
||||
let maybe_action = match operand {
|
||||
Operand::Copy(ref src_place) |
|
||||
Operand::Move(ref src_place) => {
|
||||
Action::local_copy(&body, &def_use_analysis, src_place)
|
||||
|
@ -115,6 +107,16 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
|
|||
Some(this_action) => action = this_action,
|
||||
None => continue,
|
||||
}
|
||||
} else {
|
||||
debug!(" Can't copy-propagate local: source use is not an \
|
||||
assignment");
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
debug!(" Can't copy-propagate local: source use is not an \
|
||||
assignment");
|
||||
continue
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
debug!(" Can't copy-propagate local: source use is not an \
|
||||
|
@ -124,7 +126,8 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
|
|||
}
|
||||
}
|
||||
|
||||
changed = action.perform(body, &def_use_analysis, dest_local, location) || changed;
|
||||
changed =
|
||||
action.perform(body, &def_use_analysis, dest_local, location, tcx) || changed;
|
||||
// FIXME(pcwalton): Update the use-def chains to delete the instructions instead of
|
||||
// regenerating the chains.
|
||||
break
|
||||
|
@ -148,31 +151,20 @@ fn eliminate_self_assignments(
|
|||
for def in dest_use_info.defs_not_including_drop() {
|
||||
let location = def.location;
|
||||
if let Some(stmt) = body[location.block].statements.get(location.statement_index) {
|
||||
match stmt.kind {
|
||||
StatementKind::Assign(
|
||||
box(
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
},
|
||||
Rvalue::Use(Operand::Copy(Place {
|
||||
base: PlaceBase::Local(src_local),
|
||||
projection: box [],
|
||||
})),
|
||||
)
|
||||
) |
|
||||
StatementKind::Assign(
|
||||
box(
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
},
|
||||
Rvalue::Use(Operand::Move(Place {
|
||||
base: PlaceBase::Local(src_local),
|
||||
projection: box [],
|
||||
})),
|
||||
)
|
||||
) if local == dest_local && dest_local == src_local => {}
|
||||
match &stmt.kind {
|
||||
StatementKind::Assign(box (place, Rvalue::Use(Operand::Copy(src_place))))
|
||||
| StatementKind::Assign(box (place, Rvalue::Use(Operand::Move(src_place)))) => {
|
||||
if let (Some(local), Some(src_local)) =
|
||||
(place.as_local(), src_place.as_local())
|
||||
{
|
||||
if local == dest_local && dest_local == src_local {
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
continue;
|
||||
}
|
||||
|
@ -198,10 +190,7 @@ impl<'tcx> Action<'tcx> {
|
|||
fn local_copy(body: &Body<'tcx>, def_use_analysis: &DefUseAnalysis, src_place: &Place<'tcx>)
|
||||
-> Option<Action<'tcx>> {
|
||||
// The source must be a local.
|
||||
let src_local = if let Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
} = *src_place {
|
||||
let src_local = if let Some(local) = src_place.as_local() {
|
||||
local
|
||||
} else {
|
||||
debug!(" Can't copy-propagate local: source is not a local");
|
||||
|
@ -256,7 +245,8 @@ impl<'tcx> Action<'tcx> {
|
|||
body: &mut Body<'tcx>,
|
||||
def_use_analysis: &DefUseAnalysis,
|
||||
dest_local: Local,
|
||||
location: Location)
|
||||
location: Location,
|
||||
tcx: TyCtxt<'tcx>)
|
||||
-> bool {
|
||||
match self {
|
||||
Action::PropagateLocalCopy(src_local) => {
|
||||
|
@ -280,7 +270,7 @@ impl<'tcx> Action<'tcx> {
|
|||
}
|
||||
|
||||
// Replace all uses of the destination local with the source local.
|
||||
def_use_analysis.replace_all_defs_and_uses_with(dest_local, body, src_local);
|
||||
def_use_analysis.replace_all_defs_and_uses_with(dest_local, body, src_local, tcx);
|
||||
|
||||
// Finally, zap the now-useless assignment instruction.
|
||||
debug!(" Deleting assignment");
|
||||
|
@ -304,7 +294,8 @@ impl<'tcx> Action<'tcx> {
|
|||
|
||||
// Replace all uses of the destination local with the constant.
|
||||
let mut visitor = ConstantPropagationVisitor::new(dest_local,
|
||||
src_constant);
|
||||
src_constant,
|
||||
tcx);
|
||||
for dest_place_use in &dest_local_info.defs_and_uses {
|
||||
visitor.visit_location(body, dest_place_use.location)
|
||||
}
|
||||
|
@ -336,33 +327,42 @@ impl<'tcx> Action<'tcx> {
|
|||
struct ConstantPropagationVisitor<'tcx> {
|
||||
dest_local: Local,
|
||||
constant: Constant<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
uses_replaced: usize,
|
||||
}
|
||||
|
||||
impl<'tcx> ConstantPropagationVisitor<'tcx> {
|
||||
fn new(dest_local: Local, constant: Constant<'tcx>)
|
||||
fn new(dest_local: Local, constant: Constant<'tcx>, tcx: TyCtxt<'tcx>)
|
||||
-> ConstantPropagationVisitor<'tcx> {
|
||||
ConstantPropagationVisitor {
|
||||
dest_local,
|
||||
constant,
|
||||
tcx,
|
||||
uses_replaced: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
|
||||
self.super_operand(operand, location);
|
||||
|
||||
match *operand {
|
||||
Operand::Copy(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
}) |
|
||||
Operand::Move(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
}) if local == self.dest_local => {}
|
||||
match operand {
|
||||
Operand::Copy(place) |
|
||||
Operand::Move(place) => {
|
||||
if let Some(local) = place.as_local() {
|
||||
if local == self.dest_local {
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => return,
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator {
|
|||
}),
|
||||
*kind,
|
||||
source_info,
|
||||
tcx,
|
||||
))
|
||||
});
|
||||
}
|
||||
|
|
|
@ -23,6 +23,10 @@ impl EraseRegionsVisitor<'tcx> {
|
|||
}
|
||||
|
||||
impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
|
||||
*ty = self.tcx.erase_regions(ty);
|
||||
}
|
||||
|
|
|
@ -74,12 +74,17 @@ use crate::util::liveness;
|
|||
|
||||
pub struct StateTransform;
|
||||
|
||||
struct RenameLocalVisitor {
|
||||
struct RenameLocalVisitor<'tcx> {
|
||||
from: Local,
|
||||
to: Local,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor {
|
||||
fn visit_local(&mut self,
|
||||
local: &mut Local,
|
||||
_: PlaceContext,
|
||||
|
@ -102,9 +107,15 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
struct DerefArgVisitor;
|
||||
struct DerefArgVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
|
||||
fn visit_local(&mut self,
|
||||
local: &mut Local,
|
||||
_: PlaceContext,
|
||||
|
@ -119,8 +130,8 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
|
|||
if place.base == PlaceBase::Local(self_arg()) {
|
||||
replace_base(place, Place {
|
||||
base: PlaceBase::Local(self_arg()),
|
||||
projection: Box::new([ProjectionElem::Deref]),
|
||||
});
|
||||
projection: self.tcx().intern_place_elems(&vec![ProjectionElem::Deref]),
|
||||
}, self.tcx);
|
||||
} else {
|
||||
self.visit_place_base(&mut place.base, context, location);
|
||||
|
||||
|
@ -135,9 +146,14 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
|
|||
|
||||
struct PinArgVisitor<'tcx> {
|
||||
ref_gen_ty: Ty<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_local(&mut self,
|
||||
local: &mut Local,
|
||||
_: PlaceContext,
|
||||
|
@ -145,15 +161,19 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
|
|||
assert_ne!(*local, self_arg());
|
||||
}
|
||||
|
||||
fn visit_place(&mut self,
|
||||
place: &mut Place<'tcx>,
|
||||
context: PlaceContext,
|
||||
location: Location) {
|
||||
fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
|
||||
if place.base == PlaceBase::Local(self_arg()) {
|
||||
replace_base(place, Place {
|
||||
replace_base(
|
||||
place,
|
||||
Place {
|
||||
base: PlaceBase::Local(self_arg()),
|
||||
projection: Box::new([ProjectionElem::Field(Field::new(0), self.ref_gen_ty)]),
|
||||
});
|
||||
projection: self.tcx().intern_place_elems(&vec![ProjectionElem::Field(
|
||||
Field::new(0),
|
||||
self.ref_gen_ty,
|
||||
)]),
|
||||
},
|
||||
self.tcx,
|
||||
);
|
||||
} else {
|
||||
self.visit_place_base(&mut place.base, context, location);
|
||||
|
||||
|
@ -166,13 +186,13 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn replace_base(place: &mut Place<'tcx>, new_base: Place<'tcx>) {
|
||||
fn replace_base<'tcx>(place: &mut Place<'tcx>, new_base: Place<'tcx>, tcx: TyCtxt<'tcx>) {
|
||||
place.base = new_base.base;
|
||||
|
||||
let mut new_projection = new_base.projection.to_vec();
|
||||
new_projection.append(&mut place.projection.to_vec());
|
||||
|
||||
place.projection = new_projection.into_boxed_slice();
|
||||
place.projection = tcx.intern_place_elems(&new_projection);
|
||||
}
|
||||
|
||||
fn self_arg() -> Local {
|
||||
|
@ -226,13 +246,13 @@ impl TransformVisitor<'tcx> {
|
|||
// Create a Place referencing a generator struct field
|
||||
fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> {
|
||||
let self_place = Place::from(self_arg());
|
||||
let base = self_place.downcast_unnamed(variant_index);
|
||||
let base = self.tcx.mk_place_downcast_unnamed(self_place, variant_index);
|
||||
let mut projection = base.projection.to_vec();
|
||||
projection.push(ProjectionElem::Field(Field::new(idx), ty));
|
||||
|
||||
Place {
|
||||
base: base.base,
|
||||
projection: projection.into_boxed_slice(),
|
||||
projection: self.tcx.intern_place_elems(&projection),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,6 +284,10 @@ impl TransformVisitor<'tcx> {
|
|||
}
|
||||
|
||||
impl MutVisitor<'tcx> for TransformVisitor<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_local(&mut self,
|
||||
local: &mut Local,
|
||||
_: PlaceContext,
|
||||
|
@ -280,7 +304,7 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> {
|
|||
if let PlaceBase::Local(l) = place.base {
|
||||
// Replace an Local in the remap with a generator struct access
|
||||
if let Some(&(ty, variant_index, idx)) = self.remap.get(&l) {
|
||||
replace_base(place, self.make_field(variant_index, idx, ty));
|
||||
replace_base(place, self.make_field(variant_index, idx, ty), self.tcx);
|
||||
}
|
||||
} else {
|
||||
self.visit_place_base(&mut place.base, context, location);
|
||||
|
@ -375,7 +399,7 @@ fn make_generator_state_argument_indirect<'tcx>(
|
|||
body.local_decls.raw[1].ty = ref_gen_ty;
|
||||
|
||||
// Add a deref to accesses of the generator state
|
||||
DerefArgVisitor.visit_body(body);
|
||||
DerefArgVisitor { tcx }.visit_body(body);
|
||||
}
|
||||
|
||||
fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
|
@ -390,12 +414,13 @@ fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body
|
|||
body.local_decls.raw[1].ty = pin_ref_gen_ty;
|
||||
|
||||
// Add the Pin field access to accesses of the generator state
|
||||
PinArgVisitor { ref_gen_ty }.visit_body(body);
|
||||
PinArgVisitor { ref_gen_ty, tcx }.visit_body(body);
|
||||
}
|
||||
|
||||
fn replace_result_variable<'tcx>(
|
||||
ret_ty: Ty<'tcx>,
|
||||
body: &mut Body<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Local {
|
||||
let source_info = source_info(body);
|
||||
let new_ret = LocalDecl {
|
||||
|
@ -416,6 +441,7 @@ fn replace_result_variable<'tcx>(
|
|||
RenameLocalVisitor {
|
||||
from: RETURN_PLACE,
|
||||
to: new_ret_local,
|
||||
tcx,
|
||||
}.visit_body(body);
|
||||
|
||||
new_ret_local
|
||||
|
@ -864,17 +890,24 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut
|
|||
|
||||
for (block, block_data) in body.basic_blocks().iter_enumerated() {
|
||||
let (target, unwind, source_info) = match block_data.terminator() {
|
||||
&Terminator {
|
||||
Terminator {
|
||||
source_info,
|
||||
kind: TerminatorKind::Drop {
|
||||
location: Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
},
|
||||
location,
|
||||
target,
|
||||
unwind
|
||||
}
|
||||
} if local == gen => (target, unwind, source_info),
|
||||
} => {
|
||||
if let Some(local) = location.as_local() {
|
||||
if local == gen {
|
||||
(target, unwind, source_info)
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
let unwind = if block_data.is_cleanup {
|
||||
|
@ -884,10 +917,10 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut
|
|||
};
|
||||
elaborate_drop(
|
||||
&mut elaborator,
|
||||
source_info,
|
||||
*source_info,
|
||||
&Place::from(gen),
|
||||
(),
|
||||
target,
|
||||
*target,
|
||||
unwind,
|
||||
block,
|
||||
);
|
||||
|
@ -1175,7 +1208,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
|
|||
|
||||
// We rename RETURN_PLACE which has type mir.return_ty to new_ret_local
|
||||
// RETURN_PLACE then is a fresh unused local with type ret_ty.
|
||||
let new_ret_local = replace_result_variable(ret_ty, body);
|
||||
let new_ret_local = replace_result_variable(ret_ty, body, tcx);
|
||||
|
||||
// Extract locals which are live across suspension point into `layout`
|
||||
// `remap` gives a mapping from local indices onto generator struct indices
|
||||
|
|
|
@ -461,7 +461,7 @@ impl Inliner<'tcx> {
|
|||
};
|
||||
caller_body[callsite.bb]
|
||||
.statements.push(stmt);
|
||||
tmp.deref()
|
||||
self.tcx.mk_place_deref(tmp)
|
||||
} else {
|
||||
destination.0
|
||||
};
|
||||
|
@ -481,6 +481,7 @@ impl Inliner<'tcx> {
|
|||
return_block,
|
||||
cleanup_block: cleanup,
|
||||
in_cleanup_block: false,
|
||||
tcx: self.tcx,
|
||||
};
|
||||
|
||||
|
||||
|
@ -559,7 +560,8 @@ impl Inliner<'tcx> {
|
|||
let tuple_tmp_args =
|
||||
tuple_tys.iter().enumerate().map(|(i, ty)| {
|
||||
// This is e.g., `tuple_tmp.0` in our example above.
|
||||
let tuple_field = Operand::Move(tuple.clone().field(
|
||||
let tuple_field = Operand::Move(tcx.mk_place_field(
|
||||
tuple.clone(),
|
||||
Field::new(i),
|
||||
ty.expect_ty(),
|
||||
));
|
||||
|
@ -587,15 +589,14 @@ impl Inliner<'tcx> {
|
|||
// FIXME: Analysis of the usage of the arguments to avoid
|
||||
// unnecessary temporaries.
|
||||
|
||||
if let Operand::Move(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
}) = arg {
|
||||
if let Operand::Move(place) = &arg {
|
||||
if let Some(local) = place.as_local() {
|
||||
if caller_body.local_kind(local) == LocalKind::Temp {
|
||||
// Reuse the operand if it's a temporary already
|
||||
return local;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("creating temp for argument {:?}", arg);
|
||||
// Otherwise, create a temporary for the arg
|
||||
|
@ -639,6 +640,7 @@ struct Integrator<'a, 'tcx> {
|
|||
return_block: BasicBlock,
|
||||
cleanup_block: Option<BasicBlock>,
|
||||
in_cleanup_block: bool,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Integrator<'a, 'tcx> {
|
||||
|
@ -650,14 +652,9 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
|
|||
|
||||
fn make_integrate_local(&self, local: &Local) -> Local {
|
||||
if *local == RETURN_PLACE {
|
||||
match self.destination {
|
||||
Place {
|
||||
base: PlaceBase::Local(l),
|
||||
projection: box [],
|
||||
} => {
|
||||
return l;
|
||||
},
|
||||
ref place => bug!("Return place is {:?}, not local", place)
|
||||
match self.destination.as_local() {
|
||||
Some(l) => return l,
|
||||
ref place => bug!("Return place is {:?}, not local", place),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -671,6 +668,10 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_local(
|
||||
&mut self,
|
||||
local: &mut Local,
|
||||
|
@ -686,19 +687,13 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
|
|||
context: PlaceContext,
|
||||
location: Location,
|
||||
) {
|
||||
match place {
|
||||
Place {
|
||||
base: PlaceBase::Local(RETURN_PLACE),
|
||||
projection: box [],
|
||||
} => {
|
||||
if let Some(RETURN_PLACE) = place.as_local() {
|
||||
// Return pointer; update the place itself
|
||||
*place = self.destination.clone();
|
||||
},
|
||||
_ => {
|
||||
} else {
|
||||
self.super_place(place, context, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn process_projection_elem(
|
||||
&mut self,
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
//! Performs various peephole optimizations.
|
||||
|
||||
use rustc::mir::{Constant, Location, Place, PlaceBase, Body, Operand, ProjectionElem, Rvalue,
|
||||
Local};
|
||||
use rustc::mir::{
|
||||
Constant, Location, Place, PlaceBase, PlaceRef, Body, Operand, ProjectionElem, Rvalue, Local
|
||||
};
|
||||
use rustc::mir::visit::{MutVisitor, Visitor};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::util::nodemap::{FxHashMap, FxHashSet};
|
||||
|
@ -28,32 +29,33 @@ impl<'tcx> MirPass<'tcx> for InstCombine {
|
|||
};
|
||||
|
||||
// Then carry out those optimizations.
|
||||
MutVisitor::visit_body(&mut InstCombineVisitor { optimizations }, body);
|
||||
MutVisitor::visit_body(&mut InstCombineVisitor { optimizations, tcx }, body);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InstCombineVisitor<'tcx> {
|
||||
optimizations: OptimizationList<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
|
||||
if self.optimizations.and_stars.remove(&location) {
|
||||
debug!("replacing `&*`: {:?}", rvalue);
|
||||
let new_place = match *rvalue {
|
||||
Rvalue::Ref(_, _, Place {
|
||||
ref mut base,
|
||||
projection: ref mut projection @ box [.., _],
|
||||
}) => {
|
||||
if let box [proj_l @ .., proj_r] = projection {
|
||||
let place = Place {
|
||||
// Replace with dummy
|
||||
base: mem::replace(base, PlaceBase::Local(Local::new(0))),
|
||||
projection: proj_l.to_vec().into_boxed_slice(),
|
||||
};
|
||||
*projection = vec![proj_r.clone()].into_boxed_slice();
|
||||
let new_place = match rvalue {
|
||||
Rvalue::Ref(_, _, place) => {
|
||||
if let &[ref proj_l @ .., proj_r] = place.projection.as_ref() {
|
||||
place.projection = self.tcx().intern_place_elems(&vec![proj_r.clone()]);
|
||||
|
||||
place
|
||||
Place {
|
||||
// Replace with dummy
|
||||
base: mem::replace(&mut place.base, PlaceBase::Local(Local::new(0))),
|
||||
projection: self.tcx().intern_place_elems(proj_l),
|
||||
}
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
|
@ -91,14 +93,16 @@ impl OptimizationFinder<'b, 'tcx> {
|
|||
|
||||
impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> {
|
||||
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
if let Rvalue::Ref(_, _, Place {
|
||||
if let Rvalue::Ref(_, _, place) = rvalue {
|
||||
if let PlaceRef {
|
||||
base,
|
||||
projection: box [proj_base @ .., ProjectionElem::Deref],
|
||||
}) = rvalue {
|
||||
projection: &[ref proj_base @ .., ProjectionElem::Deref],
|
||||
} = place.as_ref() {
|
||||
if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() {
|
||||
self.optimizations.and_stars.insert(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Rvalue::Len(ref place) = *rvalue {
|
||||
let place_ty = place.ty(&self.body.local_decls, self.tcx).ty;
|
||||
|
|
|
@ -228,7 +228,7 @@ fn run_optimization_passes<'tcx>(
|
|||
) {
|
||||
run_passes(tcx, body, InstanceDef::Item(def_id), promoted, MirPhase::Optimized, &[
|
||||
// Remove all things only needed by analysis
|
||||
&no_landing_pads::NoLandingPads,
|
||||
&no_landing_pads::NoLandingPads::new(tcx),
|
||||
&simplify_branches::SimplifyBranches::new("initial"),
|
||||
&remove_noop_landing_pads::RemoveNoopLandingPads,
|
||||
&cleanup_post_borrowck::CleanupNonCodegenStatements,
|
||||
|
@ -238,7 +238,7 @@ fn run_optimization_passes<'tcx>(
|
|||
// These next passes must be executed together
|
||||
&add_call_guards::CriticalCallEdges,
|
||||
&elaborate_drops::ElaborateDrops,
|
||||
&no_landing_pads::NoLandingPads,
|
||||
&no_landing_pads::NoLandingPads::new(tcx),
|
||||
// AddMovesForPackedDrops needs to run after drop
|
||||
// elaboration.
|
||||
&add_moves_for_packed_drops::AddMovesForPackedDrops,
|
||||
|
@ -257,7 +257,7 @@ fn run_optimization_passes<'tcx>(
|
|||
|
||||
|
||||
// Optimizations begin.
|
||||
&uniform_array_move_out::RestoreSubsliceArrayMoveOut,
|
||||
&uniform_array_move_out::RestoreSubsliceArrayMoveOut::new(tcx),
|
||||
&inline::Inline,
|
||||
|
||||
// Lowering generator control-flow and variables
|
||||
|
|
|
@ -6,9 +6,17 @@ use rustc::mir::*;
|
|||
use rustc::mir::visit::MutVisitor;
|
||||
use crate::transform::{MirPass, MirSource};
|
||||
|
||||
pub struct NoLandingPads;
|
||||
pub struct NoLandingPads<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> 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>) {
|
||||
no_landing_pads(tcx, body)
|
||||
}
|
||||
|
@ -16,11 +24,15 @@ impl<'tcx> MirPass<'tcx> for NoLandingPads {
|
|||
|
||||
pub fn no_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
if tcx.sess.no_landing_pads() {
|
||||
NoLandingPads.visit_body(body);
|
||||
NoLandingPads::new(tcx).visit_body(body);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
|
||||
impl<'tcx> MutVisitor<'tcx> for NoLandingPads<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_terminator_kind(&mut self,
|
||||
kind: &mut TerminatorKind<'tcx>,
|
||||
location: Location) {
|
||||
|
|
|
@ -17,7 +17,7 @@ use rustc::mir::*;
|
|||
use rustc::mir::visit::{PlaceContext, MutatingUseContext, MutVisitor, Visitor};
|
||||
use rustc::mir::traversal::ReversePostorder;
|
||||
use rustc::ty::subst::InternalSubsts;
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc::ty::{List, TyCtxt};
|
||||
use syntax_pos::Span;
|
||||
|
||||
use rustc_index::vec::{IndexVec, Idx};
|
||||
|
@ -321,7 +321,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
ty,
|
||||
def_id,
|
||||
}),
|
||||
projection: box [],
|
||||
projection: List::empty(),
|
||||
}
|
||||
};
|
||||
let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
|
||||
|
@ -339,7 +339,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
&mut place.base,
|
||||
promoted_place(ty, span).base,
|
||||
),
|
||||
projection: box [],
|
||||
projection: List::empty(),
|
||||
})
|
||||
}
|
||||
_ => bug!()
|
||||
|
@ -396,6 +396,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
|
||||
/// Replaces all temporaries with their promoted counterparts.
|
||||
impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_local(&mut self,
|
||||
local: &mut Local,
|
||||
_: PlaceContext,
|
||||
|
@ -434,16 +438,15 @@ pub fn promote_candidates<'tcx>(
|
|||
match candidate {
|
||||
Candidate::Repeat(Location { block, statement_index }) |
|
||||
Candidate::Ref(Location { block, statement_index }) => {
|
||||
match body[block].statements[statement_index].kind {
|
||||
StatementKind::Assign(box(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
}, _)) => {
|
||||
match &body[block].statements[statement_index].kind {
|
||||
StatementKind::Assign(box(place, _)) => {
|
||||
if let Some(local) = place.as_local() {
|
||||
if temps[local] == TempState::PromotedOut {
|
||||
// Already promoted.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -487,30 +490,32 @@ pub fn promote_candidates<'tcx>(
|
|||
let promoted = |index: Local| temps[index] == TempState::PromotedOut;
|
||||
for block in body.basic_blocks_mut() {
|
||||
block.statements.retain(|statement| {
|
||||
match statement.kind {
|
||||
StatementKind::Assign(box(Place {
|
||||
base: PlaceBase::Local(index),
|
||||
projection: box [],
|
||||
}, _)) |
|
||||
match &statement.kind {
|
||||
StatementKind::Assign(box(place, _)) => {
|
||||
if let Some(index) = place.as_local() {
|
||||
!promoted(index)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
StatementKind::StorageLive(index) |
|
||||
StatementKind::StorageDead(index) => {
|
||||
!promoted(index)
|
||||
!promoted(*index)
|
||||
}
|
||||
_ => true
|
||||
}
|
||||
});
|
||||
let terminator = block.terminator_mut();
|
||||
match terminator.kind {
|
||||
TerminatorKind::Drop { location: Place {
|
||||
base: PlaceBase::Local(index),
|
||||
projection: box [],
|
||||
}, target, .. } => {
|
||||
match &terminator.kind {
|
||||
TerminatorKind::Drop { location: place, target, .. } => {
|
||||
if let Some(index) = place.as_local() {
|
||||
if promoted(index) {
|
||||
terminator.kind = TerminatorKind::Goto {
|
||||
target,
|
||||
target: *target,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -292,8 +292,8 @@ trait Qualif {
|
|||
|
||||
Rvalue::Ref(_, _, ref place) => {
|
||||
// Special-case reborrows to be more like a copy of the reference.
|
||||
if let box [proj_base @ .., elem] = &place.projection {
|
||||
if ProjectionElem::Deref == *elem {
|
||||
if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
|
||||
if ProjectionElem::Deref == elem {
|
||||
let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty;
|
||||
if let ty::Ref(..) = base_ty.kind {
|
||||
return Self::in_place(cx, PlaceRef {
|
||||
|
@ -1041,28 +1041,26 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
|
|||
match *candidate {
|
||||
Candidate::Repeat(Location { block: bb, statement_index: stmt_idx }) => {
|
||||
if let StatementKind::Assign(box(_, Rvalue::Repeat(
|
||||
Operand::Move(Place {
|
||||
base: PlaceBase::Local(index),
|
||||
projection: box [],
|
||||
}),
|
||||
Operand::Move(place),
|
||||
_
|
||||
))) = self.body[bb].statements[stmt_idx].kind {
|
||||
))) = &self.body[bb].statements[stmt_idx].kind {
|
||||
if let Some(index) = place.as_local() {
|
||||
promoted_temps.insert(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
|
||||
if let StatementKind::Assign(
|
||||
box(
|
||||
_,
|
||||
Rvalue::Ref(_, _, Place {
|
||||
base: PlaceBase::Local(index),
|
||||
projection: box [],
|
||||
})
|
||||
Rvalue::Ref(_, _, place)
|
||||
)
|
||||
) = self.body[bb].statements[stmt_idx].kind {
|
||||
) = &self.body[bb].statements[stmt_idx].kind {
|
||||
if let Some(index) = place.as_local() {
|
||||
promoted_temps.insert(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
Candidate::Argument { .. } => {}
|
||||
}
|
||||
}
|
||||
|
@ -1237,10 +1235,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
|
|||
match *operand {
|
||||
Operand::Move(ref place) => {
|
||||
// Mark the consumed locals to indicate later drops are noops.
|
||||
if let Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
} = *place {
|
||||
if let Some(local) = place.as_local() {
|
||||
self.cx.per_local[NeedsDrop].remove(local);
|
||||
}
|
||||
}
|
||||
|
@ -1256,8 +1251,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
|
|||
if let Rvalue::Ref(_, kind, ref place) = *rvalue {
|
||||
// Special-case reborrows.
|
||||
let mut reborrow_place = None;
|
||||
if let box [proj_base @ .., elem] = &place.projection {
|
||||
if *elem == ProjectionElem::Deref {
|
||||
if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
|
||||
if elem == ProjectionElem::Deref {
|
||||
let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
|
||||
if let ty::Ref(..) = base_ty.kind {
|
||||
reborrow_place = Some(proj_base);
|
||||
|
@ -1568,10 +1563,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
|
|||
unleash_miri!(self);
|
||||
// HACK(eddyb): emulate a bit of dataflow analysis,
|
||||
// conservatively, that drop elaboration will do.
|
||||
let needs_drop = if let Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
} = *place {
|
||||
let needs_drop = if let Some(local) = place.as_local() {
|
||||
if NeedsDrop::in_local(self, local) {
|
||||
Some(self.body.local_decls[local].source_info.span)
|
||||
} else {
|
||||
|
@ -1817,16 +1809,17 @@ fn remove_drop_and_storage_dead_on_promoted_locals(
|
|||
}
|
||||
});
|
||||
let terminator = block.terminator_mut();
|
||||
match terminator.kind {
|
||||
match &terminator.kind {
|
||||
TerminatorKind::Drop {
|
||||
location: Place {
|
||||
base: PlaceBase::Local(index),
|
||||
projection: box [],
|
||||
},
|
||||
location,
|
||||
target,
|
||||
..
|
||||
} if promoted_temps.contains(index) => {
|
||||
terminator.kind = TerminatorKind::Goto { target };
|
||||
} => {
|
||||
if let Some(index) = location.as_local() {
|
||||
if promoted_temps.contains(index) {
|
||||
terminator.kind = TerminatorKind::Goto { target: *target };
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -259,8 +259,8 @@ fn check_place(
|
|||
def_id: DefId,
|
||||
body: &Body<'tcx>
|
||||
) -> McfResult {
|
||||
let mut cursor = &*place.projection;
|
||||
while let [proj_base @ .., elem] = cursor {
|
||||
let mut cursor = place.projection.as_ref();
|
||||
while let &[ref proj_base @ .., elem] = cursor {
|
||||
cursor = proj_base;
|
||||
match elem {
|
||||
ProjectionElem::Downcast(..) => {
|
||||
|
|
|
@ -32,7 +32,7 @@ impl RemoveNoopLandingPads {
|
|||
nop_landing_pads: &BitSet<BasicBlock>,
|
||||
) -> bool {
|
||||
for stmt in &body[bb].statements {
|
||||
match stmt.kind {
|
||||
match &stmt.kind {
|
||||
StatementKind::FakeRead(..) |
|
||||
StatementKind::StorageLive(_) |
|
||||
StatementKind::StorageDead(_) |
|
||||
|
@ -41,12 +41,13 @@ impl RemoveNoopLandingPads {
|
|||
// These are all nops in a landing pad
|
||||
}
|
||||
|
||||
StatementKind::Assign(box(Place {
|
||||
base: PlaceBase::Local(_),
|
||||
projection: box [],
|
||||
}, Rvalue::Use(_))) => {
|
||||
StatementKind::Assign(box(place, Rvalue::Use(_))) => {
|
||||
if place.as_local().is_some() {
|
||||
// Writing to a local (e.g., a drop flag) does not
|
||||
// turn a landing pad to a non-nop
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
StatementKind::Assign { .. } |
|
||||
|
|
|
@ -155,8 +155,8 @@ fn value_assigned_to_local<'a, 'tcx>(
|
|||
local: Local,
|
||||
) -> Option<&'a mir::Rvalue<'tcx>> {
|
||||
if let mir::StatementKind::Assign(box (place, rvalue)) = &stmt.kind {
|
||||
if let mir::Place { base: mir::PlaceBase::Local(l), projection: box [] } = place {
|
||||
if local == *l {
|
||||
if let Some(l) = place.as_local() {
|
||||
if local == l {
|
||||
return Some(&*rvalue);
|
||||
}
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ impl PeekCall {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
terminator: &mir::Terminator<'tcx>,
|
||||
) -> Option<Self> {
|
||||
use mir::{Operand, Place, PlaceBase};
|
||||
use mir::Operand;
|
||||
|
||||
let span = terminator.source_info.span;
|
||||
if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } =
|
||||
|
@ -207,14 +207,23 @@ impl PeekCall {
|
|||
|
||||
assert_eq!(args.len(), 1);
|
||||
let kind = PeekCallKind::from_arg_ty(substs.type_at(0));
|
||||
let arg = match args[0] {
|
||||
| Operand::Copy(Place { base: PlaceBase::Local(local), projection: box [] })
|
||||
| Operand::Move(Place { base: PlaceBase::Local(local), projection: box [] })
|
||||
=> local,
|
||||
|
||||
let arg = match &args[0] {
|
||||
Operand::Copy(place) | Operand::Move(place) => {
|
||||
if let Some(local) = place.as_local() {
|
||||
local
|
||||
} else {
|
||||
tcx.sess.diagnostic().span_err(
|
||||
span,
|
||||
"dataflow::sanity_check cannot feed a non-temp to rustc_peek.",
|
||||
);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
tcx.sess.diagnostic().span_err(
|
||||
span, "dataflow::sanity_check cannot feed a non-temp to rustc_peek.");
|
||||
span,
|
||||
"dataflow::sanity_check cannot feed a non-temp to rustc_peek.",
|
||||
);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
@ -277,12 +286,11 @@ impl<'tcx> RustcPeekAt<'tcx> for IndirectlyMutableLocals<'_, 'tcx> {
|
|||
call: PeekCall,
|
||||
) {
|
||||
warn!("peek_at: place={:?}", place);
|
||||
let local = match place {
|
||||
mir::Place { base: mir::PlaceBase::Local(l), projection: box [] } => *l,
|
||||
_ => {
|
||||
let local = if let Some(l) = place.as_local() {
|
||||
l
|
||||
} else {
|
||||
tcx.sess.span_err(call.span, "rustc_peek: argument was not a local");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if !flow_state.contains(local) {
|
||||
|
|
|
@ -319,7 +319,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyLocals {
|
|||
|
||||
let map = make_local_map(&mut body.local_decls, locals);
|
||||
// Update references to all vars and tmps now
|
||||
LocalUpdater { map }.visit_body(body);
|
||||
LocalUpdater { map, tcx }.visit_body(body);
|
||||
body.local_decls.shrink_to_fit();
|
||||
}
|
||||
}
|
||||
|
@ -374,11 +374,16 @@ impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
struct LocalUpdater {
|
||||
struct LocalUpdater<'tcx> {
|
||||
map: IndexVec<Local, Option<Local>>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for LocalUpdater {
|
||||
fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
|
||||
// Remove unnecessary StorageLive and StorageDead annotations.
|
||||
data.statements.retain(|stmt| {
|
||||
|
|
|
@ -61,7 +61,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
|
|||
rvalue: &Rvalue<'tcx>,
|
||||
location: Location) {
|
||||
if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue {
|
||||
if let box [proj_base @ .., elem] = &src_place.projection {
|
||||
if let &[ref proj_base @ .., elem] = src_place.projection.as_ref() {
|
||||
if let ProjectionElem::ConstantIndex{offset: _,
|
||||
min_length: _,
|
||||
from_end: false} = elem {
|
||||
|
@ -116,16 +116,13 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
|
|||
min_length: size,
|
||||
from_end: false,
|
||||
});
|
||||
self.patch.add_assign(location,
|
||||
self.patch.add_assign(
|
||||
location,
|
||||
Place::from(temp),
|
||||
Rvalue::Use(
|
||||
Operand::Move(
|
||||
Place {
|
||||
Rvalue::Use(Operand::Move(Place {
|
||||
base: base.clone(),
|
||||
projection: projection.into_boxed_slice(),
|
||||
}
|
||||
)
|
||||
)
|
||||
projection: self.tcx.intern_place_elems(&projection),
|
||||
})),
|
||||
);
|
||||
temp
|
||||
}).collect();
|
||||
|
@ -153,16 +150,13 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
|
|||
min_length: size,
|
||||
from_end: false,
|
||||
});
|
||||
self.patch.add_assign(location,
|
||||
self.patch.add_assign(
|
||||
location,
|
||||
dst_place.clone(),
|
||||
Rvalue::Use(
|
||||
Operand::Move(
|
||||
Place {
|
||||
Rvalue::Use(Operand::Move(Place {
|
||||
base: base.clone(),
|
||||
projection: projection.into_boxed_slice(),
|
||||
}
|
||||
)
|
||||
)
|
||||
projection: self.tcx.intern_place_elems(&projection),
|
||||
})),
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
|
@ -185,9 +179,11 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
|
|||
//
|
||||
// replaced by _10 = move _2[:-1];
|
||||
|
||||
pub struct RestoreSubsliceArrayMoveOut;
|
||||
pub struct RestoreSubsliceArrayMoveOut<'tcx> {
|
||||
tcx: TyCtxt<'tcx>
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut {
|
||||
impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut<'tcx> {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
|
||||
let mut patch = MirPatch::new(body);
|
||||
let param_env = tcx.param_env(src.def_id());
|
||||
|
@ -203,11 +199,9 @@ impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut {
|
|||
if let StatementKind::Assign(box(ref dst_place, ref rval)) = statement.kind {
|
||||
if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval {
|
||||
let items : Vec<_> = items.iter().map(|item| {
|
||||
if let Operand::Move(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
}) = item {
|
||||
let local_use = &visitor.locals_use[*local];
|
||||
if let Operand::Move(place) = item {
|
||||
if let Some(local) = place.as_local() {
|
||||
let local_use = &visitor.locals_use[local];
|
||||
let opt_index_and_place =
|
||||
Self::try_get_item_source(local_use, body);
|
||||
// each local should be used twice:
|
||||
|
@ -217,6 +211,7 @@ impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut {
|
|||
return Some((local_use, index, src_place));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}).collect();
|
||||
|
||||
|
@ -230,7 +225,9 @@ impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut {
|
|||
None
|
||||
}
|
||||
});
|
||||
Self::check_and_patch(*candidate, &items, opt_size, &mut patch, dst_place);
|
||||
let restore_subslice = RestoreSubsliceArrayMoveOut { tcx };
|
||||
restore_subslice
|
||||
.check_and_patch(*candidate, &items, opt_size, &mut patch, dst_place);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -239,11 +236,16 @@ impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut {
|
|||
}
|
||||
}
|
||||
|
||||
impl RestoreSubsliceArrayMoveOut {
|
||||
impl RestoreSubsliceArrayMoveOut<'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'tcx>) -> Self {
|
||||
RestoreSubsliceArrayMoveOut { tcx }
|
||||
}
|
||||
|
||||
// Checks that source has size, all locals are inited from same source place and
|
||||
// indices is an integer interval. If all checks pass do the replacent.
|
||||
// items are Vec<Option<LocalUse, index in source array, source place for init local>>
|
||||
fn check_and_patch<'tcx>(candidate: Location,
|
||||
fn check_and_patch(&self,
|
||||
candidate: Location,
|
||||
items: &[Option<(&LocalUse, u32, PlaceRef<'_, 'tcx>)>],
|
||||
opt_size: Option<u64>,
|
||||
patch: &mut MirPatch<'tcx>,
|
||||
|
@ -280,43 +282,35 @@ impl RestoreSubsliceArrayMoveOut {
|
|||
dst_place.clone(),
|
||||
Rvalue::Use(Operand::Move(Place {
|
||||
base: src_place.base.clone(),
|
||||
projection: projection.into_boxed_slice(),
|
||||
projection: self.tcx.intern_place_elems(&projection),
|
||||
})),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_item_source<'a, 'tcx>(local_use: &LocalUse,
|
||||
fn try_get_item_source<'a>(local_use: &LocalUse,
|
||||
body: &'a Body<'tcx>) -> Option<(u32, PlaceRef<'a, 'tcx>)> {
|
||||
if let Some(location) = local_use.first_use {
|
||||
let block = &body[location.block];
|
||||
if block.statements.len() > location.statement_index {
|
||||
let statement = &block.statements[location.statement_index];
|
||||
if let StatementKind::Assign(
|
||||
box(
|
||||
Place {
|
||||
base: PlaceBase::Local(_),
|
||||
projection: box [],
|
||||
},
|
||||
Rvalue::Use(Operand::Move(Place {
|
||||
box(place, Rvalue::Use(Operand::Move(src_place)))
|
||||
) = &statement.kind {
|
||||
if let (Some(_), PlaceRef {
|
||||
base: _,
|
||||
projection: box [.., ProjectionElem::ConstantIndex {
|
||||
projection: &[.., ProjectionElem::ConstantIndex {
|
||||
offset, min_length: _, from_end: false
|
||||
}],
|
||||
})),
|
||||
)
|
||||
) = &statement.kind {
|
||||
// FIXME remove once we can use slices patterns
|
||||
}) = (place.as_local(), src_place.as_ref()) {
|
||||
if let StatementKind::Assign(
|
||||
box(
|
||||
_,
|
||||
Rvalue::Use(Operand::Move(Place {
|
||||
base,
|
||||
projection: box [proj_base @ .., _],
|
||||
})),
|
||||
)
|
||||
box(_, Rvalue::Use(Operand::Move(place)))
|
||||
) = &statement.kind {
|
||||
return Some((*offset, PlaceRef {
|
||||
if let PlaceRef {
|
||||
base,
|
||||
projection: &[ref proj_base @ .., _],
|
||||
} = place.as_ref() {
|
||||
return Some((offset, PlaceRef {
|
||||
base,
|
||||
projection: proj_base,
|
||||
}))
|
||||
|
@ -324,6 +318,8 @@ impl RestoreSubsliceArrayMoveOut {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use rustc::mir::*;
|
||||
use rustc::ty::Ty;
|
||||
use rustc::ty::{Ty, TyCtxt};
|
||||
use rustc::ty::layout::VariantIdx;
|
||||
use rustc_index::vec::Idx;
|
||||
|
||||
|
@ -17,6 +17,7 @@ pub fn expand_aggregate<'tcx>(
|
|||
operands: impl Iterator<Item=(Operand<'tcx>, Ty<'tcx>)> + TrustedLen,
|
||||
kind: AggregateKind<'tcx>,
|
||||
source_info: SourceInfo,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> impl Iterator<Item=Statement<'tcx>> + TrustedLen {
|
||||
let mut set_discriminant = None;
|
||||
let active_field_index = match kind {
|
||||
|
@ -29,7 +30,7 @@ pub fn expand_aggregate<'tcx>(
|
|||
},
|
||||
source_info,
|
||||
});
|
||||
lhs = lhs.downcast(adt_def, variant_index);
|
||||
lhs = tcx.mk_place_downcast(lhs, adt_def, variant_index);
|
||||
}
|
||||
active_field_index
|
||||
}
|
||||
|
@ -58,7 +59,7 @@ pub fn expand_aggregate<'tcx>(
|
|||
// FIXME(eddyb) `offset` should be u64.
|
||||
let offset = i as u32;
|
||||
assert_eq!(offset as usize, i);
|
||||
lhs.clone().elem(ProjectionElem::ConstantIndex {
|
||||
tcx.mk_place_elem(lhs.clone(), ProjectionElem::ConstantIndex {
|
||||
offset,
|
||||
// FIXME(eddyb) `min_length` doesn't appear to be used.
|
||||
min_length: offset + 1,
|
||||
|
@ -66,7 +67,7 @@ pub fn expand_aggregate<'tcx>(
|
|||
})
|
||||
} else {
|
||||
let field = Field::new(active_field_index.unwrap_or(i));
|
||||
lhs.clone().field(field, ty)
|
||||
tcx.mk_place_field(lhs.clone(), field, ty)
|
||||
};
|
||||
Statement {
|
||||
source_info,
|
||||
|
|
|
@ -38,8 +38,8 @@ fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: &Place<'
|
|||
where
|
||||
L: HasLocalDecls<'tcx>,
|
||||
{
|
||||
let mut cursor = &*place.projection;
|
||||
while let [proj_base @ .., elem] = cursor {
|
||||
let mut cursor = place.projection.as_ref();
|
||||
while let &[ref proj_base @ .., elem] = cursor {
|
||||
cursor = proj_base;
|
||||
|
||||
match elem {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use rustc::mir::{Body, Local, Location, PlaceElem};
|
||||
use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use std::mem;
|
||||
|
||||
|
@ -47,20 +48,26 @@ impl DefUseAnalysis {
|
|||
&self.info[local]
|
||||
}
|
||||
|
||||
fn mutate_defs_and_uses(&self, local: Local, body: &mut Body<'_>, new_local: Local) {
|
||||
fn mutate_defs_and_uses(
|
||||
&self,
|
||||
local: Local,
|
||||
body: &mut Body<'tcx>,
|
||||
new_local: Local,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) {
|
||||
for place_use in &self.info[local].defs_and_uses {
|
||||
MutateUseVisitor::new(local,
|
||||
new_local,
|
||||
body).visit_location(body, place_use.location)
|
||||
MutateUseVisitor::new(local, new_local, body, tcx)
|
||||
.visit_location(body, place_use.location)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(pcwalton): this should update the def-use chains.
|
||||
pub fn replace_all_defs_and_uses_with(&self,
|
||||
local: Local,
|
||||
body: &mut Body<'_>,
|
||||
new_local: Local) {
|
||||
self.mutate_defs_and_uses(local, body, new_local)
|
||||
body: &mut Body<'tcx>,
|
||||
new_local: Local,
|
||||
tcx: TyCtxt<'tcx>) {
|
||||
self.mutate_defs_and_uses(local, body, new_local, tcx)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,21 +121,28 @@ impl Info {
|
|||
}
|
||||
}
|
||||
|
||||
struct MutateUseVisitor {
|
||||
struct MutateUseVisitor<'tcx> {
|
||||
query: Local,
|
||||
new_local: Local,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl MutateUseVisitor {
|
||||
fn new(query: Local, new_local: Local, _: &Body<'_>) -> MutateUseVisitor {
|
||||
MutateUseVisitor {
|
||||
query,
|
||||
new_local,
|
||||
}
|
||||
impl MutateUseVisitor<'tcx> {
|
||||
fn new(
|
||||
query: Local,
|
||||
new_local: Local,
|
||||
_: &Body<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> MutateUseVisitor<'tcx> {
|
||||
MutateUseVisitor { query, new_local, tcx }
|
||||
}
|
||||
}
|
||||
|
||||
impl MutVisitor<'_> for MutateUseVisitor {
|
||||
impl MutVisitor<'tcx> for MutateUseVisitor<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_local(&mut self,
|
||||
local: &mut Local,
|
||||
_context: PlaceContext,
|
||||
|
|
|
@ -200,13 +200,14 @@ where
|
|||
variant.fields.iter().enumerate().map(|(i, f)| {
|
||||
let field = Field::new(i);
|
||||
let subpath = self.elaborator.field_subpath(variant_path, field);
|
||||
let tcx = self.tcx();
|
||||
|
||||
assert_eq!(self.elaborator.param_env().reveal, Reveal::All);
|
||||
let field_ty = self.tcx().normalize_erasing_regions(
|
||||
let field_ty = tcx.normalize_erasing_regions(
|
||||
self.elaborator.param_env(),
|
||||
f.ty(self.tcx(), substs),
|
||||
f.ty(tcx, substs),
|
||||
);
|
||||
(base_place.clone().field(field, field_ty), subpath)
|
||||
(tcx.mk_place_field(base_place.clone(), field, field_ty), subpath)
|
||||
}).collect()
|
||||
}
|
||||
|
||||
|
@ -323,7 +324,7 @@ where
|
|||
debug!("open_drop_for_tuple({:?}, {:?})", self, tys);
|
||||
|
||||
let fields = tys.iter().enumerate().map(|(i, &ty)| {
|
||||
(self.place.clone().field(Field::new(i), ty),
|
||||
(self.tcx().mk_place_field(self.place.clone(), Field::new(i), ty),
|
||||
self.elaborator.field_subpath(self.path, Field::new(i)))
|
||||
}).collect();
|
||||
|
||||
|
@ -334,7 +335,7 @@ where
|
|||
fn open_drop_for_box(&mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>) -> BasicBlock {
|
||||
debug!("open_drop_for_box({:?}, {:?}, {:?})", self, adt, substs);
|
||||
|
||||
let interior = self.place.clone().deref();
|
||||
let interior = self.tcx().mk_place_deref(self.place.clone());
|
||||
let interior_path = self.elaborator.deref_subpath(self.path);
|
||||
|
||||
let succ = self.succ; // FIXME(#43234)
|
||||
|
@ -406,14 +407,19 @@ where
|
|||
};
|
||||
|
||||
let mut have_otherwise = false;
|
||||
let tcx = self.tcx();
|
||||
|
||||
for (variant_index, discr) in adt.discriminants(self.tcx()) {
|
||||
for (variant_index, discr) in adt.discriminants(tcx) {
|
||||
let subpath = self.elaborator.downcast_subpath(
|
||||
self.path, variant_index);
|
||||
if let Some(variant_path) = subpath {
|
||||
let base_place = self.place.clone().elem(
|
||||
ProjectionElem::Downcast(Some(adt.variants[variant_index].ident.name),
|
||||
variant_index));
|
||||
let base_place = tcx.mk_place_elem(
|
||||
self.place.clone(),
|
||||
ProjectionElem::Downcast(
|
||||
Some(adt.variants[variant_index].ident.name),
|
||||
variant_index,
|
||||
),
|
||||
);
|
||||
let fields = self.move_paths_for_fields(
|
||||
&base_place,
|
||||
variant_path,
|
||||
|
@ -586,7 +592,7 @@ where
|
|||
BorrowKind::Mut { allow_two_phase_borrow: false },
|
||||
Place {
|
||||
base: PlaceBase::Local(cur),
|
||||
projection: Box::new([ProjectionElem::Deref]),
|
||||
projection: tcx.intern_place_elems(&vec![ProjectionElem::Deref]),
|
||||
}
|
||||
),
|
||||
Rvalue::BinaryOp(BinOp::Offset, move_(&Place::from(cur)), one))
|
||||
|
@ -594,7 +600,7 @@ where
|
|||
(Rvalue::Ref(
|
||||
tcx.lifetimes.re_erased,
|
||||
BorrowKind::Mut { allow_two_phase_borrow: false },
|
||||
self.place.clone().index(cur)),
|
||||
tcx.mk_place_index(self.place.clone(), cur)),
|
||||
Rvalue::BinaryOp(BinOp::Add, move_(&Place::from(cur)), one))
|
||||
};
|
||||
|
||||
|
@ -627,7 +633,7 @@ where
|
|||
let loop_block = self.elaborator.patch().new_block(loop_block);
|
||||
|
||||
self.elaborator.patch().patch_terminator(drop_block, TerminatorKind::Drop {
|
||||
location: ptr.clone().deref(),
|
||||
location: tcx.mk_place_deref(ptr.clone()),
|
||||
target: loop_block,
|
||||
unwind: unwind.into_option()
|
||||
});
|
||||
|
@ -644,18 +650,27 @@ where
|
|||
// ptr_based_loop
|
||||
// }
|
||||
|
||||
let tcx = self.tcx();
|
||||
|
||||
if let Some(size) = opt_size {
|
||||
let size: u32 = size.try_into().unwrap_or_else(|_| {
|
||||
bug!("move out check isn't implemented for array sizes bigger than u32::MAX");
|
||||
});
|
||||
let fields: Vec<(Place<'tcx>, Option<D::Path>)> = (0..size).map(|i| {
|
||||
(self.place.clone().elem(ProjectionElem::ConstantIndex{
|
||||
let fields: Vec<(Place<'tcx>, Option<D::Path>)> = (0..size)
|
||||
.map(|i| {
|
||||
(
|
||||
tcx.mk_place_elem(
|
||||
self.place.clone(),
|
||||
ProjectionElem::ConstantIndex {
|
||||
offset: i,
|
||||
min_length: size,
|
||||
from_end: false
|
||||
}),
|
||||
self.elaborator.array_subpath(self.path, i, size))
|
||||
}).collect();
|
||||
from_end: false,
|
||||
},
|
||||
),
|
||||
self.elaborator.array_subpath(self.path, i, size),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
if fields.iter().any(|(_,path)| path.is_some()) {
|
||||
let (succ, unwind) = self.drop_ladder_bottom();
|
||||
|
@ -664,7 +679,6 @@ where
|
|||
}
|
||||
|
||||
let move_ = |place: &Place<'tcx>| Operand::Move(place.clone());
|
||||
let tcx = self.tcx();
|
||||
let elem_size = &Place::from(self.new_temp(tcx.types.usize));
|
||||
let len = &Place::from(self.new_temp(tcx.types.usize));
|
||||
|
||||
|
@ -900,8 +914,8 @@ where
|
|||
);
|
||||
let args = adt.variants[VariantIdx::new(0)].fields.iter().enumerate().map(|(i, f)| {
|
||||
let field = Field::new(i);
|
||||
let field_ty = f.ty(self.tcx(), substs);
|
||||
Operand::Move(self.place.clone().field(field, field_ty))
|
||||
let field_ty = f.ty(tcx, substs);
|
||||
Operand::Move(tcx.mk_place_field(self.place.clone(), field, field_ty))
|
||||
}).collect();
|
||||
|
||||
let call = TerminatorKind::Call {
|
||||
|
|
|
@ -26,9 +26,10 @@ use rustc::ty::{self, DefIdTree, TyCtxt, Region, RegionVid, Ty, AdtKind};
|
|||
use rustc::ty::fold::TypeFolder;
|
||||
use rustc::ty::layout::VariantIdx;
|
||||
use rustc::util::nodemap::{FxHashMap, FxHashSet};
|
||||
use syntax::ast::{self, AttrStyle, Ident};
|
||||
use syntax::ast::{self, Attribute, AttrStyle, AttrItem, Ident};
|
||||
use syntax::attr;
|
||||
use syntax_expand::base::MacroKind;
|
||||
use syntax::parse::lexer::comments;
|
||||
use syntax::source_map::DUMMY_SP;
|
||||
use syntax::symbol::{Symbol, kw, sym};
|
||||
use syntax_pos::{self, Pos, FileName};
|
||||
|
@ -858,8 +859,31 @@ impl Attributes {
|
|||
let mut cfg = Cfg::True;
|
||||
let mut doc_line = 0;
|
||||
|
||||
/// Converts `attr` to a normal `#[doc="foo"]` comment, if it is a
|
||||
/// comment like `///` or `/** */`. (Returns `attr` unchanged for
|
||||
/// non-sugared doc attributes.)
|
||||
pub fn with_desugared_doc<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| {
|
||||
attr.with_desugared_doc(|attr| {
|
||||
with_desugared_doc(attr, |attr| {
|
||||
if attr.check_name(sym::doc) {
|
||||
if let Some(mi) = attr.meta() {
|
||||
if let Some(value) = mi.value_str() {
|
||||
|
|
|
@ -79,7 +79,7 @@ function getSearchElement() {
|
|||
"derive",
|
||||
"traitalias"];
|
||||
|
||||
var disableShortcuts = getCurrentValue("rustdoc-disable-shortcuts") !== "true";
|
||||
var disableShortcuts = getCurrentValue("rustdoc-disable-shortcuts") === "true";
|
||||
var search_input = getSearchInput();
|
||||
|
||||
// On the search screen, so you remain on the last tab you opened.
|
||||
|
|
|
@ -283,7 +283,7 @@
|
|||
#![feature(needs_panic_runtime)]
|
||||
#![feature(never_type)]
|
||||
#![feature(nll)]
|
||||
#![feature(non_exhaustive)]
|
||||
#![cfg_attr(bootstrap, feature(non_exhaustive))]
|
||||
#![feature(on_unimplemented)]
|
||||
#![feature(optin_builtin_traits)]
|
||||
#![feature(panic_info_message)]
|
||||
|
|
|
@ -1363,20 +1363,24 @@ impl PathBuf {
|
|||
}
|
||||
|
||||
fn _set_extension(&mut self, extension: &OsStr) -> bool {
|
||||
if self.file_name().is_none() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut stem = match self.file_stem() {
|
||||
Some(stem) => stem.to_os_string(),
|
||||
None => OsString::new(),
|
||||
let file_stem = match self.file_stem() {
|
||||
None => return false,
|
||||
Some(f) => os_str_as_u8_slice(f),
|
||||
};
|
||||
|
||||
if !os_str_as_u8_slice(extension).is_empty() {
|
||||
stem.push(".");
|
||||
stem.push(extension);
|
||||
// truncate until right after the file stem
|
||||
let end_file_stem = file_stem[file_stem.len()..].as_ptr() as usize;
|
||||
let start = os_str_as_u8_slice(&self.inner).as_ptr() as usize;
|
||||
let v = self.as_mut_vec();
|
||||
v.truncate(end_file_stem.wrapping_sub(start));
|
||||
|
||||
// add the new extension, if any
|
||||
let new = os_str_as_u8_slice(extension);
|
||||
if !new.is_empty() {
|
||||
v.reserve_exact(new.len() + 1);
|
||||
v.push(b'.');
|
||||
v.extend_from_slice(new);
|
||||
}
|
||||
self.set_file_name(&stem);
|
||||
|
||||
true
|
||||
}
|
||||
|
|
|
@ -105,11 +105,14 @@ cfg_has_statx! {{
|
|||
flags: i32,
|
||||
mask: u32,
|
||||
) -> 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`
|
||||
// We store the availability in a global to avoid unnecessary syscalls
|
||||
static HAS_STATX: AtomicBool = AtomicBool::new(true);
|
||||
// We store the availability in global to avoid unnecessary syscalls.
|
||||
// 0: Unknown
|
||||
// 1: Not available
|
||||
// 2: Available
|
||||
static STATX_STATE: AtomicU8 = AtomicU8::new(0);
|
||||
syscall! {
|
||||
fn statx(
|
||||
fd: c_int,
|
||||
|
@ -120,21 +123,33 @@ cfg_has_statx! {{
|
|||
) -> c_int
|
||||
}
|
||||
|
||||
if !HAS_STATX.load(Ordering::Relaxed) {
|
||||
match STATX_STATE.load(Ordering::Relaxed) {
|
||||
0 => {
|
||||
// It is a trick to call `statx` with NULL pointers to check if the syscall
|
||||
// is available. According to the manual, it is expected to fail with EFAULT.
|
||||
// We do this mainly for performance, since it is nearly hundreds times
|
||||
// faster than a normal successfull call.
|
||||
let err = cvt(statx(0, ptr::null(), 0, libc::STATX_ALL, ptr::null_mut()))
|
||||
.err()
|
||||
.and_then(|e| e.raw_os_error());
|
||||
// We don't check `err == Some(libc::ENOSYS)` because the syscall may be limited
|
||||
// and returns `EPERM`. Listing all possible errors seems not a good idea.
|
||||
// See: https://github.com/rust-lang/rust/issues/65662
|
||||
if err != Some(libc::EFAULT) {
|
||||
STATX_STATE.store(1, Ordering::Relaxed);
|
||||
return None;
|
||||
}
|
||||
STATX_STATE.store(2, Ordering::Relaxed);
|
||||
}
|
||||
1 => return None,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let mut buf: libc::statx = mem::zeroed();
|
||||
let ret = cvt(statx(fd, path, flags, mask, &mut buf));
|
||||
match ret {
|
||||
Err(err) => match err.raw_os_error() {
|
||||
Some(libc::ENOSYS) => {
|
||||
HAS_STATX.store(false, Ordering::Relaxed);
|
||||
return None;
|
||||
if let Err(err) = cvt(statx(fd, path, flags, mask, &mut buf)) {
|
||||
return Some(Err(err));
|
||||
}
|
||||
_ => 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
|
||||
|
@ -163,8 +178,6 @@ cfg_has_statx! {{
|
|||
|
||||
Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) }))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
#[derive(Clone)]
|
||||
|
|
|
@ -13,8 +13,8 @@ use crate::ast::{AttrItem, AttrId, AttrStyle, Name, Ident, Path, PathSegment};
|
|||
use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem};
|
||||
use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam};
|
||||
use crate::mut_visit::visit_clobber;
|
||||
use crate::source_map::{BytePos, Spanned, DUMMY_SP};
|
||||
use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
|
||||
use crate::source_map::{BytePos, Spanned};
|
||||
use crate::parse::lexer::comments::doc_comment_style;
|
||||
use crate::parse::parser::Parser;
|
||||
use crate::parse::PResult;
|
||||
use crate::parse::token::{self, Token};
|
||||
|
@ -312,31 +312,6 @@ impl Attribute {
|
|||
span: self.span,
|
||||
})
|
||||
}
|
||||
|
||||
/// Converts `self` to a normal `#[doc="foo"]` comment, if it is a
|
||||
/// comment like `///` or `/** */`. (Returns `self` unchanged for
|
||||
/// non-sugared doc attributes.)
|
||||
pub fn with_desugared_doc<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 */
|
||||
|
|
|
@ -245,8 +245,10 @@ declare_features! (
|
|||
(accepted, bind_by_move_pattern_guards, "1.39.0", Some(15287), None),
|
||||
/// Allows attributes in formal function parameters.
|
||||
(accepted, param_attrs, "1.39.0", Some(60406), None),
|
||||
// Allows macro invocations in `extern {}` blocks.
|
||||
/// Allows macro invocations in `extern {}` blocks.
|
||||
(accepted, macros_in_extern, "1.40.0", Some(49476), None),
|
||||
/// Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008).
|
||||
(accepted, non_exhaustive, "1.40.0", Some(44109), None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: accepted features
|
||||
|
|
|
@ -383,9 +383,6 @@ declare_features! (
|
|||
/// Allows `#[doc(include = "some-file")]`.
|
||||
(active, external_doc, "1.22.0", Some(44732), None),
|
||||
|
||||
/// Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008).
|
||||
(active, non_exhaustive, "1.22.0", Some(44109), None),
|
||||
|
||||
/// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`.
|
||||
(active, crate_visibility_modifier, "1.23.0", Some(53120), None),
|
||||
|
||||
|
|
|
@ -252,6 +252,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
ungated!(path, Normal, template!(NameValueStr: "file")),
|
||||
ungated!(no_std, CrateLevel, template!(Word)),
|
||||
ungated!(no_implicit_prelude, Normal, template!(Word)),
|
||||
ungated!(non_exhaustive, Whitelisted, template!(Word)),
|
||||
|
||||
// Runtime
|
||||
ungated!(windows_subsystem, Whitelisted, template!(NameValueStr: "windows|console")),
|
||||
|
@ -314,9 +315,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
test_runner, CrateLevel, template!(List: "path"), custom_test_frameworks,
|
||||
"custom test frameworks are an unstable feature",
|
||||
),
|
||||
|
||||
// RFC #2008
|
||||
gated!(non_exhaustive, Whitelisted, template!(Word), experimental!(non_exhaustive)),
|
||||
// RFC #1268
|
||||
gated!(marker, Normal, template!(Word), marker_trait_attr, experimental!(marker)),
|
||||
gated!(
|
||||
|
|
|
@ -25,6 +25,9 @@ use std::sync::{Arc, Mutex};
|
|||
|
||||
use rustc_serialize::json::{as_json, as_pretty_json};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub struct JsonEmitter {
|
||||
dst: Box<dyn Write + Send>,
|
||||
registry: Option<Registry>,
|
||||
|
@ -336,8 +339,8 @@ impl DiagnosticSpan {
|
|||
|
||||
DiagnosticSpan {
|
||||
file_name: start.file.name.to_string(),
|
||||
byte_start: span.lo().0 - start.file.start_pos.0,
|
||||
byte_end: span.hi().0 - start.file.start_pos.0,
|
||||
byte_start: start.file.original_relative_byte_pos(span.lo()).0,
|
||||
byte_end: start.file.original_relative_byte_pos(span.hi()).0,
|
||||
line_start: start.line,
|
||||
line_end: end.line,
|
||||
column_start: start.col.0 + 1,
|
||||
|
|
186
src/libsyntax/json/tests.rs
Normal file
186
src/libsyntax/json/tests.rs
Normal 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,
|
||||
},
|
||||
)
|
||||
}
|
|
@ -31,23 +31,6 @@ mod tests;
|
|||
|
||||
pub const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments");
|
||||
|
||||
// A variant of 'panictry!' that works on a Vec<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_rules! unwrap_or {
|
||||
($opt:expr, $default:expr) => {
|
||||
|
|
|
@ -176,7 +176,7 @@ fn split_block_comment_into_lines(
|
|||
|
||||
// it appears this function is called only from pprust... that's
|
||||
// probably not a good thing.
|
||||
pub fn gather_comments(sess: &ParseSess, path: FileName, src: String) -> Vec<Comment> {
|
||||
crate fn gather_comments(sess: &ParseSess, path: FileName, src: String) -> Vec<Comment> {
|
||||
let cm = SourceMap::new(sess.source_map().path_mapping().clone());
|
||||
let source_file = cm.new_source_file(path, src);
|
||||
let text = (*source_file.src.as_ref().unwrap()).clone();
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use super::{StringReader, UnmatchedBrace};
|
||||
|
||||
use crate::print::pprust::token_to_string;
|
||||
use crate::parse::lexer::{StringReader, UnmatchedBrace};
|
||||
use crate::parse::token::{self, Token};
|
||||
use crate::parse::PResult;
|
||||
use crate::tokenstream::{DelimSpan, IsJoint::{self, *}, TokenStream, TokenTree, TreeAndJoint};
|
||||
|
|
|
@ -59,6 +59,23 @@ pub enum DirectoryOwnership {
|
|||
// uses a HOF to parse anything, and <source> includes file and
|
||||
// `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> {
|
||||
let mut parser = new_parser_from_file(sess, input);
|
||||
parser.parse_crate_mod()
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -19,6 +19,7 @@ use log::debug;
|
|||
use std::mem;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use errors::{Applicability, DiagnosticBuilder, DiagnosticId, StashKey};
|
||||
use syntax_pos::BytePos;
|
||||
|
||||
/// Whether the type alias or associated type is a concrete type or an opaque type.
|
||||
#[derive(Debug)]
|
||||
|
@ -1739,6 +1740,25 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn report_invalid_macro_expansion_item(&self) {
|
||||
self.struct_span_err(
|
||||
self.prev_span,
|
||||
"macros that expand to items must be delimited with braces or followed by a semicolon",
|
||||
).multipart_suggestion(
|
||||
"change the delimiters to curly braces",
|
||||
vec![
|
||||
(self.prev_span.with_hi(self.prev_span.lo() + BytePos(1)), String::from(" {")),
|
||||
(self.prev_span.with_lo(self.prev_span.hi() - BytePos(1)), '}'.to_string()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
).span_suggestion(
|
||||
self.sess.source_map().next_point(self.prev_span),
|
||||
"add a semicolon",
|
||||
';'.to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
).emit();
|
||||
}
|
||||
|
||||
fn mk_item(&self, span: Span, ident: Ident, kind: ItemKind, vis: Visibility,
|
||||
attrs: Vec<Attribute>) -> P<Item> {
|
||||
P(Item {
|
||||
|
|
|
@ -283,6 +283,7 @@ impl SourceMap {
|
|||
mut file_local_lines: Vec<BytePos>,
|
||||
mut file_local_multibyte_chars: Vec<MultiByteChar>,
|
||||
mut file_local_non_narrow_chars: Vec<NonNarrowChar>,
|
||||
mut file_local_normalized_pos: Vec<NormalizedPos>,
|
||||
) -> Lrc<SourceFile> {
|
||||
let start_pos = self.next_start_pos();
|
||||
|
||||
|
@ -301,6 +302,10 @@ impl SourceMap {
|
|||
*swc = *swc + start_pos;
|
||||
}
|
||||
|
||||
for nc in &mut file_local_normalized_pos {
|
||||
nc.pos = nc.pos + start_pos;
|
||||
}
|
||||
|
||||
let source_file = Lrc::new(SourceFile {
|
||||
name: filename,
|
||||
name_was_remapped,
|
||||
|
@ -314,6 +319,7 @@ impl SourceMap {
|
|||
lines: file_local_lines,
|
||||
multibyte_chars: file_local_multibyte_chars,
|
||||
non_narrow_chars: file_local_non_narrow_chars,
|
||||
normalized_pos: file_local_normalized_pos,
|
||||
name_hash,
|
||||
});
|
||||
|
||||
|
|
|
@ -111,8 +111,8 @@ struct SpanLabel {
|
|||
label: &'static str,
|
||||
}
|
||||
|
||||
struct Shared<T: Write> {
|
||||
data: Arc<Mutex<T>>,
|
||||
crate struct Shared<T: Write> {
|
||||
pub data: Arc<Mutex<T>>,
|
||||
}
|
||||
|
||||
impl<T: Write> Write for Shared<T> {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#![feature(const_fn)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(nll)]
|
||||
#![feature(non_exhaustive)]
|
||||
#![cfg_attr(bootstrap, feature(non_exhaustive))]
|
||||
#![feature(optin_builtin_traits)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![cfg_attr(bootstrap, feature(proc_macro_hygiene))]
|
||||
|
@ -855,6 +855,15 @@ impl Sub<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`.
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
pub enum ExternalSource {
|
||||
|
@ -918,6 +927,8 @@ pub struct SourceFile {
|
|||
pub multibyte_chars: Vec<MultiByteChar>,
|
||||
/// Width of characters that are not narrow in the source code.
|
||||
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.
|
||||
pub name_hash: u128,
|
||||
}
|
||||
|
@ -984,6 +995,9 @@ impl Encodable for SourceFile {
|
|||
})?;
|
||||
s.emit_struct_field("name_hash", 8, |s| {
|
||||
self.name_hash.encode(s)
|
||||
})?;
|
||||
s.emit_struct_field("normalized_pos", 9, |s| {
|
||||
self.normalized_pos.encode(s)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -1034,6 +1048,8 @@ impl Decodable for SourceFile {
|
|||
d.read_struct_field("non_narrow_chars", 7, |d| Decodable::decode(d))?;
|
||||
let name_hash: u128 =
|
||||
d.read_struct_field("name_hash", 8, |d| Decodable::decode(d))?;
|
||||
let normalized_pos: Vec<NormalizedPos> =
|
||||
d.read_struct_field("normalized_pos", 9, |d| Decodable::decode(d))?;
|
||||
Ok(SourceFile {
|
||||
name,
|
||||
name_was_remapped,
|
||||
|
@ -1050,6 +1066,7 @@ impl Decodable for SourceFile {
|
|||
lines,
|
||||
multibyte_chars,
|
||||
non_narrow_chars,
|
||||
normalized_pos,
|
||||
name_hash,
|
||||
})
|
||||
})
|
||||
|
@ -1068,8 +1085,7 @@ impl SourceFile {
|
|||
unmapped_path: FileName,
|
||||
mut src: String,
|
||||
start_pos: BytePos) -> Result<SourceFile, OffsetOverflowError> {
|
||||
remove_bom(&mut src);
|
||||
normalize_newlines(&mut src);
|
||||
let normalized_pos = normalize_src(&mut src, start_pos);
|
||||
|
||||
let src_hash = {
|
||||
let mut hasher: StableHasher = StableHasher::new();
|
||||
|
@ -1102,6 +1118,7 @@ impl SourceFile {
|
|||
lines,
|
||||
multibyte_chars,
|
||||
non_narrow_chars,
|
||||
normalized_pos,
|
||||
name_hash,
|
||||
})
|
||||
}
|
||||
|
@ -1228,12 +1245,44 @@ impl SourceFile {
|
|||
pub fn contains(&self, byte_pos: BytePos) -> bool {
|
||||
byte_pos >= self.start_pos && byte_pos <= self.end_pos
|
||||
}
|
||||
|
||||
/// Calculates the original byte position relative to the start of the file
|
||||
/// based on the given byte position.
|
||||
pub fn original_relative_byte_pos(&self, pos: BytePos) -> BytePos {
|
||||
|
||||
// Diff before any records is 0. Otherwise use the previously recorded
|
||||
// diff as that applies to the following characters until a new diff
|
||||
// is recorded.
|
||||
let diff = match self.normalized_pos.binary_search_by(
|
||||
|np| np.pos.cmp(&pos)) {
|
||||
Ok(i) => self.normalized_pos[i].diff,
|
||||
Err(i) if i == 0 => 0,
|
||||
Err(i) => self.normalized_pos[i-1].diff,
|
||||
};
|
||||
|
||||
BytePos::from_u32(pos.0 - self.start_pos.0 + diff)
|
||||
}
|
||||
}
|
||||
|
||||
/// Normalizes the source code and records the normalizations.
|
||||
fn normalize_src(src: &mut String, start_pos: BytePos) -> Vec<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.
|
||||
fn remove_bom(src: &mut String) {
|
||||
fn remove_bom(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
|
||||
if src.starts_with("\u{feff}") {
|
||||
src.drain(..3);
|
||||
normalized_pos.push(NormalizedPos { pos: BytePos(0), diff: 3 });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1241,7 +1290,7 @@ fn remove_bom(src: &mut String) {
|
|||
/// Replaces `\r\n` with `\n` in-place in `src`.
|
||||
///
|
||||
/// Returns error if there's a lone `\r` in the string
|
||||
fn normalize_newlines(src: &mut String) {
|
||||
fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
|
||||
if !src.as_bytes().contains(&b'\r') {
|
||||
return;
|
||||
}
|
||||
|
@ -1254,6 +1303,8 @@ fn normalize_newlines(src: &mut String) {
|
|||
let mut buf = std::mem::replace(src, String::new()).into_bytes();
|
||||
let mut gap_len = 0;
|
||||
let mut tail = buf.as_mut_slice();
|
||||
let mut cursor = 0;
|
||||
let original_gap = normalized_pos.last().map_or(0, |l| l.diff);
|
||||
loop {
|
||||
let idx = match find_crlf(&tail[gap_len..]) {
|
||||
None => tail.len(),
|
||||
|
@ -1264,7 +1315,12 @@ fn normalize_newlines(src: &mut String) {
|
|||
if tail.len() == gap_len {
|
||||
break;
|
||||
}
|
||||
cursor += idx - gap_len;
|
||||
gap_len += 1;
|
||||
normalized_pos.push(NormalizedPos {
|
||||
pos: BytePos::from_usize(cursor + 1),
|
||||
diff: original_gap + gap_len as u32,
|
||||
});
|
||||
}
|
||||
|
||||
// Account for removed `\r`.
|
||||
|
|
|
@ -19,20 +19,25 @@ fn test_lookup_line() {
|
|||
|
||||
#[test]
|
||||
fn test_normalize_newlines() {
|
||||
fn check(before: &str, after: &str) {
|
||||
fn check(before: &str, after: &str, expected_positions: &[u32]) {
|
||||
let mut actual = before.to_string();
|
||||
normalize_newlines(&mut actual);
|
||||
let mut actual_positions = vec![];
|
||||
normalize_newlines(&mut actual, &mut actual_positions);
|
||||
let actual_positions : Vec<_> = actual_positions
|
||||
.into_iter()
|
||||
.map(|nc| nc.pos.0).collect();
|
||||
assert_eq!(actual.as_str(), after);
|
||||
assert_eq!(actual_positions, expected_positions);
|
||||
}
|
||||
check("", "");
|
||||
check("\n", "\n");
|
||||
check("\r", "\r");
|
||||
check("\r\r", "\r\r");
|
||||
check("\r\n", "\n");
|
||||
check("hello world", "hello world");
|
||||
check("hello\nworld", "hello\nworld");
|
||||
check("hello\r\nworld", "hello\nworld");
|
||||
check("\r\nhello\r\nworld\r\n", "\nhello\nworld\n");
|
||||
check("\r\r\n", "\r\n");
|
||||
check("hello\rworld", "hello\rworld");
|
||||
check("", "", &[]);
|
||||
check("\n", "\n", &[]);
|
||||
check("\r", "\r", &[]);
|
||||
check("\r\r", "\r\r", &[]);
|
||||
check("\r\n", "\n", &[1]);
|
||||
check("hello world", "hello world", &[]);
|
||||
check("hello\nworld", "hello\nworld", &[]);
|
||||
check("hello\r\nworld", "hello\nworld", &[6]);
|
||||
check("\r\nhello\r\nworld\r\n", "\nhello\nworld\n", &[1, 7, 13]);
|
||||
check("\r\r\n", "\r\n", &[2]);
|
||||
check("hello\rworld", "hello\rworld", &[]);
|
||||
}
|
||||
|
|
3
src/test/ui/.gitattributes
vendored
3
src/test/ui/.gitattributes
vendored
|
@ -1,3 +1,6 @@
|
|||
lexer-crlf-line-endings-string-literal-doc-comment.rs -text
|
||||
json-bom-plus-crlf.rs -text
|
||||
json-bom-plus-crlf-multifile.rs -text
|
||||
json-bom-plus-crlf-multifile-aux.rs -text
|
||||
trailing-carriage-return-in-string.rs -text
|
||||
*.bin -text
|
||||
|
|
|
@ -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() { }
|
|
@ -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`.
|
27
src/test/ui/json-bom-plus-crlf-multifile-aux.rs
Normal file
27
src/test/ui/json-bom-plus-crlf-multifile-aux.rs
Normal 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.
|
||||
}
|
12
src/test/ui/json-bom-plus-crlf-multifile.rs
Normal file
12
src/test/ui/json-bom-plus-crlf-multifile.rs
Normal 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();
|
||||
}
|
86
src/test/ui/json-bom-plus-crlf-multifile.stderr
Normal file
86
src/test/ui/json-bom-plus-crlf-multifile.stderr
Normal 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
|
||||
"}
|
27
src/test/ui/json-bom-plus-crlf.rs
Normal file
27
src/test/ui/json-bom-plus-crlf.rs
Normal 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.
|
||||
}
|
86
src/test/ui/json-bom-plus-crlf.stderr
Normal file
86
src/test/ui/json-bom-plus-crlf.stderr
Normal 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
|
||||
"}
|
|
@ -1,5 +1,4 @@
|
|||
#![crate_type = "rlib"]
|
||||
#![feature(non_exhaustive)]
|
||||
|
||||
#[non_exhaustive]
|
||||
pub enum NonExhaustiveEnum {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#![feature(non_exhaustive)]
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct NormalStruct {
|
||||
pub first_field: u16,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#![crate_type = "rlib"]
|
||||
#![feature(non_exhaustive)]
|
||||
|
||||
pub enum NonExhaustiveVariants {
|
||||
#[non_exhaustive] Unit,
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
// run-pass
|
||||
|
||||
#![feature(non_exhaustive)]
|
||||
|
||||
#[non_exhaustive]
|
||||
pub enum NonExhaustiveEnum {
|
||||
Unit,
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#![feature(non_exhaustive)]
|
||||
|
||||
#[non_exhaustive]
|
||||
#[repr(C)]
|
||||
pub enum NonExhaustiveEnum {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// check-pass
|
||||
#![feature(non_exhaustive)]
|
||||
#![deny(improper_ctypes)]
|
||||
|
||||
// This test checks that non-exhaustive types with `#[repr(C)]` are considered proper within
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#![feature(non_exhaustive)]
|
||||
|
||||
#[non_exhaustive(anything)]
|
||||
//~^ ERROR malformed `non_exhaustive` attribute
|
||||
struct Foo;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue