ide_diagnostics/handlers/
moved_out_of_ref.rs

1use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
2use hir::HirDisplay;
3
4// Diagnostic: moved-out-of-ref
5//
6// This diagnostic is triggered on moving non copy things out of references.
7pub(crate) fn moved_out_of_ref(
8    ctx: &DiagnosticsContext<'_>,
9    d: &hir::MovedOutOfRef<'_>,
10) -> Diagnostic {
11    Diagnostic::new_with_syntax_node_ptr(
12        ctx,
13        DiagnosticCode::RustcHardError("E0507"),
14        format!("cannot move `{}` out of reference", d.ty.display(ctx.sema.db, ctx.display_target)),
15        d.span,
16    )
17    // spans are broken, and I'm not sure how precise we can detect copy types
18}
19
20#[cfg(test)]
21mod tests {
22    use crate::tests::check_diagnostics;
23
24    #[test]
25    fn operand_field_span_respected() {
26        check_diagnostics(
27            r#"
28struct NotCopy;
29struct S {
30    field: NotCopy,
31}
32
33fn f(s: &S) -> S {
34    S { field: s.field }
35             //^^^^^^^ error: cannot move `NotCopy` out of reference
36}
37            "#,
38        );
39    }
40
41    #[test]
42    fn move_by_explicit_deref() {
43        check_diagnostics(
44            r#"
45struct X;
46fn main() {
47    let a = &X;
48    let b = *a;
49      //^ error: cannot move `X` out of reference
50    _ = b;
51}
52"#,
53        );
54    }
55
56    #[test]
57    fn move_out_of_field() {
58        check_diagnostics(
59            r#"
60//- minicore: copy
61struct X;
62struct Y(X, i32);
63fn main() {
64    let a = &Y(X, 5);
65    let b = a.0;
66      //^ error: cannot move `X` out of reference
67    let y = a.1;
68    _ = (b, y);
69}
70"#,
71        );
72    }
73
74    #[test]
75    fn move_out_of_static() {
76        check_diagnostics(
77            r#"
78//- minicore: copy
79struct X;
80fn main() {
81    static S: X = X;
82    let _s = S;
83      //^^ error: cannot move `X` out of reference
84}
85"#,
86        );
87    }
88
89    #[test]
90    fn generic_types() {
91        check_diagnostics(
92            r#"
93//- minicore: derive, copy
94
95#[derive(Copy)]
96struct X<T>(T);
97struct Y;
98
99fn consume<T>(_: X<T>) {
100
101}
102
103fn main() {
104    let a = &X(Y);
105    consume(*a);
106          //^^ error: cannot move `X<Y>` out of reference
107    let a = &X(5);
108    consume(*a);
109}
110"#,
111        );
112    }
113
114    #[test]
115    fn no_false_positive_simple() {
116        check_diagnostics(
117            r#"
118//- minicore: copy
119fn f(_: i32) {}
120fn main() {
121    let x = &2;
122    f(*x);
123}
124"#,
125        );
126    }
127
128    #[test]
129    fn no_false_positive_unknown_type() {
130        check_diagnostics(
131            r#"
132//- minicore: derive, copy
133fn f(x: &Unknown) -> Unknown {
134    *x
135}
136
137#[derive(Copy)]
138struct X<T>(T);
139
140struct Y<T>(T);
141
142fn g(x: &X<Unknown>) -> X<Unknown> {
143    *x
144}
145
146fn h(x: &Y<Unknown>) -> Y<Unknown> {
147    // FIXME: we should show error for this, as `Y` is not copy
148    // regardless of its generic parameter.
149    *x
150}
151
152"#,
153        );
154    }
155
156    #[test]
157    fn no_false_positive_dyn_fn() {
158        check_diagnostics(
159            r#"
160//- minicore: copy, fn, dispatch_from_dyn
161fn f(x: &mut &mut dyn Fn()) {
162    x();
163}
164
165struct X<'a> {
166    field: &'a mut dyn Fn(),
167}
168
169fn g(x: &mut X<'_>) {
170    (x.field)();
171}
172"#,
173        );
174    }
175
176    #[test]
177    fn no_false_positive_match_and_closure_capture() {
178        check_diagnostics(
179            r#"
180//- minicore: copy, fn
181enum X {
182    Foo(u16),
183    Bar,
184}
185
186fn main() {
187    let x = &X::Bar;
188    let _c = || match *x {
189        X::Foo(t) => t,
190        _ => 5,
191    };
192}
193            "#,
194        );
195    }
196
197    #[test]
198    fn regression_15787() {
199        check_diagnostics(
200            r#"
201//- minicore: coerce_unsized, slice, copy
202fn foo(mut slice: &[u32]) -> usize {
203    slice = match slice {
204        [0, rest @ ..] | rest => rest,
205    };
206    slice.len()
207}
208"#,
209        );
210    }
211
212    #[test]
213    fn regression_16564() {
214        check_diagnostics(
215            r#"
216//- minicore: copy
217fn test() {
218    let _x = (&(&mut (),)).0 as *const ();
219}
220            "#,
221        )
222    }
223
224    #[test]
225    fn regression_18201() {
226        check_diagnostics(
227            r#"
228//- minicore: copy
229struct NotCopy;
230struct S(NotCopy);
231impl S {
232    fn f(&mut self) {
233        || {
234            if let ref mut _cb = self.0 {
235            }
236        };
237    }
238}
239"#,
240        )
241    }
242
243    #[test]
244    fn regression_20155() {
245        check_diagnostics(
246            r#"
247//- minicore: copy, option
248struct Box(i32);
249fn test() {
250    let b = Some(Box(0));
251    || {
252        if let Some(b) = b {
253            let _move = b;
254        }
255    };
256}
257"#,
258        )
259    }
260}