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