diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index ee6cb398acdce..b0b88209989fa 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -497,8 +497,8 @@ pub enum LocalKind { ReturnPointer, } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] -pub struct VarBindingForm { +#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +pub struct VarBindingForm<'tcx> { /// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`? pub binding_mode: ty::BindingMode, /// If an explicit type was provided for this variable binding, @@ -508,21 +508,49 @@ pub struct VarBindingForm { /// doing so breaks incremental compilation (as of this writing), /// while a `Span` does not cause our tests to fail. pub opt_ty_info: Option, + /// Place of the RHS of the =, or the subject of the `match` where this + /// variable is initialized. None in the case of `let PATTERN;`. + /// Some((None, ..)) in the case of and `let [mut] x = ...` because + /// (a) the right-hand side isn't evaluated as a place expression. + /// (b) it gives a way to separate this case from the remaining cases + /// for diagnostics. + pub opt_match_place: Option<(Option>, Span)>, } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] -pub enum BindingForm { +#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +pub enum BindingForm<'tcx> { /// This is a binding for a non-`self` binding, or a `self` that has an explicit type. - Var(VarBindingForm), + Var(VarBindingForm<'tcx>), /// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit. ImplicitSelf, } -CloneTypeFoldableAndLiftImpls! { BindingForm, } +CloneTypeFoldableAndLiftImpls! { BindingForm<'tcx>, } -impl_stable_hash_for!(struct self::VarBindingForm { binding_mode, opt_ty_info }); +impl_stable_hash_for!(struct self::VarBindingForm<'tcx> { + binding_mode, + opt_ty_info, + opt_match_place +}); + +mod binding_form_impl { + use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; + use ich::StableHashingContext; -impl_stable_hash_for!(enum self::BindingForm { Var(binding), ImplicitSelf, }); + impl<'a, 'tcx> HashStable> for super::BindingForm<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + use super::BindingForm::*; + ::std::mem::discriminant(self).hash_stable(hcx, hasher); + + match self { + Var(binding) => binding.hash_stable(hcx, hasher), + ImplicitSelf => (), + } + } + } +} /// A MIR local. /// @@ -542,7 +570,7 @@ pub struct LocalDecl<'tcx> { /// therefore it need not be visible across crates. pnkfelix /// currently hypothesized we *need* to wrap this in a /// `ClearCrossCrate` as long as it carries as `HirId`. - pub is_user_variable: Option>, + pub is_user_variable: Option>>, /// True if this is an internal local /// @@ -670,6 +698,7 @@ impl<'tcx> LocalDecl<'tcx> { Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { binding_mode: ty::BindingMode::BindByValue(_), opt_ty_info: _, + opt_match_place: _, }))) => true, // FIXME: might be able to thread the distinction between @@ -688,6 +717,7 @@ impl<'tcx> LocalDecl<'tcx> { Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { binding_mode: ty::BindingMode::BindByValue(_), opt_ty_info: _, + opt_match_place: _, }))) => true, Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf)) => true, diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 6d77364aae02a..a17e897d83447 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -35,7 +35,6 @@ use syntax_pos::Span; use dataflow::indexes::BorrowIndex; use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex}; -use dataflow::move_paths::{IllegalMoveOriginKind, MoveError}; use dataflow::Borrows; use dataflow::DataflowResultsConsumer; use dataflow::FlowAtLocation; @@ -62,6 +61,7 @@ mod path_utils; crate mod place_ext; mod prefixes; mod used_muts; +mod move_errors; pub(crate) mod nll; @@ -117,40 +117,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( let move_data: MoveData<'tcx> = match MoveData::gather_moves(mir, tcx) { Ok(move_data) => move_data, Err((move_data, move_errors)) => { - for move_error in move_errors { - let (span, kind): (Span, IllegalMoveOriginKind) = match move_error { - MoveError::UnionMove { .. } => { - unimplemented!("don't know how to report union move errors yet.") - } - MoveError::IllegalMove { - cannot_move_out_of: o, - } => (o.span, o.kind), - }; - let origin = Origin::Mir; - let mut err = match kind { - IllegalMoveOriginKind::Static => { - tcx.cannot_move_out_of(span, "static item", origin) - } - IllegalMoveOriginKind::BorrowedContent { target_ty: ty } => { - // Inspect the type of the content behind the - // borrow to provide feedback about why this - // was a move rather than a copy. - match ty.sty { - ty::TyArray(..) | ty::TySlice(..) => { - tcx.cannot_move_out_of_interior_noncopy(span, ty, None, origin) - } - _ => tcx.cannot_move_out_of(span, "borrowed content", origin), - } - } - IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => { - tcx.cannot_move_out_of_interior_of_drop(span, ty, origin) - } - IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => { - tcx.cannot_move_out_of_interior_noncopy(span, ty, Some(is_index), origin) - } - }; - err.emit(); - } + move_errors::report_move_errors(&mir, tcx, move_errors, &move_data); move_data } }; diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs new file mode 100644 index 0000000000000..bc68708decbd5 --- /dev/null +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -0,0 +1,388 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::hir; +use rustc::mir::*; +use rustc::ty::{self, TyCtxt}; +use rustc_errors::DiagnosticBuilder; +use syntax_pos::Span; + +use dataflow::move_paths::{IllegalMoveOrigin, IllegalMoveOriginKind, MoveData}; +use dataflow::move_paths::{LookupResult, MoveError, MovePathIndex}; +use util::borrowck_errors::{BorrowckErrors, Origin}; + +pub(crate) fn report_move_errors<'gcx, 'tcx>( + mir: &Mir<'tcx>, + tcx: TyCtxt<'_, 'gcx, 'tcx>, + move_errors: Vec>, + move_data: &MoveData<'tcx>, +) { + MoveErrorCtxt { + mir, + tcx, + move_data, + }.report_errors(move_errors); +} + +#[derive(Copy, Clone)] +struct MoveErrorCtxt<'a, 'gcx: 'tcx, 'tcx: 'a> { + mir: &'a Mir<'tcx>, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + move_data: &'a MoveData<'tcx>, +} + +// Often when desugaring a pattern match we may have many individual moves in +// MIR that are all part of one operation from the user's point-of-view. For +// example: +// +// let (x, y) = foo() +// +// would move x from the 0 field of some temporary, and y from the 1 field. We +// group such errors together for cleaner error reporting. +// +// Errors are kept separate if they are from places with different parent move +// paths. For example, this generates two errors: +// +// let (&x, &y) = (&String::new(), &String::new()); +#[derive(Debug)] +enum GroupedMoveError<'tcx> { + // Match place can't be moved from + // e.g. match x[0] { s => (), } where x: &[String] + MovesFromMatchPlace { + span: Span, + move_from: Place<'tcx>, + kind: IllegalMoveOriginKind<'tcx>, + binds_to: Vec, + }, + // Part of a pattern can't be moved from, + // e.g. match &String::new() { &x => (), } + MovesFromPattern { + span: Span, + move_from: MovePathIndex, + kind: IllegalMoveOriginKind<'tcx>, + binds_to: Vec, + }, + // Everything that isn't from pattern matching. + OtherIllegalMove { + span: Span, + kind: IllegalMoveOriginKind<'tcx>, + }, +} + +impl<'a, 'gcx, 'tcx> MoveErrorCtxt<'a, 'gcx, 'tcx> { + fn report_errors(self, move_errors: Vec>) { + let grouped_errors = self.group_move_errors(move_errors); + for error in grouped_errors { + self.report(error); + } + } + + fn group_move_errors(self, errors: Vec>) -> Vec> { + let mut grouped_errors = Vec::new(); + for error in errors { + self.append_to_grouped_errors(&mut grouped_errors, error); + } + grouped_errors + } + + fn append_to_grouped_errors( + self, + grouped_errors: &mut Vec>, + error: MoveError<'tcx>, + ) { + match error { + MoveError::UnionMove { .. } => { + unimplemented!("don't know how to report union move errors yet.") + } + MoveError::IllegalMove { + cannot_move_out_of: IllegalMoveOrigin { location, kind }, + } => { + let stmt_source_info = self.mir.source_info(location); + if let Some(StatementKind::Assign( + Place::Local(local), + Rvalue::Use(Operand::Move(move_from)), + )) = self.mir.basic_blocks()[location.block] + .statements + .get(location.statement_index) + .map(|stmt| &stmt.kind) + { + let local_decl = &self.mir.local_decls[*local]; + if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { + opt_match_place: Some((ref opt_match_place, match_span)), + binding_mode: _, + opt_ty_info: _, + }))) = local_decl.is_user_variable + { + // opt_match_place is the + // match_span is the span of the expression being matched on + // match *x.y { ... } match_place is Some(*x.y) + // ^^^^ match_span is the span of *x.y + // opt_match_place is None for let [mut] x = ... statements, + // whether or not the right-hand side is a place expression + + // HACK use scopes to determine if this assignment is + // the initialization of a variable. + // FIXME(matthewjasper) This would probably be more + // reliable if it used the ever initialized dataflow + // but move errors are currently reported before the + // rest of borrowck has run. + if self + .mir + .is_sub_scope(local_decl.source_info.scope, stmt_source_info.scope) + { + self.append_binding_error( + grouped_errors, + kind, + move_from, + *local, + opt_match_place, + match_span, + ); + } + return; + } + } + grouped_errors.push(GroupedMoveError::OtherIllegalMove { + span: stmt_source_info.span, + kind, + }); + } + } + } + + fn append_binding_error( + self, + grouped_errors: &mut Vec>, + kind: IllegalMoveOriginKind<'tcx>, + move_from: &Place<'tcx>, + bind_to: Local, + match_place: &Option>, + match_span: Span, + ) { + debug!( + "append_to_grouped_errors(match_place={:?}, match_span={:?})", + match_place, match_span + ); + + let from_simple_let = match_place.is_none(); + let match_place = match_place.as_ref().unwrap_or(move_from); + + match self.move_data.rev_lookup.find(match_place) { + // Error with the match place + LookupResult::Parent(_) => { + for ge in &mut *grouped_errors { + if let GroupedMoveError::MovesFromMatchPlace { span, binds_to, .. } = ge { + if match_span == *span { + debug!("appending local({:?}) to list", bind_to); + if !binds_to.is_empty() { + binds_to.push(bind_to); + } + return; + } + } + } + debug!("found a new move error location"); + + // Don't need to point to x in let x = ... . + let binds_to = if from_simple_let { + vec![] + } else { + vec![bind_to] + }; + grouped_errors.push(GroupedMoveError::MovesFromMatchPlace { + span: match_span, + move_from: match_place.clone(), + kind, + binds_to, + }); + } + // Error with the pattern + LookupResult::Exact(_) => { + let mpi = match self.move_data.rev_lookup.find(move_from) { + LookupResult::Parent(Some(mpi)) => mpi, + // move_from should be a projection from match_place. + _ => unreachable!("Probably not unreachable..."), + }; + for ge in &mut *grouped_errors { + if let GroupedMoveError::MovesFromPattern { + span, + move_from: other_mpi, + binds_to, + .. + } = ge + { + if match_span == *span && mpi == *other_mpi { + debug!("appending local({:?}) to list", bind_to); + binds_to.push(bind_to); + return; + } + } + } + debug!("found a new move error location"); + grouped_errors.push(GroupedMoveError::MovesFromPattern { + span: match_span, + move_from: mpi, + kind, + binds_to: vec![bind_to], + }); + } + }; + } + + fn report(self, error: GroupedMoveError<'tcx>) { + let (mut err, err_span) = { + let (span, kind): (Span, &IllegalMoveOriginKind) = match error { + GroupedMoveError::MovesFromMatchPlace { span, ref kind, .. } + | GroupedMoveError::MovesFromPattern { span, ref kind, .. } + | GroupedMoveError::OtherIllegalMove { span, ref kind } => (span, kind), + }; + let origin = Origin::Mir; + ( + match kind { + IllegalMoveOriginKind::Static => { + self.tcx.cannot_move_out_of(span, "static item", origin) + } + IllegalMoveOriginKind::BorrowedContent { target_ty: ty } => { + // Inspect the type of the content behind the + // borrow to provide feedback about why this + // was a move rather than a copy. + match ty.sty { + ty::TyArray(..) | ty::TySlice(..) => self + .tcx + .cannot_move_out_of_interior_noncopy(span, ty, None, origin), + _ => self + .tcx + .cannot_move_out_of(span, "borrowed content", origin), + } + } + IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => { + self.tcx + .cannot_move_out_of_interior_of_drop(span, ty, origin) + } + IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => self + .tcx + .cannot_move_out_of_interior_noncopy(span, ty, Some(*is_index), origin), + }, + span, + ) + }; + + self.add_move_hints(error, &mut err, err_span); + err.emit(); + } + + fn add_move_hints( + self, + error: GroupedMoveError<'tcx>, + err: &mut DiagnosticBuilder<'a>, + span: Span, + ) { + match error { + GroupedMoveError::MovesFromMatchPlace { + mut binds_to, + move_from, + .. + } => { + // Ok to suggest a borrow, since the target can't be moved from + // anyway. + if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) { + match move_from { + Place::Projection(ref proj) + if self.suitable_to_remove_deref(proj, &snippet) => + { + err.span_suggestion( + span, + "consider removing this dereference operator", + format!("{}", &snippet[1..]), + ); + } + _ => { + err.span_suggestion( + span, + "consider using a reference instead", + format!("&{}", snippet), + ); + } + } + + binds_to.sort(); + binds_to.dedup(); + for local in binds_to { + let bind_to = &self.mir.local_decls[local]; + let binding_span = bind_to.source_info.span; + err.span_label( + binding_span, + format!( + "move occurs because {} has type `{}`, \ + which does not implement the `Copy` trait", + bind_to.name.unwrap(), + bind_to.ty + ), + ); + } + } + } + GroupedMoveError::MovesFromPattern { mut binds_to, .. } => { + // Suggest ref, since there might be a move in + // another match arm + binds_to.sort(); + binds_to.dedup(); + for local in binds_to { + let bind_to = &self.mir.local_decls[local]; + let binding_span = bind_to.source_info.span; + + // Suggest ref mut when the user has already written mut. + let ref_kind = match bind_to.mutability { + Mutability::Not => "ref", + Mutability::Mut => "ref mut", + }; + match bind_to.name { + Some(name) => { + err.span_suggestion( + binding_span, + "to prevent move, use ref or ref mut", + format!("{} {:?}", ref_kind, name), + ); + } + None => { + err.span_label( + span, + format!("Local {:?} is not suitable for ref", bind_to), + ); + } + } + } + } + // Nothing to suggest. + GroupedMoveError::OtherIllegalMove { .. } => (), + } + } + + fn suitable_to_remove_deref(self, proj: &PlaceProjection<'tcx>, snippet: &str) -> bool { + let is_shared_ref = |ty: ty::Ty| match ty.sty { + ty::TypeVariants::TyRef(.., hir::Mutability::MutImmutable) => true, + _ => false, + }; + + proj.elem == ProjectionElem::Deref && snippet.starts_with('*') && match proj.base { + Place::Local(local) => { + let local_decl = &self.mir.local_decls[local]; + // If this is a temporary, then this could be from an + // overloaded * operator. + local_decl.is_user_variable.is_some() && is_shared_ref(local_decl.ty) + } + Place::Static(ref st) => is_shared_ref(st.ty), + Place::Projection(ref proj) => match proj.elem { + ProjectionElem::Field(_, ty) => is_shared_ref(ty), + _ => false, + }, + } + } +} diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 0fd55f752b84f..bbbe757e96ec6 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -115,11 +115,21 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Declare the bindings, which may create a source scope. let remainder_span = remainder_scope.span(this.hir.tcx(), &this.hir.region_scope_tree); - let scope = this.declare_bindings(None, remainder_span, lint_level, &pattern, - ArmHasGuard(false)); + + let scope; // Evaluate the initializer, if present. if let Some(init) = initializer { + let initializer_span = init.span(); + + scope = this.declare_bindings( + None, + remainder_span, + lint_level, + &pattern, + ArmHasGuard(false), + Some((None, initializer_span)), + ); unpack!(block = this.in_opt_scope( opt_destruction_scope.map(|de|(de, source_info)), block, |this| { let scope = (init_scope, source_info); @@ -128,6 +138,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }) })); } else { + scope = this.declare_bindings(None, remainder_span, lint_level, &pattern, + ArmHasGuard(false), None); + // FIXME(#47184): We currently only insert `UserAssertTy` statements for // patterns that are bindings, this is as we do not want to deconstruct // the type being assertion to match the pattern. diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index 1fc608c52c658..d905b38331607 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -11,7 +11,6 @@ //! See docs in build/expr/mod.rs use build::{BlockAnd, BlockAndExtension, Builder}; -use build::expr::category::Category; use hair::*; use rustc::middle::region; use rustc::mir::*; @@ -57,23 +56,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }); } - // Careful here not to cause an infinite cycle. If we always - // called `into`, then for places like `x.f`, it would - // eventually fallback to us, and we'd loop. There's a reason - // for this: `as_temp` is the point where we bridge the "by - // reference" semantics of `as_place` with the "by value" - // semantics of `into`, `as_operand`, `as_rvalue`, and (of - // course) `as_temp`. - match Category::of(&expr.kind).unwrap() { - Category::Place => { - let place = unpack!(block = this.as_place(block, expr)); - let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place)); - this.cfg.push_assign(block, source_info, &Place::Local(temp), rvalue); - } - _ => { - unpack!(block = this.into(&Place::Local(temp), block, expr)); - } - } + unpack!(block = this.into(&Place::Local(temp), block, expr)); // In constants, temp_lifetime is None. We should not need to drop // anything because no values with a destructor can be created in diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 94b387abe3c13..59a7f49af8074 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -288,6 +288,37 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block.unit() } + // Avoid creating a temporary + ExprKind::VarRef { .. } | + ExprKind::SelfRef | + ExprKind::StaticRef { .. } => { + debug_assert!(Category::of(&expr.kind) == Some(Category::Place)); + + let place = unpack!(block = this.as_place(block, expr)); + let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place)); + this.cfg.push_assign(block, source_info, destination, rvalue); + block.unit() + } + ExprKind::Index { .. } | + ExprKind::Deref { .. } | + ExprKind::Field { .. } => { + debug_assert!(Category::of(&expr.kind) == Some(Category::Place)); + + // Create a "fake" temporary variable so that we check that the + // value is Sized. Usually, this is caught in type checking, but + // in the case of box expr there is no such check. + if let Place::Projection(..) = destination { + this.local_decls.push(LocalDecl::new_temp(expr.ty, expr.span)); + } + + debug_assert!(Category::of(&expr.kind) == Some(Category::Place)); + + let place = unpack!(block = this.as_place(block, expr)); + let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place)); + this.cfg.push_assign(block, source_info, destination, rvalue); + block.unit() + } + // these are the cases that are more naturally handled by some other mode ExprKind::Unary { .. } | ExprKind::Binary { .. } | @@ -300,18 +331,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Unsize { .. } | ExprKind::Repeat { .. } | ExprKind::Borrow { .. } | - ExprKind::VarRef { .. } | - ExprKind::SelfRef | - ExprKind::StaticRef { .. } | ExprKind::Array { .. } | ExprKind::Tuple { .. } | ExprKind::Adt { .. } | ExprKind::Closure { .. } | - ExprKind::Index { .. } | - ExprKind::Deref { .. } | ExprKind::Literal { .. } | - ExprKind::Yield { .. } | - ExprKind::Field { .. } => { + ExprKind::Yield { .. } => { debug_assert!(match Category::of(&expr.kind).unwrap() { Category::Rvalue(RvalueFunc::Into) => false, _ => true, diff --git a/src/librustc_mir/build/expr/mod.rs b/src/librustc_mir/build/expr/mod.rs index 0fd4b8e7e2302..a63cf41f0663e 100644 --- a/src/librustc_mir/build/expr/mod.rs +++ b/src/librustc_mir/build/expr/mod.rs @@ -65,7 +65,7 @@ //! which can fallback to `into`. So if one of the `ExprKind` variants is not, in fact, //! implemented in the category where it is supposed to be, there will be a problem. //! -//! Of those fallbacks, the most interesting one is `as_temp`, because +//! Of those fallbacks, the most interesting one is `into`, because //! it discriminates based on the category of the expression. This is //! basically the point where the "by value" operations are bridged //! over to the "by reference" mode (`as_place`). diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index b6af0ed2a4a1c..79dbdfefeb8e1 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -44,6 +44,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { arms: Vec>) -> BlockAnd<()> { let tcx = self.hir.tcx(); + let discriminant_span = discriminant.span(); let discriminant_place = unpack!(block = self.as_place(block, discriminant)); // Matching on a `discriminant_place` with an uninhabited type doesn't @@ -96,7 +97,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let scope = self.declare_bindings(None, body.span, LintLevel::Inherited, &arm.patterns[0], - ArmHasGuard(arm.guard.is_some())); + ArmHasGuard(arm.guard.is_some()), + Some((Some(&discriminant_place), discriminant_span))); (body, scope.unwrap_or(self.source_scope)) }).collect(); @@ -254,7 +256,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } _ => { let place = unpack!(block = self.as_place(block, initializer)); - self.place_into_pattern(block, irrefutable_pat, &place) + self.place_into_pattern(block, irrefutable_pat, &place, true) } } } @@ -262,7 +264,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn place_into_pattern(&mut self, mut block: BasicBlock, irrefutable_pat: Pattern<'tcx>, - initializer: &Place<'tcx>) + initializer: &Place<'tcx>, + set_match_place: bool) -> BlockAnd<()> { // create a dummy candidate let mut candidate = Candidate { @@ -288,6 +291,25 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { candidate.match_pairs); } + // for matches and function arguments, the place that is being matched + // can be set when creating the variables. But the place for + // let PATTERN = ... might not even exist until we do the assignment. + // so we set it here instead + if set_match_place { + for binding in &candidate.bindings { + let local = self.var_local_id(binding.var_id, OutsideGuard); + + if let Some(ClearCrossCrate::Set(BindingForm::Var( + VarBindingForm {opt_match_place: Some((ref mut match_place, _)), .. } + ))) = self.local_decls[local].is_user_variable + { + *match_place = Some(initializer.clone()); + } else { + bug!("Let binding to non-user variable.") + } + } + } + // now apply the bindings, which will also declare the variables self.bind_matched_candidate_for_arm_body(block, &candidate.bindings); @@ -302,7 +324,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { scope_span: Span, lint_level: LintLevel, pattern: &Pattern<'tcx>, - has_guard: ArmHasGuard) + has_guard: ArmHasGuard, + opt_match_place: Option<(Option<&Place<'tcx>>, Span)>) -> Option { assert!(!(visibility_scope.is_some() && lint_level.is_explicit()), "can't have both a visibility and a lint scope at the same time"); @@ -326,7 +349,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }; let visibility_scope = visibility_scope.unwrap(); this.declare_binding(source_info, visibility_scope, mutability, name, mode, var, - ty, has_guard); + ty, has_guard, opt_match_place.map(|(x, y)| (x.cloned(), y))); }); visibility_scope } @@ -1121,7 +1144,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { mode: BindingMode, var_id: NodeId, var_ty: Ty<'tcx>, - has_guard: ArmHasGuard) + has_guard: ArmHasGuard, + opt_match_place: Option<(Option>, Span)>) { debug!("declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \ visibility_scope={:?}, source_info={:?})", @@ -1146,6 +1170,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // idents in pat; but complex w/ unclear UI payoff. // Instead, just abandon providing diagnostic info. opt_ty_info: None, + opt_match_place, }))), }; let for_arm_body = self.local_decls.push(local.clone()); diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 8567141461803..cdbb2a13e0ef2 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -705,6 +705,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if let Some(pattern) = pattern { let pattern = self.hir.pattern_from_hir(pattern); + let span = pattern.span; match *pattern.kind { // Don't introduce extra copies for simple bindings @@ -716,15 +717,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } else { let binding_mode = ty::BindingMode::BindByValue(mutability.into()); Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { - binding_mode, opt_ty_info }))) + binding_mode, + opt_ty_info, + opt_match_place: Some((Some(place.clone()), span)), + }))) }; self.var_indices.insert(var, LocalsForNode::One(local)); } _ => { scope = self.declare_bindings(scope, ast_body.span, LintLevel::Inherited, &pattern, - matches::ArmHasGuard(false)); - unpack!(block = self.place_into_pattern(block, pattern, &place)); + matches::ArmHasGuard(false), + Some((Some(&place), span))); + unpack!(block = self.place_into_pattern(block, pattern, &place, false)); } } } diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 590f9917015dc..9ffbe21e1e2cc 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -109,8 +109,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { match *place { Place::Local(local) => Ok(self.builder.data.rev_lookup.locals[local]), Place::Static(..) => { - let span = self.builder.mir.source_info(self.loc).span; - Err(MoveError::cannot_move_out_of(span, Static)) + Err(MoveError::cannot_move_out_of(self.loc, Static)) } Place::Projection(ref proj) => { self.move_path_for_projection(place, proj) @@ -133,13 +132,13 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { let mir = self.builder.mir; let tcx = self.builder.tcx; let place_ty = proj.base.ty(mir, tcx).to_ty(tcx); - match place_ty.sty { + match place_ty.sty { ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MoveError::cannot_move_out_of( - mir.source_info(self.loc).span, + self.loc, BorrowedContent { target_ty: place.ty(mir, tcx).to_ty(tcx) })), ty::TyAdt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => - return Err(MoveError::cannot_move_out_of(mir.source_info(self.loc).span, + return Err(MoveError::cannot_move_out_of(self.loc, InteriorOfTypeWithDestructor { container_ty: place_ty })), @@ -148,7 +147,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { return Err(MoveError::UnionMove { path: base }), ty::TySlice(_) => return Err(MoveError::cannot_move_out_of( - mir.source_info(self.loc).span, + self.loc, InteriorOfSliceOrArray { ty: place_ty, is_index: match proj.elem { ProjectionElem::Index(..) => true, @@ -158,7 +157,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { ty::TyArray(..) => match proj.elem { ProjectionElem::Index(..) => return Err(MoveError::cannot_move_out_of( - mir.source_info(self.loc).span, + self.loc, InteriorOfSliceOrArray { ty: place_ty, is_index: true })), diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index a73e47bc16ab2..3051a687eac70 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -209,7 +209,7 @@ pub enum InitKind { Deep, /// Only does a shallow init Shallow, - /// This doesn't initialize the variabe on panic (and a panic is possible). + /// This doesn't initialize the variable on panic (and a panic is possible). NonPanicPathOnly, } @@ -271,7 +271,7 @@ impl<'tcx> MovePathLookup<'tcx> { #[derive(Debug)] pub struct IllegalMoveOrigin<'tcx> { - pub(crate) span: Span, + pub(crate) location: Location, pub(crate) kind: IllegalMoveOriginKind<'tcx>, } @@ -304,8 +304,8 @@ pub enum MoveError<'tcx> { } impl<'tcx> MoveError<'tcx> { - fn cannot_move_out_of(span: Span, kind: IllegalMoveOriginKind<'tcx>) -> Self { - let origin = IllegalMoveOrigin { span, kind }; + fn cannot_move_out_of(location: Location, kind: IllegalMoveOriginKind<'tcx>) -> Self { + let origin = IllegalMoveOrigin { location, kind }; MoveError::IllegalMove { cannot_move_out_of: origin } } } diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index ab9acdc49507c..a8d29df86908d 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -315,6 +315,15 @@ pub enum LogicalOp { Or, } +impl<'tcx> ExprRef<'tcx> { + pub fn span(&self) -> Span { + match self { + ExprRef::Hair(expr) => expr.span, + ExprRef::Mirror(expr) => expr.span, + } + } +} + /////////////////////////////////////////////////////////////////////////// // The Mirror trait diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs b/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs index 8e1f7c7291474..4bb66ace02687 100644 --- a/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs +++ b/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs @@ -18,9 +18,9 @@ impl Drop for S { fn move_in_match() { match (S {f:"foo".to_string()}) { + //[mir]~^ ERROR [E0509] S {f:_s} => {} //[ast]~^ ERROR cannot move out of type `S`, which implements the `Drop` trait [E0509] - //[mir]~^^ ERROR [E0509] } } diff --git a/src/test/mir-opt/combine_array_len.rs b/src/test/mir-opt/combine_array_len.rs index 136c3493fa407..440ad3518ae5a 100644 --- a/src/test/mir-opt/combine_array_len.rs +++ b/src/test/mir-opt/combine_array_len.rs @@ -21,13 +21,13 @@ fn main() { // END RUST SOURCE // START rustc.norm2.InstCombine.before.mir -// _5 = Len(_1); +// _4 = Len(_1); // ... -// _10 = Len(_1); +// _8 = Len(_1); // END rustc.norm2.InstCombine.before.mir // START rustc.norm2.InstCombine.after.mir -// _5 = const 2usize; +// _4 = const 2usize; // ... -// _10 = const 2usize; +// _8 = const 2usize; // END rustc.norm2.InstCombine.after.mir diff --git a/src/test/mir-opt/copy_propagation.rs b/src/test/mir-opt/copy_propagation.rs index 50d8a5154c449..067a937b0b30c 100644 --- a/src/test/mir-opt/copy_propagation.rs +++ b/src/test/mir-opt/copy_propagation.rs @@ -22,12 +22,9 @@ fn main() { // START rustc.test.CopyPropagation.before.mir // bb0: { // ... -// _3 = _1; +// _2 = _1; // ... -// _2 = move _3; -// ... -// _4 = _2; -// _0 = move _4; +// _0 = _2; // ... // return; // } @@ -35,7 +32,7 @@ fn main() { // START rustc.test.CopyPropagation.after.mir // bb0: { // ... -// _0 = move _1; +// _0 = _1; // ... // return; // } diff --git a/src/test/mir-opt/copy_propagation_arg.rs b/src/test/mir-opt/copy_propagation_arg.rs index feadec6bbf76e..dacaff8f2d942 100644 --- a/src/test/mir-opt/copy_propagation_arg.rs +++ b/src/test/mir-opt/copy_propagation_arg.rs @@ -117,13 +117,11 @@ fn main() { // START rustc.arg_src.CopyPropagation.before.mir // bb0: { // ... -// _3 = _1; -// _2 = move _3; +// _2 = _1; // ... // _1 = const 123i32; // ... -// _4 = _2; -// _0 = move _4; +// _0 = _2; // ... // return; // } @@ -131,11 +129,11 @@ fn main() { // START rustc.arg_src.CopyPropagation.after.mir // bb0: { // ... -// _3 = _1; +// _2 = _1; // ... // _1 = const 123i32; // ... -// _0 = move _3; +// _0 = _2; // ... // return; // } diff --git a/src/test/mir-opt/end_region_5.rs b/src/test/mir-opt/end_region_5.rs index 1da97a997a19c..9496fd9e6c173 100644 --- a/src/test/mir-opt/end_region_5.rs +++ b/src/test/mir-opt/end_region_5.rs @@ -68,13 +68,9 @@ fn foo(f: F) where F: FnOnce() -> i32 { // START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir // fn main::{{closure}}(_1: [closure@NodeId(18) d:&'14s D]) -> i32 { // let mut _0: i32; -// let mut _2: i32; // // bb0: { -// StorageLive(_2); -// _2 = ((*(_1.0: &'14s D)).0: i32); -// _0 = move _2; -// StorageDead(_2); +// _0 = ((*(_1.0: &'14s D)).0: i32); // return; // } // END rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_6.rs b/src/test/mir-opt/end_region_6.rs index 30ba14c1bab3a..910362f65c8d9 100644 --- a/src/test/mir-opt/end_region_6.rs +++ b/src/test/mir-opt/end_region_6.rs @@ -70,14 +70,10 @@ fn foo(f: F) where F: FnOnce() -> i32 { // ... // let _2: &'16_0rs D; // ... -// let mut _3: i32; // bb0: { // StorageLive(_2); // _2 = &'16_0rs (*(_1.0: &'19s D)); -// StorageLive(_3); -// _3 = ((*_2).0: i32); -// _0 = move _3; -// StorageDead(_3); +// _0 = ((*_2).0: i32); // EndRegion('16_0rs); // StorageDead(_2); // return; diff --git a/src/test/mir-opt/end_region_7.rs b/src/test/mir-opt/end_region_7.rs index 6d6afa25ae30e..e44b41993aa95 100644 --- a/src/test/mir-opt/end_region_7.rs +++ b/src/test/mir-opt/end_region_7.rs @@ -78,14 +78,10 @@ fn foo(f: F) where F: FnOnce() -> i32 { // ... // let _2: &'16_0rs D; // ... -// let mut _3: i32; // bb0: { // StorageLive(_2); // _2 = &'16_0rs (_1.0: D); -// StorageLive(_3); -// _3 = ((*_2).0: i32); -// _0 = move _3; -// StorageDead(_3); +// _0 = ((*_2).0: i32); // EndRegion('16_0rs); // StorageDead(_2); // drop(_1) -> [return: bb2, unwind: bb1]; diff --git a/src/test/mir-opt/end_region_8.rs b/src/test/mir-opt/end_region_8.rs index 96a64f2eebfb4..7fdf971b3b9df 100644 --- a/src/test/mir-opt/end_region_8.rs +++ b/src/test/mir-opt/end_region_8.rs @@ -76,13 +76,9 @@ fn foo(f: F) where F: FnOnce() -> i32 { // START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir // fn main::{{closure}}(_1: [closure@NodeId(22) r:&'19s D]) -> i32 { // let mut _0: i32; -// let mut _2: i32; // // bb0: { -// StorageLive(_2); -// _2 = ((*(_1.0: &'21_1rs D)).0: i32); -// _0 = move _2; -// StorageDead(_2); +// _0 = ((*(_1.0: &'21_1rs D)).0: i32); // return; // } // } diff --git a/src/test/mir-opt/end_region_destruction_extents_1.rs b/src/test/mir-opt/end_region_destruction_extents_1.rs index 15b104f6c2ff7..fab2f9eff5af3 100644 --- a/src/test/mir-opt/end_region_destruction_extents_1.rs +++ b/src/test/mir-opt/end_region_destruction_extents_1.rs @@ -65,52 +65,45 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> { // START rustc.main.QualifyAndPromoteConstants.before.mir // fn main() -> () { -// let mut _0: (); +// let mut _0: (); // let mut _1: &'12ds S1; -// let mut _2: &'12ds S1; -// let mut _3: D1<'12ds, '10s>; +// let mut _2: D1<'12ds, '10s>; +// let mut _3: &'12ds S1; // let mut _4: &'12ds S1; -// let mut _5: &'12ds S1; -// let mut _6: S1; +// let mut _5: S1; +// let mut _6: &'10s S1; // let mut _7: &'10s S1; -// let mut _8: &'10s S1; -// let mut _9: S1; -// +// let mut _8: S1; // bb0: { // StorageLive(_2); // StorageLive(_3); // StorageLive(_4); // StorageLive(_5); +// _5 = S1::{{constructor}}(const "ex1",); +// _4 = &'12ds _5; +// _3 = &'12ds (*_4); // StorageLive(_6); -// _6 = S1::{{constructor}}(const "ex1",); -// _5 = &'12ds _6; -// _4 = &'12ds (*_5); // StorageLive(_7); // StorageLive(_8); -// StorageLive(_9); -// _9 = S1::{{constructor}}(const "dang1",); -// _8 = &'10s _9; -// _7 = &'10s (*_8); -// _3 = D1<'12ds, '10s>::{{constructor}}(move _4, move _7); +// _8 = S1::{{constructor}}(const "dang1",); +// _7 = &'10s _8; +// _6 = &'10s (*_7); +// _2 = D1<'12ds, '10s>::{{constructor}}(move _3, move _6); // EndRegion('10s); -// StorageDead(_7); -// StorageDead(_4); -// _2 = (_3.0: &'12ds S1); -// _1 = move _2; -// StorageDead(_2); -// drop(_3) -> [return: bb2, unwind: bb1]; +// StorageDead(_6); +// StorageDead(_3); +// _1 = (_2.0: &'12ds S1); +// drop(_2) -> [return: bb2, unwind: bb1]; // } -// // bb1: { // resume; // } -// // bb2: { -// StorageDead(_3); +// StorageDead(_2); +// StorageDead(_7); // StorageDead(_8); -// StorageDead(_9); +// StorageDead(_4); // StorageDead(_5); -// StorageDead(_6); // EndRegion('12ds); // _0 = (); // return; @@ -119,51 +112,44 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> { // END rustc.main.QualifyAndPromoteConstants.before.mir // START rustc.main.QualifyAndPromoteConstants.after.mir -// fn main() -> () { +// fn main() -> (){ // let mut _0: (); // let mut _1: &'12ds S1; -// let mut _2: &'12ds S1; -// let mut _3: D1<'12ds, '10s>; +// let mut _2: D1<'12ds, '10s>; +// let mut _3: &'12ds S1; // let mut _4: &'12ds S1; -// let mut _5: &'12ds S1; -// let mut _6: S1; +// let mut _5: S1; +// let mut _6: &'10s S1; // let mut _7: &'10s S1; -// let mut _8: &'10s S1; -// let mut _9: S1; -// let mut _10: &'10s S1; -// let mut _11: &'12ds S1; -// +// let mut _8: S1; +// let mut _9: &'10s S1; +// let mut _10: &'12ds S1; // bb0: { // StorageLive(_2); // StorageLive(_3); // StorageLive(_4); -// StorageLive(_5); -// _11 = promoted[1]; -// _5 = &'12ds (*_11); -// _4 = &'12ds (*_5); +// _10 = promoted[1]; +// _4 = &'12ds (*_10); +// _3 = &'12ds (*_4); +// StorageLive(_6); // StorageLive(_7); -// StorageLive(_8); -// _10 = promoted[0]; -// _8 = &'10s (*_10); -// _7 = &'10s (*_8); -// _3 = D1<'12ds, '10s>::{{constructor}}(move _4, move _7); +// _9 = promoted[0]; +// _7 = &'10s (*_9); +// _6 = &'10s (*_7); +// _2 = D1<'12ds, '10s>::{{constructor}}(move _3, move _6); // EndRegion('10s); -// StorageDead(_7); -// StorageDead(_4); -// _2 = (_3.0: &'12ds S1); -// _1 = move _2; -// StorageDead(_2); -// drop(_3) -> [return: bb2, unwind: bb1]; +// StorageDead(_6); +// StorageDead(_3); +// _1 = (_2.0: &'12ds S1); +// drop(_2) -> [return: bb2, unwind: bb1]; // } -// // bb1: { // resume; // } -// // bb2: { -// StorageDead(_3); -// StorageDead(_8); -// StorageDead(_5); +// StorageDead(_2); +// StorageDead(_7); +// StorageDead(_4); // EndRegion('12ds); // _0 = (); // return; diff --git a/src/test/mir-opt/inline-closure-borrows-arg.rs b/src/test/mir-opt/inline-closure-borrows-arg.rs index 3fb54f90984dd..6ce51be3ec5db 100644 --- a/src/test/mir-opt/inline-closure-borrows-arg.rs +++ b/src/test/mir-opt/inline-closure-borrows-arg.rs @@ -38,11 +38,9 @@ fn foo(_t: T, q: &i32) -> i32 { // ... // _7 = &(*_2); // _5 = (move _6, move _7); -// _9 = move (_5.0: &i32); -// _10 = move (_5.1: &i32); -// StorageLive(_8); -// _8 = (*_9); -// _0 = move _8; +// _8 = move (_5.0: &i32); +// _9 = move (_5.1: &i32); +// _0 = (*_8); // ... // return; // } diff --git a/src/test/mir-opt/inline-closure.rs b/src/test/mir-opt/inline-closure.rs index dc8ff13c03a88..22e7de31e90cf 100644 --- a/src/test/mir-opt/inline-closure.rs +++ b/src/test/mir-opt/inline-closure.rs @@ -36,7 +36,7 @@ fn foo(_t: T, q: i32) -> i32 { // _5 = (move _6, move _7); // _8 = move (_5.0: i32); // _9 = move (_5.1: i32); -// _0 = move _8; +// _0 = _8; // ... // return; // } diff --git a/src/test/mir-opt/lower_128bit_debug_test.rs b/src/test/mir-opt/lower_128bit_debug_test.rs index d7586b1aa4b10..646c4312fc21f 100644 --- a/src/test/mir-opt/lower_128bit_debug_test.rs +++ b/src/test/mir-opt/lower_128bit_debug_test.rs @@ -182,8 +182,8 @@ fn main() { // ... // _1 = move (_13.0: i128); // ... -// _17 = const 7i32 as u128 (Misc); -// _14 = const compiler_builtins::int::shift::rust_i128_shro(_1, move _17) -> bb16; +// _16 = const 7i32 as u128 (Misc); +// _14 = const compiler_builtins::int::shift::rust_i128_shro(_1, move _16) -> bb16; // ... // _1 = move (_14.0: i128); // ... @@ -195,8 +195,8 @@ fn main() { // ... // assert(!move (_13.1: bool), "attempt to shift left with overflow") -> bb8; // ... -// _16 = const 6i32 as u128 (Misc); -// _13 = const compiler_builtins::int::shift::rust_i128_shlo(_1, move _16) -> bb14; +// _15 = const 6i32 as u128 (Misc); +// _13 = const compiler_builtins::int::shift::rust_i128_shlo(_1, move _15) -> bb14; // ... // assert(!move (_14.1: bool), "attempt to shift right with overflow") -> bb9; // END rustc.test_signed.Lower128Bit.after.mir @@ -218,8 +218,8 @@ fn main() { // ... // _1 = move (_7.0: u128); // ... -// _11 = const 7i32 as u128 (Misc); -// _8 = const compiler_builtins::int::shift::rust_u128_shro(_1, move _11) -> bb14; +// _10 = const 7i32 as u128 (Misc); +// _8 = const compiler_builtins::int::shift::rust_u128_shro(_1, move _10) -> bb14; // ... // _1 = move (_8.0: u128); // ... @@ -231,8 +231,8 @@ fn main() { // ... // assert(!move (_7.1: bool), "attempt to shift left with overflow") -> bb6; // ... -// _10 = const 6i32 as u128 (Misc); -// _7 = const compiler_builtins::int::shift::rust_u128_shlo(_1, move _10) -> bb12; +// _9 = const 6i32 as u128 (Misc); +// _7 = const compiler_builtins::int::shift::rust_u128_shlo(_1, move _9) -> bb12; // ... // assert(!move (_8.1: bool), "attempt to shift right with overflow") -> bb7; // END rustc.test_unsigned.Lower128Bit.after.mir diff --git a/src/test/mir-opt/lower_128bit_test.rs b/src/test/mir-opt/lower_128bit_test.rs index 341682debeb35..27446d6bd28f5 100644 --- a/src/test/mir-opt/lower_128bit_test.rs +++ b/src/test/mir-opt/lower_128bit_test.rs @@ -176,11 +176,11 @@ fn main() { // ... // _1 = const compiler_builtins::int::addsub::rust_i128_sub(_1, const 2i128) -> bb6; // ... -// _11 = const 7i32 as u32 (Misc); -// _1 = const compiler_builtins::int::shift::rust_i128_shr(_1, move _11) -> bb9; +// _10 = const 7i32 as u32 (Misc); +// _1 = const compiler_builtins::int::shift::rust_i128_shr(_1, move _10) -> bb9; // ... -// _12 = const 6i32 as u32 (Misc); -// _1 = const compiler_builtins::int::shift::rust_i128_shl(_1, move _12) -> bb10; +// _11 = const 6i32 as u32 (Misc); +// _1 = const compiler_builtins::int::shift::rust_i128_shl(_1, move _11) -> bb10; // END rustc.test_signed.Lower128Bit.after.mir // START rustc.test_unsigned.Lower128Bit.after.mir @@ -194,9 +194,9 @@ fn main() { // ... // _1 = const compiler_builtins::int::addsub::rust_u128_sub(_1, const 2u128) -> bb4; // ... -// _5 = const 7i32 as u32 (Misc); -// _1 = const compiler_builtins::int::shift::rust_u128_shr(_1, move _5) -> bb7; +// _4 = const 7i32 as u32 (Misc); +// _1 = const compiler_builtins::int::shift::rust_u128_shr(_1, move _4) -> bb7; // ... -// _6 = const 6i32 as u32 (Misc); -// _1 = const compiler_builtins::int::shift::rust_u128_shl(_1, move _6) -> bb8; +// _5 = const 6i32 as u32 (Misc); +// _1 = const compiler_builtins::int::shift::rust_u128_shl(_1, move _5) -> bb8; // END rustc.test_unsigned.Lower128Bit.after.mir diff --git a/src/test/mir-opt/nll/region-subtyping-basic.rs b/src/test/mir-opt/nll/region-subtyping-basic.rs index 57a11d8dd25cb..a8dd6c73ef017 100644 --- a/src/test/mir-opt/nll/region-subtyping-basic.rs +++ b/src/test/mir-opt/nll/region-subtyping-basic.rs @@ -32,9 +32,9 @@ fn main() { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#2r | {bb2[0..=6], bb3[0..=1]} -// | '_#3r | {bb2[1..=6], bb3[0..=1]} -// | '_#4r | {bb2[5..=6], bb3[0..=1]} +// | '_#2r | {bb2[0..=3], bb3[0..=1]} +// | '_#3r | {bb2[1..=3], bb3[0..=1]} +// | '_#4r | {bb2[3], bb3[0..=1]} // END rustc.main.nll.0.mir // START rustc.main.nll.0.mir // let _6: &'_#4r usize; @@ -43,7 +43,5 @@ fn main() { // ... // _2 = &'_#2r _1[_3]; // ... -// _7 = _2; -// ... -// _6 = move _7; +// _6 = _2; // END rustc.main.nll.0.mir diff --git a/src/test/mir-opt/validate_1.rs b/src/test/mir-opt/validate_1.rs index c331276aade77..2d5c98ff0ed91 100644 --- a/src/test/mir-opt/validate_1.rs +++ b/src/test/mir-opt/validate_1.rs @@ -67,10 +67,7 @@ fn main() { // Validate(Suspend(ReScope(Remainder(BlockRemainder { block: ItemLocalId(25), first_statement_index: 0 }))), [(*_2): i32]); // _3 = &ReErased (*_2); // Validate(Acquire, [(*_3): i32/ReScope(Remainder(BlockRemainder { block: ItemLocalId(25), first_statement_index: 0 })) (imm)]); -// StorageLive(_4); -// _4 = (*_3); -// _0 = move _4; -// StorageDead(_4); +// _0 = (*_3); // EndRegion(ReScope(Remainder(BlockRemainder { block: ItemLocalId(25), first_statement_index: 0 }))); // StorageDead(_3); // return; diff --git a/src/test/ui/E0508.ast.nll.stderr b/src/test/ui/E0508.ast.nll.stderr deleted file mode 100644 index 28403644a234a..0000000000000 --- a/src/test/ui/E0508.ast.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array - --> $DIR/E0508.rs:18:18 - | -LL | let _value = array[0]; //[ast]~ ERROR [E0508] - | ^^^^^^^^ cannot move out of here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/E0508.mir.stderr b/src/test/ui/E0508.mir.stderr deleted file mode 100644 index 28403644a234a..0000000000000 --- a/src/test/ui/E0508.mir.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array - --> $DIR/E0508.rs:18:18 - | -LL | let _value = array[0]; //[ast]~ ERROR [E0508] - | ^^^^^^^^ cannot move out of here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/E0508.rs b/src/test/ui/E0508.rs index 0c3dce6b0346a..86445ad89821c 100644 --- a/src/test/ui/E0508.rs +++ b/src/test/ui/E0508.rs @@ -8,13 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - struct NonCopy; fn main() { let array = [NonCopy; 1]; - let _value = array[0]; //[ast]~ ERROR [E0508] - //[mir]~^ ERROR [E0508] + let _value = array[0]; //~ ERROR [E0508] } diff --git a/src/test/ui/E0508.ast.stderr b/src/test/ui/E0508.stderr similarity index 81% rename from src/test/ui/E0508.ast.stderr rename to src/test/ui/E0508.stderr index 5878b795b771c..28ce0d971c69d 100644 --- a/src/test/ui/E0508.ast.stderr +++ b/src/test/ui/E0508.stderr @@ -1,7 +1,7 @@ error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array - --> $DIR/E0508.rs:18:18 + --> $DIR/E0508.rs:15:18 | -LL | let _value = array[0]; //[ast]~ ERROR [E0508] +LL | let _value = array[0]; //~ ERROR [E0508] | ^^^^^^^^ | | | cannot move out of here diff --git a/src/test/ui/borrowck/borrowck-move-error-with-note.nll.stderr b/src/test/ui/borrowck/borrowck-move-error-with-note.nll.stderr index c563a28b317d6..a34c97974da11 100644 --- a/src/test/ui/borrowck/borrowck-move-error-with-note.nll.stderr +++ b/src/test/ui/borrowck/borrowck-move-error-with-note.nll.stderr @@ -1,40 +1,46 @@ error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-move-error-with-note.rs:23:19 + --> $DIR/borrowck-move-error-with-note.rs:21:11 | +LL | match *f { //~ ERROR cannot move out of + | ^^ + | | + | cannot move out of borrowed content + | help: consider removing this dereference operator: `f` +LL | //~| cannot move out LL | Foo::Foo1(num1, - | ^^^^ cannot move out of borrowed content - -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-move-error-with-note.rs:24:19 - | + | ---- move occurs because num1 has type `std::boxed::Box`, which does not implement the `Copy` trait LL | num2) => (), - | ^^^^ cannot move out of borrowed content - -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-move-error-with-note.rs:25:19 - | + | ---- move occurs because num2 has type `std::boxed::Box`, which does not implement the `Copy` trait LL | Foo::Foo2(num) => (), - | ^^^ cannot move out of borrowed content + | --- move occurs because num has type `std::boxed::Box`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-move-error-with-note.rs:42:16 + --> $DIR/borrowck-move-error-with-note.rs:39:11 | -LL | f: _s, - | ^^ cannot move out of here - -error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-move-error-with-note.rs:43:16 +LL | match (S {f: "foo".to_string(), g: "bar".to_string()}) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here +help: to prevent move, use ref or ref mut + | +LL | f: ref _s, + | ^^^^^^ +help: to prevent move, use ref or ref mut | -LL | g: _t - | ^^ cannot move out of here +LL | g: ref _t + | ^^^^^^ error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-move-error-with-note.rs:59:9 + --> $DIR/borrowck-move-error-with-note.rs:57:11 | +LL | match a.a { //~ ERROR cannot move out of + | ^^^ + | | + | cannot move out of borrowed content + | help: consider using a reference instead: `&a.a` +LL | //~| cannot move out LL | n => { - | ^ cannot move out of borrowed content + | - move occurs because n has type `std::boxed::Box`, which does not implement the `Copy` trait -error: aborting due to 6 previous errors +error: aborting due to 3 previous errors Some errors occurred: E0507, E0509. For more information about an error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.nll.stderr b/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.nll.stderr index 96b376ea7ae40..d01b24507d9fe 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.nll.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.nll.stderr @@ -1,15 +1,17 @@ error[E0508]: cannot move out of type `[Foo]`, a non-copy slice - --> $DIR/borrowck-move-out-of-vec-tail.rs:30:33 + --> $DIR/borrowck-move-out-of-vec-tail.rs:29:19 | -LL | &[Foo { string: a }, - | ^ cannot move out of here - -error[E0508]: cannot move out of type `[Foo]`, a non-copy slice - --> $DIR/borrowck-move-out-of-vec-tail.rs:34:33 +LL | match tail { + | ^^^^ cannot move out of here +help: to prevent move, use ref or ref mut + | +LL | &[Foo { string: ref a }, + | ^^^^^ +help: to prevent move, use ref or ref mut | -LL | Foo { string: b }] => { - | ^ cannot move out of here +LL | Foo { string: ref b }] => { + | ^^^^^ -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.nll.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.nll.stderr index 6d28a37463b92..50ef3ba40e7b2 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.nll.stderr +++ b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.nll.stderr @@ -23,54 +23,68 @@ LL | _b.use_ref(); | -- borrow later used here error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:44:15 + --> $DIR/borrowck-vec-pattern-nesting.rs:43:11 | +LL | match vec { + | ^^^ cannot move out of here LL | &mut [_a, //~ ERROR cannot move out - | ^^ cannot move out of here + | -- help: to prevent move, use ref or ref mut: `ref _a` error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice --> $DIR/borrowck-vec-pattern-nesting.rs:57:13 | LL | let a = vec[0]; //~ ERROR cannot move out - | ^^^^^^ cannot move out of here + | ^^^^^^ + | | + | cannot move out of here + | help: consider using a reference instead: `&vec[0]` error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:67:10 + --> $DIR/borrowck-vec-pattern-nesting.rs:64:11 | +LL | match vec { + | ^^^ cannot move out of here +... LL | _b] => {} - | ^^ cannot move out of here + | -- help: to prevent move, use ref or ref mut: `ref _b` error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice --> $DIR/borrowck-vec-pattern-nesting.rs:70:13 | LL | let a = vec[0]; //~ ERROR cannot move out - | ^^^^^^ cannot move out of here + | ^^^^^^ + | | + | cannot move out of here + | help: consider using a reference instead: `&vec[0]` error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:78:15 + --> $DIR/borrowck-vec-pattern-nesting.rs:77:11 | -LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out - | ^^ cannot move out of here - -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:78:19 +LL | match vec { + | ^^^ cannot move out of here +help: to prevent move, use ref or ref mut | -LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out - | ^^ cannot move out of here - -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:78:23 +LL | &mut [ref _a, _b, _c] => {} //~ ERROR cannot move out + | ^^^^^^ +help: to prevent move, use ref or ref mut + | +LL | &mut [_a, ref _b, _c] => {} //~ ERROR cannot move out + | ^^^^^^ +help: to prevent move, use ref or ref mut | -LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out - | ^^ cannot move out of here +LL | &mut [_a, _b, ref _c] => {} //~ ERROR cannot move out + | ^^^^^^ error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice --> $DIR/borrowck-vec-pattern-nesting.rs:82:13 | LL | let a = vec[0]; //~ ERROR cannot move out - | ^^^^^^ cannot move out of here + | ^^^^^^ + | | + | cannot move out of here + | help: consider using a reference instead: `&vec[0]` -error: aborting due to 10 previous errors +error: aborting due to 8 previous errors Some errors occurred: E0506, E0508. For more information about an error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/issue-51415.nll.stderr b/src/test/ui/borrowck/issue-51415.nll.stderr index 79454b635263c..d872c7efe2bc1 100644 --- a/src/test/ui/borrowck/issue-51415.nll.stderr +++ b/src/test/ui/borrowck/issue-51415.nll.stderr @@ -1,8 +1,11 @@ error[E0507]: cannot move out of borrowed content - --> $DIR/issue-51415.rs:16:47 + --> $DIR/issue-51415.rs:16:42 | LL | let opt = a.iter().enumerate().find(|(_, &s)| { - | ^ cannot move out of borrowed content + | ^^^^^-^ + | | | + | | help: to prevent move, use ref or ref mut: `ref s` + | cannot move out of borrowed content error: aborting due to previous error diff --git a/src/test/ui/codemap_tests/overlapping_spans.nll.stderr b/src/test/ui/codemap_tests/overlapping_spans.nll.stderr index b6630b2e666cf..34616a8de45ed 100644 --- a/src/test/ui/codemap_tests/overlapping_spans.nll.stderr +++ b/src/test/ui/codemap_tests/overlapping_spans.nll.stderr @@ -1,8 +1,10 @@ error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/overlapping_spans.rs:21:14 + --> $DIR/overlapping_spans.rs:20:11 | +LL | match (S {f:"foo".to_string()}) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here LL | S {f:_s} => {} //~ ERROR cannot move out - | ^^ cannot move out of here + | -- help: to prevent move, use ref or ref mut: `ref _s` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0509.nll.stderr b/src/test/ui/error-codes/E0509.nll.stderr deleted file mode 100644 index 56d970494a0e0..0000000000000 --- a/src/test/ui/error-codes/E0509.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0509]: cannot move out of type `DropStruct`, which implements the `Drop` trait - --> $DIR/E0509.rs:26:23 - | -LL | let fancy_field = drop_struct.fancy; //~ ERROR E0509 - | ^^^^^^^^^^^^^^^^^ cannot move out of here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0509`. diff --git a/src/test/ui/issue-40402-ref-hints/issue-40402-1.nll.stderr b/src/test/ui/issue-40402-ref-hints/issue-40402-1.nll.stderr index 48e27014792c7..162e43abc0ac4 100644 --- a/src/test/ui/issue-40402-ref-hints/issue-40402-1.nll.stderr +++ b/src/test/ui/issue-40402-ref-hints/issue-40402-1.nll.stderr @@ -2,7 +2,10 @@ error[E0507]: cannot move out of borrowed content --> $DIR/issue-40402-1.rs:19:13 | LL | let e = f.v[0]; //~ ERROR cannot move out of indexed content - | ^^^^^^ cannot move out of borrowed content + | ^^^^^^ + | | + | cannot move out of borrowed content + | help: consider using a reference instead: `&f.v[0]` error: aborting due to previous error diff --git a/src/test/ui/issue-40402-ref-hints/issue-40402-2.nll.stderr b/src/test/ui/issue-40402-ref-hints/issue-40402-2.nll.stderr index 0b907c5acf1dc..cd75be24589df 100644 --- a/src/test/ui/issue-40402-ref-hints/issue-40402-2.nll.stderr +++ b/src/test/ui/issue-40402-ref-hints/issue-40402-2.nll.stderr @@ -1,15 +1,14 @@ error[E0507]: cannot move out of borrowed content - --> $DIR/issue-40402-2.rs:15:10 + --> $DIR/issue-40402-2.rs:15:18 | LL | let (a, b) = x[0]; //~ ERROR cannot move out of indexed content - | ^ cannot move out of borrowed content + | - - ^^^^ + | | | | + | | | cannot move out of borrowed content + | | | help: consider using a reference instead: `&x[0]` + | | move occurs because b has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because a has type `std::string::String`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/issue-40402-2.rs:15:13 - | -LL | let (a, b) = x[0]; //~ ERROR cannot move out of indexed content - | ^ cannot move out of borrowed content - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/moves-based-on-type-block-bad.nll.stderr b/src/test/ui/moves-based-on-type-block-bad.nll.stderr index 942d9816c4ee3..94f2074b45d4c 100644 --- a/src/test/ui/moves-based-on-type-block-bad.nll.stderr +++ b/src/test/ui/moves-based-on-type-block-bad.nll.stderr @@ -1,8 +1,14 @@ error[E0507]: cannot move out of borrowed content - --> $DIR/moves-based-on-type-block-bad.rs:37:28 + --> $DIR/moves-based-on-type-block-bad.rs:34:19 | +LL | match hellothere.x { //~ ERROR cannot move out + | ^^^^^^^^^^^^ + | | + | cannot move out of borrowed content + | help: consider using a reference instead: `&hellothere.x` +... LL | box E::Bar(x) => println!("{}", x.to_string()), - | ^ cannot move out of borrowed content + | - move occurs because x has type `std::boxed::Box`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/nll/move-errors.rs b/src/test/ui/nll/move-errors.rs new file mode 100644 index 0000000000000..6445f166b5719 --- /dev/null +++ b/src/test/ui/nll/move-errors.rs @@ -0,0 +1,130 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused)] +#![feature(nll)] + +struct A(String); +struct C(D); + +fn suggest_remove_deref() { + let a = &A("".to_string()); + let b = *a; + //~^ ERROR +} + +fn suggest_borrow() { + let a = [A("".to_string())]; + let b = a[0]; + //~^ ERROR +} + +fn suggest_borrow2() { + let mut a = A("".to_string()); + let r = &&mut a; + let s = **r; + //~^ ERROR +} + +fn suggest_borrow3() { + use std::rc::Rc; + let mut a = A("".to_string()); + let r = Rc::new(a); + let s = *r; + //~^ ERROR +} + +fn suggest_borrow4() { + let a = [A("".to_string())][0]; + //~^ ERROR +} + +fn suggest_borrow5() { + let a = &A("".to_string()); + let A(s) = *a; + //~^ ERROR +} + +fn suggest_ref() { + let c = C(D(String::new())); + let C(D(s)) = c; + //~^ ERROR +} + +fn suggest_nothing() { + let a = &A("".to_string()); + let b; + b = *a; + //~^ ERROR +} + +enum B { + V(String), + U(D), +} + +struct D(String); + +impl Drop for D { + fn drop(&mut self) {} +} + +struct F(String, String); + +impl Drop for F { + fn drop(&mut self) {} +} + +fn probably_suggest_borrow() { + let x = [B::V(String::new())]; + match x[0] { + //~^ ERROR + B::U(d) => (), + B::V(s) => (), + } +} + +fn have_to_suggest_ref() { + let x = B::V(String::new()); + match x { + //~^ ERROR + B::V(s) => drop(s), + B::U(D(s)) => (), + }; +} + +fn two_separate_errors() { + let x = (D(String::new()), &String::new()); + match x { + //~^ ERROR + //~^^ ERROR + (D(s), &t) => (), + _ => (), + } +} + +fn have_to_suggest_double_ref() { + let x = F(String::new(), String::new()); + match x { + //~^ ERROR + F(s, mut t) => (), + _ => (), + } +} + +fn double_binding(x: &Result) { + match *x { + //~^ ERROR + Ok(s) | Err(s) => (), + } +} + +fn main() { +} diff --git a/src/test/ui/nll/move-errors.stderr b/src/test/ui/nll/move-errors.stderr new file mode 100644 index 0000000000000..3f2c651ae3a6a --- /dev/null +++ b/src/test/ui/nll/move-errors.stderr @@ -0,0 +1,140 @@ +error[E0507]: cannot move out of borrowed content + --> $DIR/move-errors.rs:19:13 + | +LL | let b = *a; + | ^^ + | | + | cannot move out of borrowed content + | help: consider removing this dereference operator: `a` + +error[E0508]: cannot move out of type `[A; 1]`, a non-copy array + --> $DIR/move-errors.rs:25:13 + | +LL | let b = a[0]; + | ^^^^ + | | + | cannot move out of here + | help: consider using a reference instead: `&a[0]` + +error[E0507]: cannot move out of borrowed content + --> $DIR/move-errors.rs:32:13 + | +LL | let s = **r; + | ^^^ + | | + | cannot move out of borrowed content + | help: consider using a reference instead: `&**r` + +error[E0507]: cannot move out of borrowed content + --> $DIR/move-errors.rs:40:13 + | +LL | let s = *r; + | ^^ + | | + | cannot move out of borrowed content + | help: consider using a reference instead: `&*r` + +error[E0508]: cannot move out of type `[A; 1]`, a non-copy array + --> $DIR/move-errors.rs:45:13 + | +LL | let a = [A("".to_string())][0]; + | ^^^^^^^^^^^^^^^^^^^^^^ + | | + | cannot move out of here + | help: consider using a reference instead: `&[A("".to_string())][0]` + +error[E0507]: cannot move out of borrowed content + --> $DIR/move-errors.rs:51:16 + | +LL | let A(s) = *a; + | - ^^ + | | | + | | cannot move out of borrowed content + | | help: consider removing this dereference operator: `a` + | move occurs because s has type `std::string::String`, which does not implement the `Copy` trait + +error[E0509]: cannot move out of type `D`, which implements the `Drop` trait + --> $DIR/move-errors.rs:57:19 + | +LL | let C(D(s)) = c; + | - ^ cannot move out of here + | | + | help: to prevent move, use ref or ref mut: `ref s` + +error[E0507]: cannot move out of borrowed content + --> $DIR/move-errors.rs:64:9 + | +LL | b = *a; + | ^^ cannot move out of borrowed content + +error[E0508]: cannot move out of type `[B; 1]`, a non-copy array + --> $DIR/move-errors.rs:87:11 + | +LL | match x[0] { + | ^^^^ + | | + | cannot move out of here + | help: consider using a reference instead: `&x[0]` +LL | //~^ ERROR +LL | B::U(d) => (), + | - move occurs because d has type `D`, which does not implement the `Copy` trait +LL | B::V(s) => (), + | - move occurs because s has type `std::string::String`, which does not implement the `Copy` trait + +error[E0509]: cannot move out of type `D`, which implements the `Drop` trait + --> $DIR/move-errors.rs:96:11 + | +LL | match x { + | ^ cannot move out of here +... +LL | B::U(D(s)) => (), + | - help: to prevent move, use ref or ref mut: `ref s` + +error[E0509]: cannot move out of type `D`, which implements the `Drop` trait + --> $DIR/move-errors.rs:105:11 + | +LL | match x { + | ^ cannot move out of here +... +LL | (D(s), &t) => (), + | - help: to prevent move, use ref or ref mut: `ref s` + +error[E0507]: cannot move out of borrowed content + --> $DIR/move-errors.rs:105:11 + | +LL | match x { + | ^ cannot move out of borrowed content +... +LL | (D(s), &t) => (), + | - help: to prevent move, use ref or ref mut: `ref t` + +error[E0509]: cannot move out of type `F`, which implements the `Drop` trait + --> $DIR/move-errors.rs:115:11 + | +LL | match x { + | ^ cannot move out of here +help: to prevent move, use ref or ref mut + | +LL | F(ref s, mut t) => (), + | ^^^^^ +help: to prevent move, use ref or ref mut + | +LL | F(s, ref mut t) => (), + | ^^^^^^^^^ + +error[E0507]: cannot move out of borrowed content + --> $DIR/move-errors.rs:123:11 + | +LL | match *x { + | ^^ + | | + | cannot move out of borrowed content + | help: consider removing this dereference operator: `x` +LL | //~^ ERROR +LL | Ok(s) | Err(s) => (), + | - move occurs because s has type `std::string::String`, which does not implement the `Copy` trait + +error: aborting due to 14 previous errors + +Some errors occurred: E0507, E0508, E0509. +For more information about an error, try `rustc --explain E0507`.