]> git.lizzy.rs Git - rust.git/commitdiff
Suggest match ergonomics, not `ref`/`ref mut`
authorashtneoi <ashtneoi@gmail.com>
Tue, 7 Aug 2018 08:02:39 +0000 (01:02 -0700)
committerashtneoi <ashtneoi@gmail.com>
Wed, 15 Aug 2018 22:14:21 +0000 (15:14 -0700)
src/librustc/mir/mod.rs
src/librustc_borrowck/borrowck/mod.rs
src/librustc_mir/borrow_check/move_errors.rs
src/librustc_mir/borrow_check/mutability_errors.rs
src/librustc_mir/build/matches/mod.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/lib.rs
src/librustc_mir/util/mod.rs
src/test/ui/suggestions/dont-suggest-ref.rs [new file with mode: 0644]
src/test/ui/suggestions/dont-suggest-ref.stderr [new file with mode: 0644]

index 6b9cd2956216f80716b0660f3f9fdab28f10134c..8ceff303774b596a265af6a1dfac05a09589914c 100644 (file)
@@ -523,6 +523,8 @@ pub struct VarBindingForm<'tcx> {
     /// (b) it gives a way to separate this case from the remaining cases
     ///     for diagnostics.
     pub opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
+    /// Span of the pattern in which this variable was bound.
+    pub pat_span: Span,
 }
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
@@ -540,7 +542,8 @@ pub enum BindingForm<'tcx> {
 impl_stable_hash_for!(struct self::VarBindingForm<'tcx> {
     binding_mode,
     opt_ty_info,
-    opt_match_place
+    opt_match_place,
+    pat_span
 });
 
 mod binding_form_impl {
@@ -710,6 +713,7 @@ pub fn can_be_made_mutable(&self) -> bool {
                 binding_mode: ty::BindingMode::BindByValue(_),
                 opt_ty_info: _,
                 opt_match_place: _,
+                pat_span: _,
             }))) => true,
 
             // FIXME: might be able to thread the distinction between
@@ -729,6 +733,7 @@ pub fn is_nonref_binding(&self) -> bool {
                 binding_mode: ty::BindingMode::BindByValue(_),
                 opt_ty_info: _,
                 opt_match_place: _,
+                pat_span: _,
             }))) => true,
 
             Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf)) => true,
