1
Fork 0

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

Rollup of 9 pull requests

Successful merges:

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

Failed merges:

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

View file

@ -1,76 +0,0 @@
# `non_exhaustive`
The tracking issue for this feature is: [#44109]
[#44109]: https://github.com/rust-lang/rust/issues/44109
------------------------
The `non_exhaustive` gate allows you to use the `#[non_exhaustive]` attribute
on structs, enums and enum variants. When applied within a crate, users of the
crate will need to use the `_` pattern when matching enums and use the `..`
pattern when matching structs. Enum variants cannot be matched against.
Structs and enum variants marked as `non_exhaustive` will not be able to
be created normally outside of the defining crate. This is demonstrated
below:
```rust,ignore (pseudo-Rust)
use std::error::Error as StdError;
#[non_exhaustive]
pub enum Error {
Message(String),
Other,
}
impl StdError for Error {
fn description(&self) -> &str {
// This will not error, despite being marked as non_exhaustive, as this
// enum is defined within the current crate, it can be matched
// exhaustively.
match *self {
Message(ref s) => s,
Other => "other or unknown error",
}
}
}
```
```rust,ignore (pseudo-Rust)
use mycrate::Error;
// This will not error as the non_exhaustive Error enum has been matched with
// a wildcard.
match error {
Message(ref s) => ...,
Other => ...,
_ => ...,
}
```
```rust,ignore (pseudo-Rust)
#[non_exhaustive]
pub struct Config {
pub window_width: u16,
pub window_height: u16,
}
// We can create structs as normal within the defining crate when marked as
// non_exhaustive.
let config = Config { window_width: 640, window_height: 480 };
// We can match structs exhaustively when within the defining crate.
if let Ok(Config { window_width, window_height }) = load_config() {
// ...
}
```
```rust,ignore (pseudo-Rust)
use mycrate::Config;
// We cannot create a struct like normal if it has been marked as
// non_exhaustive.
let config = Config { window_width: 640, window_height: 480 };
// By adding the `..` we can match the config as below outside of the crate
// when marked non_exhaustive.
let &Config { window_width, window_height, .. } = config;
```

View file

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

View file

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

View file

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

View file

@ -425,6 +425,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
ref lines,
ref multibyte_chars,
ref non_narrow_chars,
ref normalized_pos,
} = *self;
(name_hash as u64).hash_stable(hcx, hasher);
@ -453,6 +454,12 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
for &char_pos in non_narrow_chars.iter() {
stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher);
}
normalized_pos.len().hash_stable(hcx, hasher);
for &char_pos in normalized_pos.iter() {
stable_normalized_pos(char_pos, start_pos).hash_stable(hcx, hasher);
}
}
}
@ -482,6 +489,18 @@ fn stable_non_narrow_char(swc: ::syntax_pos::NonNarrowChar,
(pos.0 - source_file_start.0, width as u32)
}
fn stable_normalized_pos(np: ::syntax_pos::NormalizedPos,
source_file_start: ::syntax_pos::BytePos)
-> (u32, u32) {
let ::syntax_pos::NormalizedPos {
pos,
diff
} = np;
(pos.0 - source_file_start.0, diff)
}
impl<'tcx> HashStable<StableHashingContext<'tcx>> for feature_gate::Features {
fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
// Unfortunately we cannot exhaustively list fields here, since the

View file

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

View file

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

View file

@ -784,6 +784,8 @@ macro_rules! make_mir_visitor {
macro_rules! visit_place_fns {
(mut) => (
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
fn super_place(
&mut self,
place: &mut Place<'tcx>,
@ -793,19 +795,21 @@ macro_rules! visit_place_fns {
self.visit_place_base(&mut place.base, context, location);
if let Some(new_projection) = self.process_projection(&place.projection) {
place.projection = new_projection;
place.projection = self.tcx().intern_place_elems(&new_projection);
}
}
fn process_projection(
&mut self,
projection: &'a [PlaceElem<'tcx>],
) -> Option<Box<[PlaceElem<'tcx>]>> {
) -> Option<Vec<PlaceElem<'tcx>>> {
let mut projection = Cow::Borrowed(projection);
for i in 0..projection.len() {
if let Some(elem) = projection.get(i) {
if let Some(elem) = self.process_projection_elem(elem) {
// This converts the borrowed projection into `Cow::Owned(_)` and returns a
// clone of the projection so we can mutate and reintern later.
let vec = projection.to_mut();
vec[i] = elem;
}
@ -814,7 +818,7 @@ macro_rules! visit_place_fns {
match projection {
Cow::Borrowed(_) => None,
Cow::Owned(vec) => Some(vec.into_boxed_slice()),
Cow::Owned(vec) => Some(vec),
}
}

View file

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

View file

@ -1,3 +1,4 @@
// ignore-tidy-filelength
//! Type context book-keeping.
use crate::arena::Arena;
@ -21,7 +22,7 @@ use crate::middle::cstore::EncodedMetadata;
use crate::middle::lang_items;
use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault};
use crate::middle::stability;
use crate::mir::{Body, interpret, ProjectionKind, Promoted};
use crate::mir::{Body, Field, interpret, Local, Place, PlaceElem, ProjectionKind, Promoted};
use crate::mir::interpret::{ConstValue, Allocation, Scalar};
use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef, Subst};
use crate::ty::ReprOptions;
@ -106,6 +107,7 @@ pub struct CtxtInterners<'tcx> {
goal: InternedSet<'tcx, GoalKind<'tcx>>,
goal_list: InternedSet<'tcx, List<Goal<'tcx>>>,
projs: InternedSet<'tcx, List<ProjectionKind>>,
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
const_: InternedSet<'tcx, Const<'tcx>>,
}
@ -124,6 +126,7 @@ impl<'tcx> CtxtInterners<'tcx> {
goal: Default::default(),
goal_list: Default::default(),
projs: Default::default(),
place_elems: Default::default(),
const_: Default::default(),
}
}
@ -2142,6 +2145,13 @@ impl<'tcx> Borrow<[ProjectionKind]>
}
}
impl<'tcx> Borrow<[PlaceElem<'tcx>]>
for Interned<'tcx, List<PlaceElem<'tcx>>> {
fn borrow(&self) -> &[PlaceElem<'tcx>] {
&self.0[..]
}
}
impl<'tcx> Borrow<RegionKind> for Interned<'tcx, RegionKind> {
fn borrow(&self) -> &RegionKind {
&self.0
@ -2242,7 +2252,8 @@ slice_interners!(
predicates: _intern_predicates(Predicate<'tcx>),
clauses: _intern_clauses(Clause<'tcx>),
goal_list: _intern_goals(Goal<'tcx>),
projs: _intern_projs(ProjectionKind)
projs: _intern_projs(ProjectionKind),
place_elems: _intern_place_elems(PlaceElem<'tcx>)
);
impl<'tcx> TyCtxt<'tcx> {
@ -2584,6 +2595,48 @@ impl<'tcx> TyCtxt<'tcx> {
self.mk_ty(Opaque(def_id, substs))
}
pub fn mk_place_field(self, place: Place<'tcx>, f: Field, ty: Ty<'tcx>) -> Place<'tcx> {
self.mk_place_elem(place, PlaceElem::Field(f, ty))
}
pub fn mk_place_deref(self, place: Place<'tcx>) -> Place<'tcx> {
self.mk_place_elem(place, PlaceElem::Deref)
}
pub fn mk_place_downcast(
self,
place: Place<'tcx>,
adt_def: &'tcx AdtDef,
variant_index: VariantIdx,
) -> Place<'tcx> {
self.mk_place_elem(
place,
PlaceElem::Downcast(Some(adt_def.variants[variant_index].ident.name), variant_index),
)
}
pub fn mk_place_downcast_unnamed(
self,
place: Place<'tcx>,
variant_index: VariantIdx,
) -> Place<'tcx> {
self.mk_place_elem(place, PlaceElem::Downcast(None, variant_index))
}
pub fn mk_place_index(self, place: Place<'tcx>, index: Local) -> Place<'tcx> {
self.mk_place_elem(place, PlaceElem::Index(index))
}
/// This method copies `Place`'s projection, add an element and reintern it. Should not be used
/// to build a full `Place` it's just a convenient way to grab a projection and modify it in
/// flight.
pub fn mk_place_elem(self, place: Place<'tcx>, elem: PlaceElem<'tcx>) -> Place<'tcx> {
let mut projection = place.projection.to_vec();
projection.push(elem);
Place { base: place.base, projection: self.intern_place_elems(&projection) }
}
pub fn intern_existential_predicates(self, eps: &[ExistentialPredicate<'tcx>])
-> &'tcx List<ExistentialPredicate<'tcx>> {
assert!(!eps.is_empty());
@ -2628,6 +2681,14 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
pub fn intern_place_elems(self, ts: &[PlaceElem<'tcx>]) -> &'tcx List<PlaceElem<'tcx>> {
if ts.len() == 0 {
List::empty()
} else {
self._intern_place_elems(ts)
}
}
pub fn intern_canonical_var_infos(self, ts: &[CanonicalVarInfo]) -> CanonicalVarInfos<'tcx> {
if ts.len() == 0 {
List::empty()
@ -2690,6 +2751,11 @@ impl<'tcx> TyCtxt<'tcx> {
iter.intern_with(|xs| self.intern_substs(xs))
}
pub fn mk_place_elems<I: InternAs<[PlaceElem<'tcx>],
&'tcx List<PlaceElem<'tcx>>>>(self, iter: I) -> I::Output {
iter.intern_with(|xs| self.intern_place_elems(xs))
}
pub fn mk_substs_trait(self,
self_ty: Ty<'tcx>,
rest: &[GenericArg<'tcx>])

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -239,11 +239,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
}
}
let span = if let Place {
base: PlaceBase::Local(local),
projection: box [],
} = place {
let decl = &self.body.local_decls[*local];
let span = if let Some(local) = place.as_local() {
let decl = &self.body.local_decls[local];
Some(decl.source_info.span)
} else {
None
@ -611,7 +608,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
projection,
} = first_borrowed_place;
let mut cursor = &**projection;
let mut cursor = projection.as_ref();
while let [proj_base @ .., elem] = cursor {
cursor = proj_base;
@ -635,7 +632,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
projection,
} = second_borrowed_place;
let mut cursor = &**projection;
let mut cursor = projection.as_ref();
while let [proj_base @ .., elem] = cursor {
cursor = proj_base;
@ -710,10 +707,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
_ => drop_span,
};
let root_place_projection = self.infcx.tcx.intern_place_elems(root_place.projection);
if self.access_place_error_reported
.contains(&(Place {
base: root_place.base.clone(),
projection: root_place.projection.to_vec().into_boxed_slice(),
projection: root_place_projection,
}, borrow_span))
{
debug!(
@ -726,7 +725,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.access_place_error_reported
.insert((Place {
base: root_place.base.clone(),
projection: root_place.projection.to_vec().into_boxed_slice(),
projection: root_place_projection,
}, borrow_span));
if let StorageDeadOrDrop::Destructor(dropped_ty) =
@ -1124,11 +1123,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
};
let (place_desc, note) = if let Some(place_desc) = opt_place_desc {
let local_kind = match borrow.borrowed_place {
Place {
base: PlaceBase::Local(local),
projection: box [],
} => {
let local_kind = if let Some(local) = borrow.borrowed_place.as_local() {
match self.body.local_kind(local) {
LocalKind::ReturnPointer
| LocalKind::Temp => bug!("temporary or return pointer with a name"),
@ -1142,8 +1137,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
"function parameter "
}
}
}
_ => "local data ",
} else {
"local data "
};
(
format!("{}`{}`", local_kind, place_desc),
@ -1480,10 +1475,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
assigned_span: Span,
err_place: &Place<'tcx>,
) {
let (from_arg, local_decl) = if let Place {
base: PlaceBase::Local(local),
projection: box [],
} = *err_place {
let (from_arg, local_decl) = if let Some(local) = err_place.as_local() {
if let LocalKind::Arg = self.body.local_kind(local) {
(true, Some(&self.body.local_decls[local]))
} else {
@ -1643,11 +1635,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
reservation
);
// Check that the initial assignment of the reserve location is into a temporary.
let mut target = *match reservation {
Place {
base: PlaceBase::Local(local),
projection: box [],
} if self.body.local_kind(*local) == LocalKind::Temp => local,
let mut target = match reservation.as_local() {
Some(local) if self.body.local_kind(local) == LocalKind::Temp => local,
_ => return None,
};
@ -1659,15 +1648,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
"annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
target, stmt
);
if let StatementKind::Assign(
box(
Place {
base: PlaceBase::Local(assigned_to),
projection: box [],
},
rvalue
)
) = &stmt.kind {
if let StatementKind::Assign(box(place, rvalue)) = &stmt.kind {
if let Some(assigned_to) = place.as_local() {
debug!(
"annotate_argument_and_return_for_borrow: assigned_to={:?} \
rvalue={:?}",
@ -1692,7 +1674,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
// Find the local from the operand.
let assigned_from_local = match assigned_from.local_or_deref_local() {
let assigned_from_local = match assigned_from.local_or_deref_local()
{
Some(local) => local,
None => continue,
};
@ -1715,13 +1698,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
annotated_closure, assigned_from_local, assigned_to
);
if *assigned_to == mir::RETURN_PLACE {
if assigned_to == mir::RETURN_PLACE {
// If it was assigned directly into the return place, then
// return now.
return annotated_closure;
} else {
// Otherwise, update the target.
target = *assigned_to;
target = assigned_to;
}
}
@ -1771,7 +1754,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
assigned_from_local={:?} assigned_to={:?}",
assigned_from_local, assigned_to
);
if *assigned_to == mir::RETURN_PLACE {
if assigned_to == mir::RETURN_PLACE {
// If it was then return the annotated closure if there was one,
// else, annotate this function.
return annotated_closure.or_else(fallback);
@ -1779,7 +1762,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// If we didn't assign into the return place, then we just update
// the target.
target = *assigned_to;
target = assigned_to;
}
}
}
@ -1790,14 +1774,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
target, terminator
);
if let TerminatorKind::Call {
destination: Some((Place {
base: PlaceBase::Local(assigned_to),
projection: box [],
}, _)),
destination: Some((place, _)),
args,
..
} = &terminator.kind
{
if let Some(assigned_to) = place.as_local() {
debug!(
"annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
assigned_to, args
@ -1820,13 +1802,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
assigned_from_local,
);
if *assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
if assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
return annotated_closure.or_else(fallback);
}
}
}
}
}
}
// If we haven't found an assignment into the return place, then we need not add
// any annotations.

View file

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

View file

@ -1133,15 +1133,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// Special case: you can assign a immutable local variable
// (e.g., `x = ...`) so long as it has never been initialized
// before (at this point in the flow).
if let Place {
base: PlaceBase::Local(local),
projection: box [],
} = place_span.0 {
if let Mutability::Not = self.body.local_decls[*local].mutability {
if let Some(local) = place_span.0.as_local() {
if let Mutability::Not = self.body.local_decls[local].mutability {
// check for reassignments to immutable local variables
self.check_if_reassignment_to_immutable_state(
location,
*local,
local,
place_span,
flow_state,
);
@ -1288,14 +1285,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// captures of a closure are copied/moved directly
// when generating MIR.
match *operand {
Operand::Move(Place {
base: PlaceBase::Local(local),
projection: box [],
}) |
Operand::Copy(Place {
base: PlaceBase::Local(local),
projection: box [],
}) if self.body.local_decls[local].is_user_variable.is_none() => {
Operand::Move(ref place) | Operand::Copy(ref place) => {
match place.as_local() {
Some(local) if self.body.local_decls[local].is_user_variable.is_none() => {
if self.body.local_decls[local].ty.is_mutable_ptr() {
// The variable will be marked as mutable by the borrow.
return;
@ -1331,16 +1323,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let stmt = &bbd.statements[loc.statement_index];
debug!("temporary assigned in: stmt={:?}", stmt);
if let StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref source))) = stmt.kind {
if let StatementKind::Assign(box (_, Rvalue::Ref(_, _, ref source))) =
stmt.kind
{
propagate_closure_used_mut_place(self, source);
} else {
bug!("closures should only capture user variables \
or references to user variables");
bug!(
"closures should only capture user variables \
or references to user variables"
);
}
}
Operand::Move(ref place)
| Operand::Copy(ref place) => {
propagate_closure_used_mut_place(self, place);
_ => propagate_closure_used_mut_place(self, place),
}
}
Operand::Constant(..) => {}
}
@ -1702,7 +1697,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
debug!("check_if_assigned_path_is_moved place: {:?}", place);
// None case => assigning to `x` does not require `x` be initialized.
let mut cursor = &*place.projection;
let mut cursor = &*place.projection.as_ref();
while let [proj_base @ .., elem] = cursor {
cursor = proj_base;

View file

@ -89,19 +89,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// If that ever stops being the case, then the ever initialized
// flow could be used.
if let Some(StatementKind::Assign(
box(
Place {
base: PlaceBase::Local(local),
projection: box [],
},
Rvalue::Use(Operand::Move(move_from))
)
box(place, Rvalue::Use(Operand::Move(move_from)))
)) = self.body.basic_blocks()[location.block]
.statements
.get(location.statement_index)
.map(|stmt| &stmt.kind)
{
let local_decl = &self.body.local_decls[*local];
if let Some(local) = place.as_local() {
let local_decl = &self.body.local_decls[local];
// opt_match_place is the
// match_span is the span of the expression being matched on
// match *x.y { ... } match_place is Some(*x.y)
@ -122,7 +117,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
kind,
original_path,
move_from,
*local,
local,
opt_match_place,
match_span,
stmt_source_info.span,
@ -130,6 +125,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
return;
}
}
}
let move_spans = self.move_spans(original_path.as_ref(), location);
grouped_errors.push(GroupedMoveError::OtherIllegalMove {
@ -307,11 +303,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All)
.find_map(|p| self.is_upvar_field_projection(p));
let deref_base = match &deref_target_place.projection {
box [proj_base @ .., ProjectionElem::Deref] => {
let deref_base = match deref_target_place.projection.as_ref() {
&[ref proj_base @ .., ProjectionElem::Deref] => {
PlaceRef {
base: &deref_target_place.base,
projection: proj_base,
projection: &proj_base,
}
}
_ => bug!("deref_target_place is not a deref projection"),

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -64,14 +64,8 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
// This Local/Local case is handled by the more general code below, but
// it's so common that it's a speed win to check for it first.
if let Place {
base: PlaceBase::Local(l1),
projection: box [],
} = borrow_place {
if let PlaceRef {
base: PlaceBase::Local(l2),
projection: [],
} = access_place {
if let Some(l1) = borrow_place.as_local() {
if let Some(l2) = access_place.as_local() {
return l1 == l2;
}
}

View file

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

View file

@ -6,7 +6,7 @@ use crate::build::{BlockAnd, BlockAndExtension, Builder};
use crate::hair::*;
use rustc::mir::interpret::{PanicInfo::BoundsCheck};
use rustc::mir::*;
use rustc::ty::{CanonicalUserTypeAnnotation, Ty, Variance};
use rustc::ty::{CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance};
use rustc_index::vec::Idx;
@ -23,10 +23,10 @@ struct PlaceBuilder<'tcx> {
}
impl PlaceBuilder<'tcx> {
fn into_place(self) -> Place<'tcx> {
fn into_place(self, tcx: TyCtxt<'tcx>) -> Place<'tcx> {
Place {
base: self.base,
projection: self.projection.into_boxed_slice(),
projection: tcx.intern_place_elems(&self.projection),
}
}
@ -73,7 +73,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
M: Mirror<'tcx, Output = Expr<'tcx>>,
{
let place_builder = unpack!(block = self.as_place_builder(block, expr));
block.and(place_builder.into_place())
block.and(place_builder.into_place(self.hir.tcx()))
}
/// This is used when constructing a compound `Place`, so that we can avoid creating
@ -96,7 +96,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
M: Mirror<'tcx, Output = Expr<'tcx>>,
{
let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
block.and(place_builder.into_place())
block.and(place_builder.into_place(self.hir.tcx()))
}
/// This is used when constructing a compound `Place`, so that we can avoid creating
@ -165,7 +165,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Mutability::Not,
));
let slice = place_builder.clone().into_place();
let slice = place_builder.clone().into_place(this.hir.tcx());
// bounds check:
let (len, lt) = (
this.temp(usize_ty.clone(), expr_span),
@ -225,7 +225,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
);
let place = place_builder.clone().into_place();
let place = place_builder.clone().into_place(this.hir.tcx());
this.cfg.push(
block,
Statement {

View file

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

View file

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

View file

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

View file

@ -166,7 +166,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
});
if irrefutable {
let place = match_pair.place.downcast(adt_def, variant_index);
let place = tcx.mk_place_downcast(match_pair.place, adt_def, variant_index);
candidate.match_pairs.extend(self.field_match_pairs(place, subpatterns));
Ok(())
} else {
@ -191,7 +191,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
PatKind::Deref { ref subpattern } => {
let place = match_pair.place.deref();
let place = tcx.mk_place_deref(match_pair.place);
candidate.match_pairs.push(MatchPair::new(place, subpattern));
Ok(())
}

View file

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

View file

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

View file

@ -926,14 +926,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// If constants and statics, we don't generate StorageLive for this
// temporary, so don't try to generate StorageDead for it either.
_ if self.local_scope().is_none() => (),
Operand::Copy(Place {
base: PlaceBase::Local(cond_temp),
projection: box [],
})
| Operand::Move(Place {
base: PlaceBase::Local(cond_temp),
projection: box [],
}) => {
Operand::Copy(place)
| Operand::Move(place) => {
if let Some(cond_temp) = place.as_local() {
// Manually drop the condition on both branches.
let top_scope = self.scopes.scopes.last_mut().unwrap();
let top_drop_data = top_scope.drops.pop().unwrap();
@ -964,8 +959,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
top_scope.invalidate_cache(true, self.is_generator, true);
} else {
bug!("Expected as_local_operand to produce a temporary");
}
}
_ => bug!("Expected as_local_operand to produce a temporary"),
}
(true_block, false_block)

View file

@ -157,11 +157,13 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
// Since `propagate_call_unwind` doesn't exist, we have to kill the
// destination here, and then gen it again in `propagate_call_return`.
if let TerminatorKind::Call {
destination: Some((Place { base: PlaceBase::Local(local), projection: box [] }, _)),
destination: Some((ref place, _)),
..
} = self.body[loc.block].terminator().kind {
if let Some(local) = place.as_local() {
sets.kill(local);
}
}
self.check_for_move(sets, loc);
}

View file

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

View file

@ -327,7 +327,7 @@ impl<'tcx> MoveData<'tcx> {
pub fn base_local(&self, mut mpi: MovePathIndex) -> Option<Local> {
loop {
let path = &self.move_paths[mpi];
if let Place { base: PlaceBase::Local(l), projection: box [] } = path.place {
if let Some(l) = path.place.as_local() {
return Some(l);
}
if let Some(parent) = path.parent {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -319,7 +319,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyLocals {
let map = make_local_map(&mut body.local_decls, locals);
// Update references to all vars and tmps now
LocalUpdater { map }.visit_body(body);
LocalUpdater { map, tcx }.visit_body(body);
body.local_decls.shrink_to_fit();
}
}
@ -374,11 +374,16 @@ impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> {
}
}
struct LocalUpdater {
struct LocalUpdater<'tcx> {
map: IndexVec<Local, Option<Local>>,
tcx: TyCtxt<'tcx>,
}
impl<'tcx> MutVisitor<'tcx> for LocalUpdater {
impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
// Remove unnecessary StorageLive and StorageDead annotations.
data.statements.retain(|stmt| {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -26,9 +26,10 @@ use rustc::ty::{self, DefIdTree, TyCtxt, Region, RegionVid, Ty, AdtKind};
use rustc::ty::fold::TypeFolder;
use rustc::ty::layout::VariantIdx;
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use syntax::ast::{self, AttrStyle, Ident};
use syntax::ast::{self, Attribute, AttrStyle, AttrItem, Ident};
use syntax::attr;
use syntax_expand::base::MacroKind;
use syntax::parse::lexer::comments;
use syntax::source_map::DUMMY_SP;
use syntax::symbol::{Symbol, kw, sym};
use syntax_pos::{self, Pos, FileName};
@ -858,8 +859,31 @@ impl Attributes {
let mut cfg = Cfg::True;
let mut doc_line = 0;
/// Converts `attr` to a normal `#[doc="foo"]` comment, if it is a
/// comment like `///` or `/** */`. (Returns `attr` unchanged for
/// non-sugared doc attributes.)
pub fn with_desugared_doc<T>(attr: &Attribute, f: impl FnOnce(&Attribute) -> T) -> T {
if attr.is_sugared_doc {
let comment = attr.value_str().unwrap();
let meta = attr::mk_name_value_item_str(
Ident::with_dummy_span(sym::doc),
Symbol::intern(&comments::strip_doc_comment_decoration(&comment.as_str())),
DUMMY_SP,
);
f(&Attribute {
item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) },
id: attr.id,
style: attr.style,
is_sugared_doc: true,
span: attr.span,
})
} else {
f(attr)
}
}
let other_attrs = attrs.iter().filter_map(|attr| {
attr.with_desugared_doc(|attr| {
with_desugared_doc(attr, |attr| {
if attr.check_name(sym::doc) {
if let Some(mi) = attr.meta() {
if let Some(value) = mi.value_str() {

View file

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

View file

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

View file

@ -1363,20 +1363,24 @@ impl PathBuf {
}
fn _set_extension(&mut self, extension: &OsStr) -> bool {
if self.file_name().is_none() {
return false;
}
let mut stem = match self.file_stem() {
Some(stem) => stem.to_os_string(),
None => OsString::new(),
let file_stem = match self.file_stem() {
None => return false,
Some(f) => os_str_as_u8_slice(f),
};
if !os_str_as_u8_slice(extension).is_empty() {
stem.push(".");
stem.push(extension);
// truncate until right after the file stem
let end_file_stem = file_stem[file_stem.len()..].as_ptr() as usize;
let start = os_str_as_u8_slice(&self.inner).as_ptr() as usize;
let v = self.as_mut_vec();
v.truncate(end_file_stem.wrapping_sub(start));
// add the new extension, if any
let new = os_str_as_u8_slice(extension);
if !new.is_empty() {
v.reserve_exact(new.len() + 1);
v.push(b'.');
v.extend_from_slice(new);
}
self.set_file_name(&stem);
true
}

View file

@ -105,11 +105,14 @@ cfg_has_statx! {{
flags: i32,
mask: u32,
) -> Option<io::Result<FileAttr>> {
use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sync::atomic::{AtomicU8, Ordering};
// Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx`
// We store the availability in a global to avoid unnecessary syscalls
static HAS_STATX: AtomicBool = AtomicBool::new(true);
// We store the availability in global to avoid unnecessary syscalls.
// 0: Unknown
// 1: Not available
// 2: Available
static STATX_STATE: AtomicU8 = AtomicU8::new(0);
syscall! {
fn statx(
fd: c_int,
@ -120,21 +123,33 @@ cfg_has_statx! {{
) -> c_int
}
if !HAS_STATX.load(Ordering::Relaxed) {
match STATX_STATE.load(Ordering::Relaxed) {
0 => {
// It is a trick to call `statx` with NULL pointers to check if the syscall
// is available. According to the manual, it is expected to fail with EFAULT.
// We do this mainly for performance, since it is nearly hundreds times
// faster than a normal successfull call.
let err = cvt(statx(0, ptr::null(), 0, libc::STATX_ALL, ptr::null_mut()))
.err()
.and_then(|e| e.raw_os_error());
// We don't check `err == Some(libc::ENOSYS)` because the syscall may be limited
// and returns `EPERM`. Listing all possible errors seems not a good idea.
// See: https://github.com/rust-lang/rust/issues/65662
if err != Some(libc::EFAULT) {
STATX_STATE.store(1, Ordering::Relaxed);
return None;
}
STATX_STATE.store(2, Ordering::Relaxed);
}
1 => return None,
_ => {}
}
let mut buf: libc::statx = mem::zeroed();
let ret = cvt(statx(fd, path, flags, mask, &mut buf));
match ret {
Err(err) => match err.raw_os_error() {
Some(libc::ENOSYS) => {
HAS_STATX.store(false, Ordering::Relaxed);
return None;
if let Err(err) = cvt(statx(fd, path, flags, mask, &mut buf)) {
return Some(Err(err));
}
_ => return Some(Err(err)),
}
Ok(_) => {
// We cannot fill `stat64` exhaustively because of private padding fields.
let mut stat: stat64 = mem::zeroed();
// `c_ulong` on gnu-mips, `dev_t` otherwise
@ -163,8 +178,6 @@ cfg_has_statx! {{
Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) }))
}
}
}
} else {
#[derive(Clone)]

View file

@ -13,8 +13,8 @@ use crate::ast::{AttrItem, AttrId, AttrStyle, Name, Ident, Path, PathSegment};
use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem};
use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam};
use crate::mut_visit::visit_clobber;
use crate::source_map::{BytePos, Spanned, DUMMY_SP};
use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
use crate::source_map::{BytePos, Spanned};
use crate::parse::lexer::comments::doc_comment_style;
use crate::parse::parser::Parser;
use crate::parse::PResult;
use crate::parse::token::{self, Token};
@ -312,31 +312,6 @@ impl Attribute {
span: self.span,
})
}
/// Converts `self` to a normal `#[doc="foo"]` comment, if it is a
/// comment like `///` or `/** */`. (Returns `self` unchanged for
/// non-sugared doc attributes.)
pub fn with_desugared_doc<T, F>(&self, f: F) -> T where
F: FnOnce(&Attribute) -> T,
{
if self.is_sugared_doc {
let comment = self.value_str().unwrap();
let meta = mk_name_value_item_str(
Ident::with_dummy_span(sym::doc),
Symbol::intern(&strip_doc_comment_decoration(&comment.as_str())),
DUMMY_SP,
);
f(&Attribute {
item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) },
id: self.id,
style: self.style,
is_sugared_doc: true,
span: self.span,
})
} else {
f(self)
}
}
}
/* Constructors */

View file

@ -245,8 +245,10 @@ declare_features! (
(accepted, bind_by_move_pattern_guards, "1.39.0", Some(15287), None),
/// Allows attributes in formal function parameters.
(accepted, param_attrs, "1.39.0", Some(60406), None),
// Allows macro invocations in `extern {}` blocks.
/// Allows macro invocations in `extern {}` blocks.
(accepted, macros_in_extern, "1.40.0", Some(49476), None),
/// Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008).
(accepted, non_exhaustive, "1.40.0", Some(44109), None),
// -------------------------------------------------------------------------
// feature-group-end: accepted features

View file

@ -383,9 +383,6 @@ declare_features! (
/// Allows `#[doc(include = "some-file")]`.
(active, external_doc, "1.22.0", Some(44732), None),
/// Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008).
(active, non_exhaustive, "1.22.0", Some(44109), None),
/// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`.
(active, crate_visibility_modifier, "1.23.0", Some(53120), None),

View file

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

View file

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

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

@ -0,0 +1,186 @@
use super::*;
use crate::json::JsonEmitter;
use crate::source_map::{FilePathMapping, SourceMap};
use crate::tests::Shared;
use crate::with_default_globals;
use errors::emitter::{ColorConfig, HumanReadableErrorType};
use errors::Handler;
use rustc_serialize::json::decode;
use syntax_pos::{BytePos, Span};
use std::str;
#[derive(RustcDecodable, Debug, PartialEq, Eq)]
struct TestData {
spans: Vec<SpanTestData>,
}
#[derive(RustcDecodable, Debug, PartialEq, Eq)]
struct SpanTestData {
pub byte_start: u32,
pub byte_end: u32,
pub line_start: u32,
pub column_start: u32,
pub line_end: u32,
pub column_end: u32,
}
/// Test the span yields correct positions in JSON.
fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
let expected_output = TestData { spans: vec![expected_output] };
with_default_globals(|| {
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
sm.new_source_file(Path::new("test.rs").to_owned().into(), code.to_owned());
let output = Arc::new(Mutex::new(Vec::new()));
let je = JsonEmitter::new(
Box::new(Shared { data: output.clone() }),
None,
sm,
true,
HumanReadableErrorType::Short(ColorConfig::Never),
false,
);
let span = Span::with_root_ctxt(BytePos(span.0), BytePos(span.1));
let handler = Handler::with_emitter(true, None, Box::new(je));
handler.span_err(span, "foo");
let bytes = output.lock().unwrap();
let actual_output = str::from_utf8(&bytes).unwrap();
let actual_output: TestData = decode(actual_output).unwrap();
assert_eq!(expected_output, actual_output)
})
}
#[test]
fn empty() {
test_positions(
" ",
(0, 1),
SpanTestData {
byte_start: 0,
byte_end: 1,
line_start: 1,
column_start: 1,
line_end: 1,
column_end: 2,
},
)
}
#[test]
fn bom() {
test_positions(
"\u{feff} ",
(0, 1),
SpanTestData {
byte_start: 3,
byte_end: 4,
line_start: 1,
column_start: 1,
line_end: 1,
column_end: 2,
},
)
}
#[test]
fn lf_newlines() {
test_positions(
"\nmod foo;\nmod bar;\n",
(5, 12),
SpanTestData {
byte_start: 5,
byte_end: 12,
line_start: 2,
column_start: 5,
line_end: 3,
column_end: 3,
},
)
}
#[test]
fn crlf_newlines() {
test_positions(
"\r\nmod foo;\r\nmod bar;\r\n",
(5, 12),
SpanTestData {
byte_start: 6,
byte_end: 14,
line_start: 2,
column_start: 5,
line_end: 3,
column_end: 3,
},
)
}
#[test]
fn crlf_newlines_with_bom() {
test_positions(
"\u{feff}\r\nmod foo;\r\nmod bar;\r\n",
(5, 12),
SpanTestData {
byte_start: 9,
byte_end: 17,
line_start: 2,
column_start: 5,
line_end: 3,
column_end: 3,
},
)
}
#[test]
fn span_before_crlf() {
test_positions(
"foo\r\nbar",
(2, 3),
SpanTestData {
byte_start: 2,
byte_end: 3,
line_start: 1,
column_start: 3,
line_end: 1,
column_end: 4,
},
)
}
#[test]
fn span_on_crlf() {
test_positions(
"foo\r\nbar",
(3, 4),
SpanTestData {
byte_start: 3,
byte_end: 5,
line_start: 1,
column_start: 4,
line_end: 2,
column_end: 1,
},
)
}
#[test]
fn span_after_crlf() {
test_positions(
"foo\r\nbar",
(4, 5),
SpanTestData {
byte_start: 5,
byte_end: 6,
line_start: 2,
column_start: 1,
line_end: 2,
column_end: 2,
},
)
}

View file

@ -31,23 +31,6 @@ mod tests;
pub const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments");
// A variant of 'panictry!' that works on a Vec<Diagnostic> instead of a single DiagnosticBuilder.
macro_rules! panictry_buffer {
($handler:expr, $e:expr) => ({
use std::result::Result::{Ok, Err};
use errors::FatalError;
match $e {
Ok(e) => e,
Err(errs) => {
for e in errs {
$handler.emit_diagnostic(&e);
}
FatalError.raise()
}
}
})
}
#[macro_export]
macro_rules! unwrap_or {
($opt:expr, $default:expr) => {

View file

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

View file

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

View file

@ -59,6 +59,23 @@ pub enum DirectoryOwnership {
// uses a HOF to parse anything, and <source> includes file and
// `source_str`.
/// A variant of 'panictry!' that works on a Vec<Diagnostic> instead of a single DiagnosticBuilder.
macro_rules! panictry_buffer {
($handler:expr, $e:expr) => ({
use std::result::Result::{Ok, Err};
use errors::FatalError;
match $e {
Ok(e) => e,
Err(errs) => {
for e in errs {
$handler.emit_diagnostic(&e);
}
FatalError.raise()
}
}
})
}
pub fn parse_crate_from_file<'a>(input: &Path, sess: &'a ParseSess) -> PResult<'a, ast::Crate> {
let mut parser = new_parser_from_file(sess, input);
parser.parse_crate_mod()

View file

@ -1368,25 +1368,6 @@ impl<'a> Parser<'a> {
}
}
}
fn report_invalid_macro_expansion_item(&self) {
self.struct_span_err(
self.prev_span,
"macros that expand to items must be delimited with braces or followed by a semicolon",
).multipart_suggestion(
"change the delimiters to curly braces",
vec![
(self.prev_span.with_hi(self.prev_span.lo() + BytePos(1)), String::from(" {")),
(self.prev_span.with_lo(self.prev_span.hi() - BytePos(1)), '}'.to_string()),
],
Applicability::MaybeIncorrect,
).span_suggestion(
self.sess.source_map().next_point(self.prev_span),
"add a semicolon",
';'.to_string(),
Applicability::MaybeIncorrect,
).emit();
}
}
pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedBrace>, handler: &errors::Handler) {

View file

@ -19,6 +19,7 @@ use log::debug;
use std::mem;
use rustc_target::spec::abi::Abi;
use errors::{Applicability, DiagnosticBuilder, DiagnosticId, StashKey};
use syntax_pos::BytePos;
/// Whether the type alias or associated type is a concrete type or an opaque type.
#[derive(Debug)]
@ -1739,6 +1740,25 @@ impl<'a> Parser<'a> {
}
}
fn report_invalid_macro_expansion_item(&self) {
self.struct_span_err(
self.prev_span,
"macros that expand to items must be delimited with braces or followed by a semicolon",
).multipart_suggestion(
"change the delimiters to curly braces",
vec![
(self.prev_span.with_hi(self.prev_span.lo() + BytePos(1)), String::from(" {")),
(self.prev_span.with_lo(self.prev_span.hi() - BytePos(1)), '}'.to_string()),
],
Applicability::MaybeIncorrect,
).span_suggestion(
self.sess.source_map().next_point(self.prev_span),
"add a semicolon",
';'.to_string(),
Applicability::MaybeIncorrect,
).emit();
}
fn mk_item(&self, span: Span, ident: Ident, kind: ItemKind, vis: Visibility,
attrs: Vec<Attribute>) -> P<Item> {
P(Item {

View file

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

View file

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

View file

@ -9,7 +9,7 @@
#![feature(const_fn)]
#![feature(crate_visibility_modifier)]
#![feature(nll)]
#![feature(non_exhaustive)]
#![cfg_attr(bootstrap, feature(non_exhaustive))]
#![feature(optin_builtin_traits)]
#![feature(rustc_attrs)]
#![cfg_attr(bootstrap, feature(proc_macro_hygiene))]
@ -855,6 +855,15 @@ impl Sub<BytePos> for NonNarrowChar {
}
}
/// Identifies an offset of a character that was normalized away from `SourceFile`.
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq, Debug)]
pub struct NormalizedPos {
/// The absolute offset of the character in the `SourceMap`.
pub pos: BytePos,
/// The difference between original and normalized string at position.
pub diff: u32,
}
/// The state of the lazy external source loading mechanism of a `SourceFile`.
#[derive(PartialEq, Eq, Clone)]
pub enum ExternalSource {
@ -918,6 +927,8 @@ pub struct SourceFile {
pub multibyte_chars: Vec<MultiByteChar>,
/// Width of characters that are not narrow in the source code.
pub non_narrow_chars: Vec<NonNarrowChar>,
/// Locations of characters removed during normalization.
pub normalized_pos: Vec<NormalizedPos>,
/// A hash of the filename, used for speeding up hashing in incremental compilation.
pub name_hash: u128,
}
@ -984,6 +995,9 @@ impl Encodable for SourceFile {
})?;
s.emit_struct_field("name_hash", 8, |s| {
self.name_hash.encode(s)
})?;
s.emit_struct_field("normalized_pos", 9, |s| {
self.normalized_pos.encode(s)
})
})
}
@ -1034,6 +1048,8 @@ impl Decodable for SourceFile {
d.read_struct_field("non_narrow_chars", 7, |d| Decodable::decode(d))?;
let name_hash: u128 =
d.read_struct_field("name_hash", 8, |d| Decodable::decode(d))?;
let normalized_pos: Vec<NormalizedPos> =
d.read_struct_field("normalized_pos", 9, |d| Decodable::decode(d))?;
Ok(SourceFile {
name,
name_was_remapped,
@ -1050,6 +1066,7 @@ impl Decodable for SourceFile {
lines,
multibyte_chars,
non_narrow_chars,
normalized_pos,
name_hash,
})
})
@ -1068,8 +1085,7 @@ impl SourceFile {
unmapped_path: FileName,
mut src: String,
start_pos: BytePos) -> Result<SourceFile, OffsetOverflowError> {
remove_bom(&mut src);
normalize_newlines(&mut src);
let normalized_pos = normalize_src(&mut src, start_pos);
let src_hash = {
let mut hasher: StableHasher = StableHasher::new();
@ -1102,6 +1118,7 @@ impl SourceFile {
lines,
multibyte_chars,
non_narrow_chars,
normalized_pos,
name_hash,
})
}
@ -1228,12 +1245,44 @@ impl SourceFile {
pub fn contains(&self, byte_pos: BytePos) -> bool {
byte_pos >= self.start_pos && byte_pos <= self.end_pos
}
/// Calculates the original byte position relative to the start of the file
/// based on the given byte position.
pub fn original_relative_byte_pos(&self, pos: BytePos) -> BytePos {
// Diff before any records is 0. Otherwise use the previously recorded
// diff as that applies to the following characters until a new diff
// is recorded.
let diff = match self.normalized_pos.binary_search_by(
|np| np.pos.cmp(&pos)) {
Ok(i) => self.normalized_pos[i].diff,
Err(i) if i == 0 => 0,
Err(i) => self.normalized_pos[i-1].diff,
};
BytePos::from_u32(pos.0 - self.start_pos.0 + diff)
}
}
/// Normalizes the source code and records the normalizations.
fn normalize_src(src: &mut String, start_pos: BytePos) -> Vec<NormalizedPos> {
let mut normalized_pos = vec![];
remove_bom(src, &mut normalized_pos);
normalize_newlines(src, &mut normalized_pos);
// Offset all the positions by start_pos to match the final file positions.
for np in &mut normalized_pos {
np.pos.0 += start_pos.0;
}
normalized_pos
}
/// Removes UTF-8 BOM, if any.
fn remove_bom(src: &mut String) {
fn remove_bom(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
if src.starts_with("\u{feff}") {
src.drain(..3);
normalized_pos.push(NormalizedPos { pos: BytePos(0), diff: 3 });
}
}
@ -1241,7 +1290,7 @@ fn remove_bom(src: &mut String) {
/// Replaces `\r\n` with `\n` in-place in `src`.
///
/// Returns error if there's a lone `\r` in the string
fn normalize_newlines(src: &mut String) {
fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
if !src.as_bytes().contains(&b'\r') {
return;
}
@ -1254,6 +1303,8 @@ fn normalize_newlines(src: &mut String) {
let mut buf = std::mem::replace(src, String::new()).into_bytes();
let mut gap_len = 0;
let mut tail = buf.as_mut_slice();
let mut cursor = 0;
let original_gap = normalized_pos.last().map_or(0, |l| l.diff);
loop {
let idx = match find_crlf(&tail[gap_len..]) {
None => tail.len(),
@ -1264,7 +1315,12 @@ fn normalize_newlines(src: &mut String) {
if tail.len() == gap_len {
break;
}
cursor += idx - gap_len;
gap_len += 1;
normalized_pos.push(NormalizedPos {
pos: BytePos::from_usize(cursor + 1),
diff: original_gap + gap_len as u32,
});
}
// Account for removed `\r`.

View file

@ -19,20 +19,25 @@ fn test_lookup_line() {
#[test]
fn test_normalize_newlines() {
fn check(before: &str, after: &str) {
fn check(before: &str, after: &str, expected_positions: &[u32]) {
let mut actual = before.to_string();
normalize_newlines(&mut actual);
let mut actual_positions = vec![];
normalize_newlines(&mut actual, &mut actual_positions);
let actual_positions : Vec<_> = actual_positions
.into_iter()
.map(|nc| nc.pos.0).collect();
assert_eq!(actual.as_str(), after);
assert_eq!(actual_positions, expected_positions);
}
check("", "");
check("\n", "\n");
check("\r", "\r");
check("\r\r", "\r\r");
check("\r\n", "\n");
check("hello world", "hello world");
check("hello\nworld", "hello\nworld");
check("hello\r\nworld", "hello\nworld");
check("\r\nhello\r\nworld\r\n", "\nhello\nworld\n");
check("\r\r\n", "\r\n");
check("hello\rworld", "hello\rworld");
check("", "", &[]);
check("\n", "\n", &[]);
check("\r", "\r", &[]);
check("\r\r", "\r\r", &[]);
check("\r\n", "\n", &[1]);
check("hello world", "hello world", &[]);
check("hello\nworld", "hello\nworld", &[]);
check("hello\r\nworld", "hello\nworld", &[6]);
check("\r\nhello\r\nworld\r\n", "\nhello\nworld\n", &[1, 7, 13]);
check("\r\r\n", "\r\n", &[2]);
check("hello\rworld", "hello\rworld", &[]);
}

View file

@ -1,3 +1,6 @@
lexer-crlf-line-endings-string-literal-doc-comment.rs -text
json-bom-plus-crlf.rs -text
json-bom-plus-crlf-multifile.rs -text
json-bom-plus-crlf-multifile-aux.rs -text
trailing-carriage-return-in-string.rs -text
*.bin -text

View file

@ -1,10 +0,0 @@
//#![feature(non_exhaustive)]
#[non_exhaustive] //~ERROR the `#[non_exhaustive]` attribute is an experimental feature
pub enum NonExhaustiveEnum {
Unit,
Tuple(u32),
Struct { field: u32 }
}
fn main() { }

View file

@ -1,12 +0,0 @@
error[E0658]: the `#[non_exhaustive]` attribute is an experimental feature
--> $DIR/feature-gate-non_exhaustive.rs:3:1
|
LL | #[non_exhaustive]
| ^^^^^^^^^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/44109
= help: add `#![feature(non_exhaustive)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View file

@ -0,0 +1,27 @@
// (This line has BOM so it's ignored by compiletest for directives)
//
// ignore-test Not a test. Used by other tests
// ignore-tidy-cr
// For easier verifying, the byte offsets in this file should match those
// in the json-bom-plus-crlf.rs - given the actual fn is identical (just with
// a different, but equally sized name), the easiest way to do this is to
// ensure the two files are of equal size on disk.
// Padding............................
// N.B., this file needs CRLF line endings. The .gitattributes file in
// this directory should enforce it.
pub fn test() {
let s : String = 1; // Error in the middle of line.
let s : String = 1
; // Error before the newline.
let s : String =
1; // Error after the newline.
let s : String = (
); // Error spanning the newline.
}

View file

@ -0,0 +1,12 @@
// (This line has BOM so it's ignored by compiletest for directives)
//
// build-fail
// compile-flags: --json=diagnostic-short --error-format=json
// ignore-tidy-cr
#[path = "json-bom-plus-crlf-multifile-aux.rs"]
mod json_bom_plus_crlf_multifile_aux;
fn main() {
json_bom_plus_crlf_multifile_aux::test();
}

View file

@ -0,0 +1,86 @@
{"message":"mismatched types","code":{"code":"E0308","explanation":"
This error occurs when the compiler was unable to infer the concrete type of a
variable. It can occur for several cases, the most common of which is a
mismatch in the expected type that the compiler inferred for a variable's
initializing expression, and the actual type explicitly assigned to the
variable.
For example:
```compile_fail,E0308
let x: i32 = \"I am not a number!\";
// ~~~ ~~~~~~~~~~~~~~~~~~~~
// | |
// | initializing expression;
// | compiler infers type `&str`
// |
// type `i32` assigned to variable `x`
```
"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected type `std::string::String`
found type `{integer}`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types
"}
{"message":"mismatched types","code":{"code":"E0308","explanation":"
This error occurs when the compiler was unable to infer the concrete type of a
variable. It can occur for several cases, the most common of which is a
mismatch in the expected type that the compiler inferred for a variable's
initializing expression, and the actual type explicitly assigned to the
variable.
For example:
```compile_fail,E0308
let x: i32 = \"I am not a number!\";
// ~~~ ~~~~~~~~~~~~~~~~~~~~
// | |
// | initializing expression;
// | compiler infers type `&str`
// |
// type `i32` assigned to variable `x`
```
"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected type `std::string::String`
found type `{integer}`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types
"}
{"message":"mismatched types","code":{"code":"E0308","explanation":"
This error occurs when the compiler was unable to infer the concrete type of a
variable. It can occur for several cases, the most common of which is a
mismatch in the expected type that the compiler inferred for a variable's
initializing expression, and the actual type explicitly assigned to the
variable.
For example:
```compile_fail,E0308
let x: i32 = \"I am not a number!\";
// ~~~ ~~~~~~~~~~~~~~~~~~~~
// | |
// | initializing expression;
// | compiler infers type `&str`
// |
// type `i32` assigned to variable `x`
```
"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected type `std::string::String`
found type `{integer}`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types
"}
{"message":"mismatched types","code":{"code":"E0308","explanation":"
This error occurs when the compiler was unable to infer the concrete type of a
variable. It can occur for several cases, the most common of which is a
mismatch in the expected type that the compiler inferred for a variable's
initializing expression, and the actual type explicitly assigned to the
variable.
For example:
```compile_fail,E0308
let x: i32 = \"I am not a number!\";
// ~~~ ~~~~~~~~~~~~~~~~~~~~
// | |
// | initializing expression;
// | compiler infers type `&str`
// |
// type `i32` assigned to variable `x`
```
"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":801,"byte_end":809,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `std::string::String`, found ()","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected type `std::string::String`
found type `()`","code":null,"level":"note","spans":[],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:25:22: error[E0308]: mismatched types
"}
{"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors
"}

View file

@ -0,0 +1,27 @@
// (This line has BOM so it's ignored by compiletest for directives)
//
// build-fail
// compile-flags: --json=diagnostic-short --error-format=json
// ignore-tidy-cr
// For easier verifying, the byte offsets in this file should match those
// in the json_bom_plus_crlf_multifile_aux.rs - given the actual fn is
// identical (just with a different, but equally sized name), the easiest way
// to do this is to ensure the two files are of equal size on disk.
// N.B., this file needs CRLF line endings. The .gitattributes file in
// this directory should enforce it.
fn main() {
let s : String = 1; // Error in the middle of line.
let s : String = 1
; // Error before the newline.
let s : String =
1; // Error after the newline.
let s : String = (
); // Error spanning the newline.
}

View file

@ -0,0 +1,86 @@
{"message":"mismatched types","code":{"code":"E0308","explanation":"
This error occurs when the compiler was unable to infer the concrete type of a
variable. It can occur for several cases, the most common of which is a
mismatch in the expected type that the compiler inferred for a variable's
initializing expression, and the actual type explicitly assigned to the
variable.
For example:
```compile_fail,E0308
let x: i32 = \"I am not a number!\";
// ~~~ ~~~~~~~~~~~~~~~~~~~~
// | |
// | initializing expression;
// | compiler infers type `&str`
// |
// type `i32` assigned to variable `x`
```
"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected type `std::string::String`
found type `{integer}`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:17:22: error[E0308]: mismatched types
"}
{"message":"mismatched types","code":{"code":"E0308","explanation":"
This error occurs when the compiler was unable to infer the concrete type of a
variable. It can occur for several cases, the most common of which is a
mismatch in the expected type that the compiler inferred for a variable's
initializing expression, and the actual type explicitly assigned to the
variable.
For example:
```compile_fail,E0308
let x: i32 = \"I am not a number!\";
// ~~~ ~~~~~~~~~~~~~~~~~~~~
// | |
// | initializing expression;
// | compiler infers type `&str`
// |
// type `i32` assigned to variable `x`
```
"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected type `std::string::String`
found type `{integer}`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:19:22: error[E0308]: mismatched types
"}
{"message":"mismatched types","code":{"code":"E0308","explanation":"
This error occurs when the compiler was unable to infer the concrete type of a
variable. It can occur for several cases, the most common of which is a
mismatch in the expected type that the compiler inferred for a variable's
initializing expression, and the actual type explicitly assigned to the
variable.
For example:
```compile_fail,E0308
let x: i32 = \"I am not a number!\";
// ~~~ ~~~~~~~~~~~~~~~~~~~~
// | |
// | initializing expression;
// | compiler infers type `&str`
// |
// type `i32` assigned to variable `x`
```
"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected type `std::string::String`
found type `{integer}`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:23:1: error[E0308]: mismatched types
"}
{"message":"mismatched types","code":{"code":"E0308","explanation":"
This error occurs when the compiler was unable to infer the concrete type of a
variable. It can occur for several cases, the most common of which is a
mismatch in the expected type that the compiler inferred for a variable's
initializing expression, and the actual type explicitly assigned to the
variable.
For example:
```compile_fail,E0308
let x: i32 = \"I am not a number!\";
// ~~~ ~~~~~~~~~~~~~~~~~~~~
// | |
// | initializing expression;
// | compiler infers type `&str`
// |
// type `i32` assigned to variable `x`
```
"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":801,"byte_end":809,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `std::string::String`, found ()","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected type `std::string::String`
found type `()`","code":null,"level":"note","spans":[],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:25:22: error[E0308]: mismatched types
"}
{"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors
"}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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