index 098149c36ce435f74f6d253a14914552650c6fcd..5b08400eb112d05ddc56fe37aca367d0eb61391c 100644 (file)
@@ -1235,7 +1235,7 @@ fn note_immutability_blame(&self,
                     ty::BindByReference(..) => {
                         let let_span = self.tcx.hir.span(node_id);
                         let suggestion = suggest_ref_mut(self.tcx, let_span);
-                        if let Some((let_span, replace_str)) = suggestion {
+                        if let Some(replace_str) = suggestion {
                             db.span_suggestion(
                                 let_span,
                                 "use a mutable reference instead",
index 5bbedbcfeee4e5efd9390b06f0c43efa21218284..b89a8fa88b3e6c052534f5a3c40ab2f8bf4602b8 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::hir;
+use core::unicode::property::Pattern_White_Space;
 use rustc::mir::*;
 use rustc::ty;
 use rustc_errors::DiagnosticBuilder;
 // let (&x, &y) = (&String::new(), &String::new());
 #[derive(Debug)]
 enum GroupedMoveError<'tcx> {
-    // Match place can't be moved from
+    // Place expression can't be moved from,
     // e.g. match x[0] { s => (), } where x: &[String]
-    MovesFromMatchPlace {
+    MovesFromPlace {
         original_path: Place<'tcx>,
         span: Span,
         move_from: Place<'tcx>,
         kind: IllegalMoveOriginKind<'tcx>,
         binds_to: Vec<Local>,
     },
-    // Part of a pattern can't be moved from,
+    // Part of a value expression can't be moved from,
     // e.g. match &String::new() { &x => (), }
-    MovesFromPattern {
+    MovesFromValue {
         original_path: Place<'tcx>,
         span: Span,
         move_from: MovePathIndex,
@@ -55,6 +55,8 @@ enum GroupedMoveError<'tcx> {
         binds_to: Vec<Local>,
     },
     // Everything that isn't from pattern matching.
+    // FIXME(ashtneoi): I think this is only for moves into temporaries, as
+    // when returning a value. Clarification needed.
     OtherIllegalMove {
         original_path: Place<'tcx>,
         span: Span,
@@ -119,6 +121,7 @@ fn append_to_grouped_errors(
                         opt_match_place: Some((ref opt_match_place, match_span)),
                         binding_mode: _,
                         opt_ty_info: _,
+                        pat_span: _,
                     }))) = local_decl.is_user_variable
                     {
                         self.append_binding_error(
@@ -166,7 +169,7 @@ fn append_binding_error(
             // Error with the match place
             LookupResult::Parent(_) => {
                 for ge in &mut *grouped_errors {
-                    if let GroupedMoveError::MovesFromMatchPlace { span, binds_to, .. } = ge {
+                    if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge {
                         if match_span == *span {
                             debug!("appending local({:?}) to list", bind_to);
                             if !binds_to.is_empty() {
@@ -184,7 +187,7 @@ fn append_binding_error(
                 } else {
                     (vec![bind_to], match_span)
                 };
-                grouped_errors.push(GroupedMoveError::MovesFromMatchPlace {
+                grouped_errors.push(GroupedMoveError::MovesFromPlace {
                     span,
                     move_from: match_place.clone(),
                     original_path,
@@ -200,7 +203,7 @@ fn append_binding_error(
                     _ => unreachable!("Probably not unreachable..."),
                 };
                 for ge in &mut *grouped_errors {
-                    if let GroupedMoveError::MovesFromPattern {
+                    if let GroupedMoveError::MovesFromValue {
                         span,
                         move_from: other_mpi,
                         binds_to,
@@ -215,7 +218,7 @@ fn append_binding_error(
                     }
                 }
                 debug!("found a new move error location");
-                grouped_errors.push(GroupedMoveError::MovesFromPattern {
+                grouped_errors.push(GroupedMoveError::MovesFromValue {
                     span: match_span,
                     move_from: mpi,
                     original_path,
@@ -230,13 +233,13 @@ fn report(&mut self, error: GroupedMoveError<'tcx>) {
         let (mut err, err_span) = {
             let (span, original_path, kind): (Span, &Place<'tcx>, &IllegalMoveOriginKind) =
                 match error {
-                    GroupedMoveError::MovesFromMatchPlace {
+                    GroupedMoveError::MovesFromPlace {
                         span,
                         ref original_path,
                         ref kind,
                         ..
                     } |
-                    GroupedMoveError::MovesFromPattern { span, ref original_path, ref kind, .. } |
+                    GroupedMoveError::MovesFromValue { span, ref original_path, ref kind, .. } |
                     GroupedMoveError::OtherIllegalMove { span, ref original_path, ref kind } => {
                         (span, original_path, kind)
                     },
@@ -331,111 +334,119 @@ fn add_move_hints(
         err: &mut DiagnosticBuilder<'a>,
         span: Span,
     ) {
+        let snippet = self.tcx.sess.codemap().span_to_snippet(span).unwrap();
         match error {
-            GroupedMoveError::MovesFromMatchPlace {
+            GroupedMoveError::MovesFromPlace {
                 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) =>
-                        {
+                let mut suggest_change_head_expr = false;
+                match move_from {
+                    Place::Projection(box PlaceProjection {
+                        elem: ProjectionElem::Deref,
+                        ..
+                    }) => {
+                        // This is false for (e.g.) index expressions `a[b]`,
+                        // which roughly desugar to `*Index::index(&a, b)` or
+                        // `*IndexMut::index_mut(&mut a, b)`.
+                        if snippet.starts_with('*') {
                             err.span_suggestion(
                                 span,
                                 "consider removing this dereference operator",
                                 (&snippet[1..]).to_owned(),
                             );
-                        }
-                        _ => {
-                            err.span_suggestion(
-                                span,
-                                "consider using a reference instead",
-                                format!("&{}", snippet),
-                            );
+                            suggest_change_head_expr = true;
                         }
                     }
-
-                    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
-                            ),
+                    _ => {
+                        err.span_suggestion(
+                            span,
+                            "consider using a reference instead",
+                            format!("&{}", snippet),
                         );
+                        suggest_change_head_expr = true;
                     }
                 }
+                binds_to.sort();
+                binds_to.dedup();
+                if !suggest_change_head_expr {
+                    self.add_move_error_suggestions(err, &binds_to);
+                }
+                self.add_move_error_labels(err, &binds_to);
             }
-            GroupedMoveError::MovesFromPattern { mut binds_to, .. } => {
-                // Suggest ref, since there might be a move in
-                // another match arm
+            GroupedMoveError::MovesFromValue { mut binds_to, .. } => {
                 binds_to.sort();
                 binds_to.dedup();
-                let mut multipart_suggestion = Vec::with_capacity(binds_to.len());
-                for (j, local) in binds_to.into_iter().enumerate() {
-                    let bind_to = &self.mir.local_decls[local];
-                    let binding_span = bind_to.source_info.span;
+                self.add_move_error_suggestions(err, &binds_to);
+                self.add_move_error_labels(err, &binds_to);
+            }
+            // No binding. Nothing to suggest.
+            GroupedMoveError::OtherIllegalMove { .. } => (),
+        }
+    }
 
-                    // Suggest ref mut when the user has already written mut.
-                    let ref_kind = match bind_to.mutability {
-                        Mutability::Not => "ref",
-                        Mutability::Mut => "ref mut",
-                    };
-                    if j == 0 {
-                        err.span_label(binding_span, format!("data moved here"));
+    fn add_move_error_suggestions(
+        &self,
+        err: &mut DiagnosticBuilder<'a>,
+        binds_to: &[Local],
+    ) {
+        for local in binds_to {
+            let bind_to = &self.mir.local_decls[*local];
+            if let Some(
+                ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
+                    pat_span,
+                    ..
+                }))
+            ) = bind_to.is_user_variable {
+                let pat_snippet = self
+                    .tcx.sess.codemap()
+                    .span_to_snippet(pat_span)
+                    .unwrap();
+                if pat_snippet.starts_with('&') {
+                    let pat_snippet = &pat_snippet[1..];
+                    let suggestion;
+                    if pat_snippet.starts_with("mut")
+                        && pat_snippet["mut".len()..].starts_with(Pattern_White_Space)
+                    {
+                        suggestion = pat_snippet["mut".len()..].trim_left();
                     } else {
-                        err.span_label(binding_span, format!("... and here"));
-                    }
-                    match bind_to.name {
-                        Some(name) => {
-                            multipart_suggestion.push((binding_span,
-                                                       format!("{} {}", ref_kind, name)));
-                        }
-                        None => {
-                            err.span_label(
-                                span,
-                                format!("Local {:?} is not suitable for ref", bind_to),
-                            );
-                        }
+                        suggestion = pat_snippet;
                     }
+                    err.span_suggestion(
+                        pat_span,
+                        "consider removing this borrow operator",
+                        suggestion.to_owned(),
+                    );
                 }
-                err.multipart_suggestion("to prevent move, use ref or ref mut",
-                                         multipart_suggestion);
             }
-            // 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,
-        };
+    fn add_move_error_labels(
+        &self,
+        err: &mut DiagnosticBuilder<'a>,
+        binds_to: &[Local],
+    ) {
+        for (j, local) in binds_to.into_iter().enumerate() {
+            let bind_to = &self.mir.local_decls[*local];
+            let binding_span = bind_to.source_info.span;
 
-        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)
+            if j == 0 {
+                err.span_label(binding_span, format!("data moved here"));
+            } else {
+                err.span_label(binding_span, format!("... and here"));
             }
-            Place::Promoted(_) => true,
-            Place::Static(ref st) => is_shared_ref(st.ty),
-            Place::Projection(ref proj) => match proj.elem {
-                ProjectionElem::Field(_, ty) => is_shared_ref(ty),
-                _ => false,
-            },
+
+            err.span_note(
+                binding_span,
+                &format!(
+                    "move occurs because {} has type `{}`, \
+                        which does not implement the `Copy` trait",
+                    bind_to.name.unwrap(),
+                    bind_to.ty
+                ),
+            );
         }
     }
 }
index 283cccd51174a1bbe81e32f8c8def62fb5f3805f..f11135fc026f53acd940600a43d226a733416c30 100644 (file)
@@ -329,7 +329,11 @@ pub(super) fn report_mutability_error(
                     ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm {
                         binding_mode: ty::BindingMode::BindByReference(_),
                         ..
-                    })) => suggest_ref_mut(self.tcx, local_decl.source_info.span),
+                    })) => {
+                        let pattern_span = local_decl.source_info.span;
+                        suggest_ref_mut(self.tcx, pattern_span)
+                            .map(|replacement| (pattern_span, replacement))
+                    }
 
                     //
                     ClearCrossCrate::Set(mir::BindingForm::RefForGuard) => unreachable!(),
index ebf9631831c88d76ccd4e063f40551a3ecccb5ee..b317bb7cff0e3c9a6e0b720f0dd0b2a63e1123f9 100644 (file)
@@ -357,7 +357,8 @@ pub fn declare_bindings(&mut self,
             let visibility_scope = visibility_scope.unwrap();
             this.declare_binding(source_info, visibility_scope, mutability, name, mode,
                                  num_patterns, var, ty, has_guard,
-                                 opt_match_place.map(|(x, y)| (x.cloned(), y)));
+                                 opt_match_place.map(|(x, y)| (x.cloned(), y)),
+                                 patterns[0].span);
         });
         visibility_scope
     }
@@ -1182,7 +1183,8 @@ fn declare_binding(&mut self,
                        var_id: NodeId,
                        var_ty: Ty<'tcx>,
                        has_guard: ArmHasGuard,
-                       opt_match_place: Option<(Option<Place<'tcx>>, Span)>)
+                       opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
+                       pat_span: Span)
     {
         debug!("declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \
                 visibility_scope={:?}, source_info={:?})",
@@ -1208,6 +1210,7 @@ fn declare_binding(&mut self,
                 // Instead, just abandon providing diagnostic info.
                 opt_ty_info: None,
                 opt_match_place,
+                pat_span,
             }))),
         };
         let for_arm_body = self.local_decls.push(local.clone());
index 054bd69c361b92115eb6c60dd32e67ec3cccbcd4..c0c431804d8c1ea52fcf1716084e06c761586e55 100644 (file)
@@ -763,6 +763,7 @@ fn args_and_body(&mut self,
                                     binding_mode,
                                     opt_ty_info,
                                     opt_match_place: Some((Some(place.clone()), span)),
+                                    pat_span: span,
                                 })))
                             };
                         self.var_indices.insert(var, LocalsForNode::One(local));
index 42682c34407cab08c713731ac8fc89d4dadbc097..bda80ff562c75ede8ef6cbacc79b5982d36de066 100644 (file)
@@ -35,6 +35,7 @@
 #![feature(try_trait)]
 #![feature(unicode_internals)]
 #![feature(step_trait)]
+#![feature(slice_concat_ext)]
 
 #![recursion_limit="256"]
 
index 78e9dd23e83ae718387a9fa5bd1e47e2a50028e3..fe6fefe89fd66b59cab4e0e5b4887eb165fbc1ce 100644 (file)
 /// If possible, suggest replacing `ref` with `ref mut`.
 pub fn suggest_ref_mut<'cx, 'gcx, 'tcx>(
     tcx: ty::TyCtxt<'cx, 'gcx, 'tcx>,
-    pattern_span: Span,
-) -> Option<(Span, String)> {
-    let hi_src = tcx.sess.codemap().span_to_snippet(pattern_span).unwrap();
+    binding_span: Span,
+) -> Option<(String)> {
+    let hi_src = tcx.sess.codemap().span_to_snippet(binding_span).unwrap();
     if hi_src.starts_with("ref")
         && hi_src["ref".len()..].starts_with(Pattern_White_Space)
     {
         let replacement = format!("ref mut{}", &hi_src["ref".len()..]);
-        Some((pattern_span, replacement))
+        Some(replacement)
     } else {
         None
     }
diff --git a/src/test/ui/suggestions/dont-suggest-ref.rs b/src/test/ui/suggestions/dont-suggest-ref.rs
new file mode 100644 (file)
index 0000000..cdf5503
--- /dev/null
@@ -0,0 +1,267 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(nll)]
+
+enum Either {
+    One(X),
+    Two(X),
+}
+
+struct X(Y);
+
+struct Y;
+
+pub fn main() {
+    let e = Either::One(X(Y));
+    let mut em = Either::One(X(Y));
+
+    let r = &e;
+    let rm = &mut Either::One(X(Y));
+
+    let x = X(Y);
+    let mut xm = X(Y);
+
+    let s = &x;
+    let sm = &mut X(Y);
+
+    // --------
+
+    let X(_t) = *s;
+    //~^ ERROR cannot move
+    //~| HELP consider removing this dereference operator
+    //~| SUGGESTION s
+    if let Either::One(_t) = *r { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing this dereference operator
+    //~| SUGGESTION r
+    while let Either::One(_t) = *r { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing this dereference operator
+    //~| SUGGESTION r
+    match *r {
+        //~^ ERROR cannot move
+        //~| HELP consider removing this dereference operator
+        //~| SUGGESTION r
+        Either::One(_t)
+        | Either::Two(_t) => (),
+    }
+    match *r {
+        //~^ ERROR cannot move
+        //~| HELP consider removing this dereference operator
+        //~| SUGGESTION r
+        // (invalid but acceptable)
+        Either::One(_t) => (),
+        Either::Two(ref _t) => (),
+    }
+
+    let X(_t) = *sm;
+    //~^ ERROR cannot move
+    //~| HELP consider removing this dereference operator
+    //~| SUGGESTION sm
+    if let Either::One(_t) = *rm { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing this dereference operator
+    //~| SUGGESTION rm
+    while let Either::One(_t) = *rm { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing this dereference operator
+    //~| SUGGESTION rm
+    match *rm {
+        //~^ ERROR cannot move
+        //~| HELP consider removing this dereference operator
+        //~| SUGGESTION rm
+        Either::One(_t)
+        | Either::Two(_t) => (),
+    }
+    match *rm {
+        //~^ ERROR cannot move
+        //~| HELP consider removing this dereference operator
+        //~| SUGGESTION rm
+        // (invalid but acceptable)
+        Either::One(_t) => (),
+        Either::Two(ref _t) => (),
+    }
+    match *rm {
+        //~^ ERROR cannot move
+        //~| HELP consider removing this dereference operator
+        //~| SUGGESTION rm
+        // (invalid but acceptable)
+        Either::One(_t) => (),
+        Either::Two(ref mut _t) => (),
+    }
+
+    // --------
+
+    let &X(_t) = s;
+    //~^ ERROR cannot move
+    //~| HELP consider removing this borrow operator
+    //~| SUGGESTION X(_t)
+    if let &Either::One(_t) = r { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing this borrow operator
+    //~| SUGGESTION Either::One(_t)
+    while let &Either::One(_t) = r { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing this borrow operator
+    //~| SUGGESTION Either::One(_t)
+    match r {
+        //~^ ERROR cannot move
+        &Either::One(_t)
+        //~^ HELP consider removing this borrow operator
+        //~| SUGGESTION Either::One(_t)
+        | &Either::Two(_t) => (),
+        // TODO: would really like a suggestion here too
+    }
+    match r {
+        //~^ ERROR cannot move
+        &Either::One(_t) => (),
+        //~^ HELP consider removing this borrow operator
+        //~| SUGGESTION Either::One(_t)
+        &Either::Two(ref _t) => (),
+    }
+    match r {
+        //~^ ERROR cannot move
+        &Either::One(_t) => (),
+        //~^ HELP consider removing this borrow operator
+        //~| SUGGESTION Either::One(_t)
+        Either::Two(_t) => (),
+    }
+    fn f1(&X(_t): &X) { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing this borrow operator
+    //~| SUGGESTION X(_t)
+
+    let &mut X(_t) = sm;
+    //~^ ERROR cannot move
+    //~| HELP consider removing this borrow operator
+    //~| SUGGESTION X(_t)
+    if let &mut Either::One(_t) = rm { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing this borrow operator
+    //~| SUGGESTION Either::One(_t)
+    while let &mut Either::One(_t) = rm { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing this borrow operator
+    //~| SUGGESTION Either::One(_t)
+    match rm {
+        //~^ ERROR cannot move
+        &mut Either::One(_t) => (),
+        //~^ HELP consider removing this borrow operator
+        //~| SUGGESTION Either::One(_t)
+        &mut Either::Two(_t) => (),
+        //~^ HELP consider removing this borrow operator
+        //~| SUGGESTION Either::Two(_t)
+    }
+    match rm {
+        //~^ ERROR cannot move
+        &mut Either::One(_t) => (),
+        //~^ HELP consider removing this borrow operator
+        //~| SUGGESTION Either::One(_t)
+        &mut Either::Two(ref _t) => (),
+    }
+    match rm {
+        //~^ ERROR cannot move
+        &mut Either::One(_t) => (),
+        //~^ HELP consider removing this borrow operator
+        //~| SUGGESTION Either::One(_t)
+        &mut Either::Two(ref mut _t) => (),
+    }
+    match rm {
+        //~^ ERROR cannot move
+        &mut Either::One(_t) => (),
+        //~^ HELP consider removing this borrow operator
+        //~| SUGGESTION Either::One(_t)
+        Either::Two(_t) => (),
+    }
+    fn f2(&mut X(_t): &mut X) { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing this borrow operator
+    //~| SUGGESTION X(_t)
+
+    // --------
+
+    let &X(_t) = &x;
+    //~^ ERROR cannot move
+    //~| HELP consider removing this borrow operator
+    //~| SUGGESTION X(_t)
+    if let &Either::One(_t) = &e { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing this borrow operator
+    //~| SUGGESTION Either::One(_t)
+    while let &Either::One(_t) = &e { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing this borrow operator
+    //~| SUGGESTION Either::One(_t)
+    match &e {
+        //~^ ERROR cannot move
+        &Either::One(_t)
+        //~^ HELP consider removing this borrow operator
+        //~| SUGGESTION Either::One(_t)
+        | &Either::Two(_t) => (),
+        // TODO: would really like a suggestion here too
+    }
+    match &e {
+        //~^ ERROR cannot move
+        &Either::One(_t) => (),
+        //~^ HELP consider removing this borrow operator
+        //~| SUGGESTION Either::One(_t)
+        &Either::Two(ref _t) => (),
+    }
+    match &e {
+        //~^ ERROR cannot move
+        &Either::One(_t) => (),
+        //~^ HELP consider removing this borrow operator
+        //~| SUGGESTION Either::One(_t)
+        Either::Two(_t) => (),
+    }
+
+    let &mut X(_t) = &mut xm;
+    //~^ ERROR cannot move
+    //~| HELP consider removing this borrow operator
+    //~| SUGGESTION X(_t)
+    if let &mut Either::One(_t) = &mut em { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing this borrow operator
+    //~| SUGGESTION Either::One(_t)
+    while let &mut Either::One(_t) = &mut em { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing this borrow operator
+    //~| SUGGESTION Either::One(_t)
+    match &mut em {
+        //~^ ERROR cannot move
+        &mut Either::One(_t)
+        //~^ HELP consider removing this borrow operator
+        //~| SUGGESTION Either::One(_t)
+        | &mut Either::Two(_t) => (),
+        // TODO: would really like a suggestion here too
+    }
+    match &mut em {
+        //~^ ERROR cannot move
+        &mut Either::One(_t) => (),
+        //~^ HELP consider removing this borrow operator
+        //~| SUGGESTION Either::One(_t)
+        &mut Either::Two(ref _t) => (),
+    }
+    match &mut em {
+        //~^ ERROR cannot move
+        &mut Either::One(_t) => (),
+        //~^ HELP consider removing this borrow operator
+        //~| SUGGESTION Either::One(_t)
+        &mut Either::Two(ref mut _t) => (),
+    }
+    match &mut em {
+        //~^ ERROR cannot move
+        &mut Either::One(_t) => (),
+        //~^ HELP consider removing this borrow operator
+        //~| SUGGESTION Either::One(_t)
+        Either::Two(_t) => (),
+    }
+}
diff --git a/src/test/ui/suggestions/dont-suggest-ref.stderr b/src/test/ui/suggestions/dont-suggest-ref.stderr
new file mode 100644 (file)
index 0000000..682ba88
--- /dev/null
@@ -0,0 +1,666 @@
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:37:17
+   |
+LL |     let X(_t) = *s;
+   |           --    ^^
+   |           |     |
+   |           |     cannot move out of borrowed content
+   |           |     help: consider removing this dereference operator: `s`
+   |           data moved here
+   |
+note: move occurs because _t has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:37:11
+   |
+LL |     let X(_t) = *s;
+   |           ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:41:30
+   |
+LL |     if let Either::One(_t) = *r { }
+   |                        --    ^^
+   |                        |     |
+   |                        |     cannot move out of borrowed content
+   |                        |     help: consider removing this dereference operator: `r`
+   |                        data moved here
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:41:24
+   |
+LL |     if let Either::One(_t) = *r { }
+   |                        ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:45:33
+   |
+LL |     while let Either::One(_t) = *r { }
+   |                           --    ^^
+   |                           |     |
+   |                           |     cannot move out of borrowed content
+   |                           |     help: consider removing this dereference operator: `r`
+   |                           data moved here
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:45:27
+   |
+LL |     while let Either::One(_t) = *r { }
+   |                           ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:49:11
+   |
+LL |     match *r {
+   |           ^^
+   |           |
+   |           cannot move out of borrowed content
+   |           help: consider removing this dereference operator: `r`
+...
+LL |         Either::One(_t)
+   |                     -- data moved here
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:53:21
+   |
+LL |         Either::One(_t)
+   |                     ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:56:11
+   |
+LL |     match *r {
+   |           ^^
+   |           |
+   |           cannot move out of borrowed content
+   |           help: consider removing this dereference operator: `r`
+...
+LL |         Either::One(_t) => (),
+   |                     -- data moved here
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:61:21
+   |
+LL |         Either::One(_t) => (),
+   |                     ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:65:17
+   |
+LL |     let X(_t) = *sm;
+   |           --    ^^^
+   |           |     |
+   |           |     cannot move out of borrowed content
+   |           |     help: consider removing this dereference operator: `sm`
+   |           data moved here
+   |
+note: move occurs because _t has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:65:11
+   |
+LL |     let X(_t) = *sm;
+   |           ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:69:30
+   |
+LL |     if let Either::One(_t) = *rm { }
+   |                        --    ^^^
+   |                        |     |
+   |                        |     cannot move out of borrowed content
+   |                        |     help: consider removing this dereference operator: `rm`
+   |                        data moved here
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:69:24
+   |
+LL |     if let Either::One(_t) = *rm { }
+   |                        ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:73:33
+   |
+LL |     while let Either::One(_t) = *rm { }
+   |                           --    ^^^
+   |                           |     |
+   |                           |     cannot move out of borrowed content
+   |                           |     help: consider removing this dereference operator: `rm`
+   |                           data moved here
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:73:27
+   |
+LL |     while let Either::One(_t) = *rm { }
+   |                           ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:77:11
+   |
+LL |     match *rm {
+   |           ^^^
+   |           |
+   |           cannot move out of borrowed content
+   |           help: consider removing this dereference operator: `rm`
+...
+LL |         Either::One(_t)
+   |                     -- data moved here
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:81:21
+   |
+LL |         Either::One(_t)
+   |                     ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:84:11
+   |
+LL |     match *rm {
+   |           ^^^
+   |           |
+   |           cannot move out of borrowed content
+   |           help: consider removing this dereference operator: `rm`
+...
+LL |         Either::One(_t) => (),
+   |                     -- data moved here
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:89:21
+   |
+LL |         Either::One(_t) => (),
+   |                     ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:92:11
+   |
+LL |     match *rm {
+   |           ^^^
+   |           |
+   |           cannot move out of borrowed content
+   |           help: consider removing this dereference operator: `rm`
+...
+LL |         Either::One(_t) => (),
+   |                     -- data moved here
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:97:21
+   |
+LL |         Either::One(_t) => (),
+   |                     ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:103:18
+   |
+LL |     let &X(_t) = s;
+   |         ------   ^ cannot move out of borrowed content
+   |         |  |
+   |         |  data moved here
+   |         help: consider removing this borrow operator: `X(_t)`
+   |
+note: move occurs because _t has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:103:12
+   |
+LL |     let &X(_t) = s;
+   |            ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:107:31
+   |
+LL |     if let &Either::One(_t) = r { }
+   |            ----------------   ^ cannot move out of borrowed content
+   |            |            |
+   |            |            data moved here
+   |            help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:107:25
+   |
+LL |     if let &Either::One(_t) = r { }
+   |                         ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:111:34
+   |
+LL |     while let &Either::One(_t) = r { }
+   |               ----------------   ^ cannot move out of borrowed content
+   |               |            |
+   |               |            data moved here
+   |               help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:111:28
+   |
+LL |     while let &Either::One(_t) = r { }
+   |                            ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:115:11
+   |
+LL |     match r {
+   |           ^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &Either::One(_t)
+   |         ----------------
+   |         |            |
+   |         |            data moved here
+   |         help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:117:22
+   |
+LL |         &Either::One(_t)
+   |                      ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:123:11
+   |
+LL |     match r {
+   |           ^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &Either::One(_t) => (),
+   |         ----------------
+   |         |            |
+   |         |            data moved here
+   |         help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:125:22
+   |
+LL |         &Either::One(_t) => (),
+   |                      ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:130:11
+   |
+LL |     match r {
+   |           ^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &Either::One(_t) => (),
+   |         ----------------
+   |         |            |
+   |         |            data moved here
+   |         help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:132:22
+   |
+LL |         &Either::One(_t) => (),
+   |                      ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:142:22
+   |
+LL |     let &mut X(_t) = sm;
+   |         ----------   ^^ cannot move out of borrowed content
+   |         |      |
+   |         |      data moved here
+   |         help: consider removing this borrow operator: `X(_t)`
+   |
+note: move occurs because _t has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:142:16
+   |
+LL |     let &mut X(_t) = sm;
+   |                ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:146:35
+   |
+LL |     if let &mut Either::One(_t) = rm { }
+   |            --------------------   ^^ cannot move out of borrowed content
+   |            |                |
+   |            |                data moved here
+   |            help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:146:29
+   |
+LL |     if let &mut Either::One(_t) = rm { }
+   |                             ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:150:38
+   |
+LL |     while let &mut Either::One(_t) = rm { }
+   |               --------------------   ^^ cannot move out of borrowed content
+   |               |                |
+   |               |                data moved here
+   |               help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:150:32
+   |
+LL |     while let &mut Either::One(_t) = rm { }
+   |                                ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:154:11
+   |
+LL |     match rm {
+   |           ^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut Either::One(_t) => (),
+   |                          -- data moved here
+...
+LL |         &mut Either::Two(_t) => (),
+   |                          -- ... and here
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:156:26
+   |
+LL |         &mut Either::One(_t) => (),
+   |                          ^^
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:159:26
+   |
+LL |         &mut Either::Two(_t) => (),
+   |                          ^^
+help: consider removing this borrow operator
+   |
+LL |         Either::One(_t) => (),
+   |         ^^^^^^^^^^^^^^^
+help: consider removing this borrow operator
+   |
+LL |         Either::Two(_t) => (),
+   |         ^^^^^^^^^^^^^^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:163:11
+   |
+LL |     match rm {
+   |           ^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut Either::One(_t) => (),
+   |         --------------------
+   |         |                |
+   |         |                data moved here
+   |         help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:165:26
+   |
+LL |         &mut Either::One(_t) => (),
+   |                          ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:170:11
+   |
+LL |     match rm {
+   |           ^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut Either::One(_t) => (),
+   |         --------------------
+   |         |                |
+   |         |                data moved here
+   |         help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:172:26
+   |
+LL |         &mut Either::One(_t) => (),
+   |                          ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:177:11
+   |
+LL |     match rm {
+   |           ^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut Either::One(_t) => (),
+   |         --------------------
+   |         |                |
+   |         |                data moved here
+   |         help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:179:26
+   |
+LL |         &mut Either::One(_t) => (),
+   |                          ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:191:18
+   |
+LL |     let &X(_t) = &x;
+   |         ------   ^^ cannot move out of borrowed content
+   |         |  |
+   |         |  data moved here
+   |         help: consider removing this borrow operator: `X(_t)`
+   |
+note: move occurs because _t has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:191:12
+   |
+LL |     let &X(_t) = &x;
+   |            ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:195:31
+   |
+LL |     if let &Either::One(_t) = &e { }
+   |            ----------------   ^^ cannot move out of borrowed content
+   |            |            |
+   |            |            data moved here
+   |            help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:195:25
+   |
+LL |     if let &Either::One(_t) = &e { }
+   |                         ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:199:34
+   |
+LL |     while let &Either::One(_t) = &e { }
+   |               ----------------   ^^ cannot move out of borrowed content
+   |               |            |
+   |               |            data moved here
+   |               help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:199:28
+   |
+LL |     while let &Either::One(_t) = &e { }
+   |                            ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:203:11
+   |
+LL |     match &e {
+   |           ^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &Either::One(_t)
+   |         ----------------
+   |         |            |
+   |         |            data moved here
+   |         help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:205:22
+   |
+LL |         &Either::One(_t)
+   |                      ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:211:11
+   |
+LL |     match &e {
+   |           ^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &Either::One(_t) => (),
+   |         ----------------
+   |         |            |
+   |         |            data moved here
+   |         help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:213:22
+   |
+LL |         &Either::One(_t) => (),
+   |                      ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:218:11
+   |
+LL |     match &e {
+   |           ^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &Either::One(_t) => (),
+   |         ----------------
+   |         |            |
+   |         |            data moved here
+   |         help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:220:22
+   |
+LL |         &Either::One(_t) => (),
+   |                      ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:226:22
+   |
+LL |     let &mut X(_t) = &mut xm;
+   |         ----------   ^^^^^^^ cannot move out of borrowed content
+   |         |      |
+   |         |      data moved here
+   |         help: consider removing this borrow operator: `X(_t)`
+   |
+note: move occurs because _t has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:226:16
+   |
+LL |     let &mut X(_t) = &mut xm;
+   |                ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:230:35
+   |
+LL |     if let &mut Either::One(_t) = &mut em { }
+   |            --------------------   ^^^^^^^ cannot move out of borrowed content
+   |            |                |
+   |            |                data moved here
+   |            help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:230:29
+   |
+LL |     if let &mut Either::One(_t) = &mut em { }
+   |                             ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:234:38
+   |
+LL |     while let &mut Either::One(_t) = &mut em { }
+   |               --------------------   ^^^^^^^ cannot move out of borrowed content
+   |               |                |
+   |               |                data moved here
+   |               help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:234:32
+   |
+LL |     while let &mut Either::One(_t) = &mut em { }
+   |                                ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:238:11
+   |
+LL |     match &mut em {
+   |           ^^^^^^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut Either::One(_t)
+   |         --------------------
+   |         |                |
+   |         |                data moved here
+   |         help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:240:26
+   |
+LL |         &mut Either::One(_t)
+   |                          ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:246:11
+   |
+LL |     match &mut em {
+   |           ^^^^^^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut Either::One(_t) => (),
+   |         --------------------
+   |         |                |
+   |         |                data moved here
+   |         help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:248:26
+   |
+LL |         &mut Either::One(_t) => (),
+   |                          ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:253:11
+   |
+LL |     match &mut em {
+   |           ^^^^^^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut Either::One(_t) => (),
+   |         --------------------
+   |         |                |
+   |         |                data moved here
+   |         help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:255:26
+   |
+LL |         &mut Either::One(_t) => (),
+   |                          ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:260:11
+   |
+LL |     match &mut em {
+   |           ^^^^^^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut Either::One(_t) => (),
+   |         --------------------
+   |         |                |
+   |         |                data moved here
+   |         help: consider removing this borrow operator: `Either::One(_t)`
+   |
+note: move occurs because _t has type `X`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:262:26
+   |
+LL |         &mut Either::One(_t) => (),
+   |                          ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:137:11
+   |
+LL |     fn f1(&X(_t): &X) { }
+   |           ^^^--^
+   |           |  |
+   |           |  data moved here
+   |           cannot move out of borrowed content
+   |           help: consider removing this borrow operator: `X(_t)`
+   |
+note: move occurs because _t has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:137:14
+   |
+LL |     fn f1(&X(_t): &X) { }
+   |              ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dont-suggest-ref.rs:184:11
+   |
+LL |     fn f2(&mut X(_t): &mut X) { }
+   |           ^^^^^^^--^
+   |           |      |
+   |           |      data moved here
+   |           cannot move out of borrowed content
+   |           help: consider removing this borrow operator: `X(_t)`
+   |
+note: move occurs because _t has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/dont-suggest-ref.rs:184:18
+   |
+LL |     fn f2(&mut X(_t): &mut X) { }
+   |                  ^^
+
+error: aborting due to 39 previous errors
+
+For more information about this error, try `rustc --explain E0507`.