rustc_borrowck/
borrowck_errors.rs

1#![allow(rustc::diagnostic_outside_of_impl)]
2#![allow(rustc::untranslatable_diagnostic)]
3
4use rustc_errors::codes::*;
5use rustc_errors::{Applicability, Diag, DiagCtxtHandle, struct_span_code_err};
6use rustc_hir as hir;
7use rustc_middle::span_bug;
8use rustc_middle::ty::{self, Ty, TyCtxt};
9use rustc_span::Span;
10
11impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> {
12    pub(crate) fn dcx(&self) -> DiagCtxtHandle<'infcx> {
13        self.infcx.dcx()
14    }
15
16    pub(crate) fn cannot_move_when_borrowed(
17        &self,
18        span: Span,
19        borrow_span: Span,
20        place: &str,
21        borrow_place: &str,
22        value_place: &str,
23    ) -> Diag<'infcx> {
24        self.dcx().create_err(crate::session_diagnostics::MoveBorrow {
25            place,
26            span,
27            borrow_place,
28            value_place,
29            borrow_span,
30        })
31    }
32
33    pub(crate) fn cannot_use_when_mutably_borrowed(
34        &self,
35        span: Span,
36        desc: &str,
37        borrow_span: Span,
38        borrow_desc: &str,
39    ) -> Diag<'infcx> {
40        struct_span_code_err!(
41            self.dcx(),
42            span,
43            E0503,
44            "cannot use {} because it was mutably borrowed",
45            desc,
46        )
47        .with_span_label(borrow_span, format!("{borrow_desc} is borrowed here"))
48        .with_span_label(span, format!("use of borrowed {borrow_desc}"))
49    }
50
51    pub(crate) fn cannot_mutably_borrow_multiply(
52        &self,
53        new_loan_span: Span,
54        desc: &str,
55        opt_via: &str,
56        old_loan_span: Span,
57        old_opt_via: &str,
58        old_load_end_span: Option<Span>,
59    ) -> Diag<'infcx> {
60        let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") };
61        let mut err = struct_span_code_err!(
62            self.dcx(),
63            new_loan_span,
64            E0499,
65            "cannot borrow {}{} as mutable more than once at a time",
66            desc,
67            via(opt_via),
68        );
69        if old_loan_span == new_loan_span {
70            // Both borrows are happening in the same place
71            // Meaning the borrow is occurring in a loop
72            err.span_label(
73                new_loan_span,
74                format!(
75                    "{}{} was mutably borrowed here in the previous iteration of the loop{}",
76                    desc,
77                    via(opt_via),
78                    opt_via,
79                ),
80            );
81            if let Some(old_load_end_span) = old_load_end_span {
82                err.span_label(old_load_end_span, "mutable borrow ends here");
83            }
84        } else {
85            err.span_label(
86                old_loan_span,
87                format!("first mutable borrow occurs here{}", via(old_opt_via)),
88            );
89            err.span_label(
90                new_loan_span,
91                format!("second mutable borrow occurs here{}", via(opt_via)),
92            );
93            if let Some(old_load_end_span) = old_load_end_span {
94                err.span_label(old_load_end_span, "first borrow ends here");
95            }
96        }
97        err
98    }
99
100    pub(crate) fn cannot_uniquely_borrow_by_two_closures(
101        &self,
102        new_loan_span: Span,
103        desc: &str,
104        old_loan_span: Span,
105        old_load_end_span: Option<Span>,
106    ) -> Diag<'infcx> {
107        let mut err = struct_span_code_err!(
108            self.dcx(),
109            new_loan_span,
110            E0524,
111            "two closures require unique access to {} at the same time",
112            desc,
113        );
114        if old_loan_span == new_loan_span {
115            err.span_label(
116                old_loan_span,
117                "closures are constructed here in different iterations of loop",
118            );
119        } else {
120            err.span_label(old_loan_span, "first closure is constructed here");
121            err.span_label(new_loan_span, "second closure is constructed here");
122        }
123        if let Some(old_load_end_span) = old_load_end_span {
124            err.span_label(old_load_end_span, "borrow from first closure ends here");
125        }
126        err
127    }
128
129    pub(crate) fn cannot_uniquely_borrow_by_one_closure(
130        &self,
131        new_loan_span: Span,
132        container_name: &str,
133        desc_new: &str,
134        opt_via: &str,
135        old_loan_span: Span,
136        noun_old: &str,
137        old_opt_via: &str,
138        previous_end_span: Option<Span>,
139    ) -> Diag<'infcx> {
140        let mut err = struct_span_code_err!(
141            self.dcx(),
142            new_loan_span,
143            E0500,
144            "closure requires unique access to {} but {} is already borrowed{}",
145            desc_new,
146            noun_old,
147            old_opt_via,
148        );
149        err.span_label(
150            new_loan_span,
151            format!("{container_name} construction occurs here{opt_via}"),
152        );
153        err.span_label(old_loan_span, format!("borrow occurs here{old_opt_via}"));
154        if let Some(previous_end_span) = previous_end_span {
155            err.span_label(previous_end_span, "borrow ends here");
156        }
157        err
158    }
159
160    pub(crate) fn cannot_reborrow_already_uniquely_borrowed(
161        &self,
162        new_loan_span: Span,
163        container_name: &str,
164        desc_new: &str,
165        opt_via: &str,
166        kind_new: &str,
167        old_loan_span: Span,
168        old_opt_via: &str,
169        previous_end_span: Option<Span>,
170        second_borrow_desc: &str,
171    ) -> Diag<'infcx> {
172        let mut err = struct_span_code_err!(
173            self.dcx(),
174            new_loan_span,
175            E0501,
176            "cannot borrow {}{} as {} because previous closure requires unique access",
177            desc_new,
178            opt_via,
179            kind_new,
180        );
181        err.span_label(new_loan_span, format!("{second_borrow_desc}borrow occurs here{opt_via}"));
182        err.span_label(
183            old_loan_span,
184            format!("{container_name} construction occurs here{old_opt_via}"),
185        );
186        if let Some(previous_end_span) = previous_end_span {
187            err.span_label(previous_end_span, "borrow from closure ends here");
188        }
189        err
190    }
191
192    pub(crate) fn cannot_reborrow_already_borrowed(
193        &self,
194        span: Span,
195        desc_new: &str,
196        msg_new: &str,
197        kind_new: &str,
198        old_span: Span,
199        noun_old: &str,
200        kind_old: &str,
201        msg_old: &str,
202        old_load_end_span: Option<Span>,
203    ) -> Diag<'infcx> {
204        let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") };
205        let mut err = struct_span_code_err!(
206            self.dcx(),
207            span,
208            E0502,
209            "cannot borrow {}{} as {} because {} is also borrowed as {}{}",
210            desc_new,
211            via(msg_new),
212            kind_new,
213            noun_old,
214            kind_old,
215            via(msg_old),
216        );
217
218        if msg_new.is_empty() {
219            // If `msg_new` is empty, then this isn't a borrow of a union field.
220            err.span_label(span, format!("{kind_new} borrow occurs here"));
221            err.span_label(old_span, format!("{kind_old} borrow occurs here"));
222        } else {
223            // If `msg_new` isn't empty, then this a borrow of a union field.
224            err.span_label(
225                span,
226                format!(
227                    "{kind_new} borrow of {msg_new} -- which overlaps with {msg_old} -- occurs here",
228                ),
229            );
230            err.span_label(old_span, format!("{} borrow occurs here{}", kind_old, via(msg_old)));
231        }
232
233        if let Some(old_load_end_span) = old_load_end_span {
234            err.span_label(old_load_end_span, format!("{kind_old} borrow ends here"));
235        }
236        err
237    }
238
239    pub(crate) fn cannot_assign_to_borrowed(
240        &self,
241        span: Span,
242        borrow_span: Span,
243        desc: &str,
244    ) -> Diag<'infcx> {
245        struct_span_code_err!(
246            self.dcx(),
247            span,
248            E0506,
249            "cannot assign to {} because it is borrowed",
250            desc,
251        )
252        .with_span_label(borrow_span, format!("{desc} is borrowed here"))
253        .with_span_label(span, format!("{desc} is assigned to here but it was already borrowed"))
254    }
255
256    pub(crate) fn cannot_reassign_immutable(
257        &self,
258        span: Span,
259        desc: &str,
260        is_arg: bool,
261    ) -> Diag<'infcx> {
262        let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" };
263        struct_span_code_err!(self.dcx(), span, E0384, "cannot assign {} {}", msg, desc)
264    }
265
266    pub(crate) fn cannot_assign(&self, span: Span, desc: &str) -> Diag<'infcx> {
267        struct_span_code_err!(self.dcx(), span, E0594, "cannot assign to {}", desc)
268    }
269
270    pub(crate) fn cannot_move_out_of(
271        &self,
272        move_from_span: Span,
273        move_from_desc: &str,
274    ) -> Diag<'infcx> {
275        struct_span_code_err!(
276            self.dcx(),
277            move_from_span,
278            E0507,
279            "cannot move out of {}",
280            move_from_desc
281        )
282    }
283
284    /// Signal an error due to an attempt to move out of the interior
285    /// of an array or slice. `is_index` is None when error origin
286    /// didn't capture whether there was an indexing operation or not.
287    pub(crate) fn cannot_move_out_of_interior_noncopy(
288        &self,
289        move_from_span: Span,
290        ty: Ty<'_>,
291        is_index: Option<bool>,
292    ) -> Diag<'infcx> {
293        let type_name = match (ty.kind(), is_index) {
294            (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
295            (&ty::Slice(_), _) => "slice",
296            _ => span_bug!(move_from_span, "this path should not cause illegal move"),
297        };
298        struct_span_code_err!(
299            self.dcx(),
300            move_from_span,
301            E0508,
302            "cannot move out of type `{}`, a non-copy {}",
303            ty,
304            type_name,
305        )
306        .with_span_label(move_from_span, "cannot move out of here")
307    }
308
309    pub(crate) fn cannot_move_out_of_interior_of_drop(
310        &self,
311        move_from_span: Span,
312        container_ty: Ty<'_>,
313    ) -> Diag<'infcx> {
314        struct_span_code_err!(
315            self.dcx(),
316            move_from_span,
317            E0509,
318            "cannot move out of type `{}`, which implements the `Drop` trait",
319            container_ty,
320        )
321        .with_span_label(move_from_span, "cannot move out of here")
322    }
323
324    pub(crate) fn cannot_act_on_moved_value(
325        &self,
326        use_span: Span,
327        verb: &str,
328        optional_adverb_for_moved: &str,
329        moved_path: Option<String>,
330    ) -> Diag<'infcx> {
331        let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default();
332
333        struct_span_code_err!(
334            self.dcx(),
335            use_span,
336            E0382,
337            "{} of {}moved value{}",
338            verb,
339            optional_adverb_for_moved,
340            moved_path,
341        )
342    }
343
344    pub(crate) fn cannot_borrow_path_as_mutable_because(
345        &self,
346        span: Span,
347        path: &str,
348        reason: &str,
349    ) -> Diag<'infcx> {
350        struct_span_code_err!(
351            self.dcx(),
352            span,
353            E0596,
354            "cannot borrow {} as mutable{}",
355            path,
356            reason
357        )
358    }
359
360    pub(crate) fn cannot_mutate_in_immutable_section(
361        &self,
362        mutate_span: Span,
363        immutable_span: Span,
364        immutable_place: &str,
365        immutable_section: &str,
366        action: &str,
367    ) -> Diag<'infcx> {
368        struct_span_code_err!(
369            self.dcx(),
370            mutate_span,
371            E0510,
372            "cannot {} {} in {}",
373            action,
374            immutable_place,
375            immutable_section,
376        )
377        .with_span_label(mutate_span, format!("cannot {action}"))
378        .with_span_label(immutable_span, format!("value is immutable in {immutable_section}"))
379    }
380
381    pub(crate) fn cannot_borrow_across_coroutine_yield(
382        &self,
383        span: Span,
384        yield_span: Span,
385    ) -> Diag<'infcx> {
386        let coroutine_kind = self.body.coroutine.as_ref().unwrap().coroutine_kind;
387        let mut diag = struct_span_code_err!(
388            self.dcx(),
389            span,
390            E0626,
391            "borrow may still be in use when {coroutine_kind:#} yields",
392        );
393        diag.span_label(
394            self.infcx.tcx.def_span(self.body.source.def_id()),
395            format!("within this {coroutine_kind:#}"),
396        );
397        diag.span_label(yield_span, "possible yield occurs here");
398        if matches!(coroutine_kind, hir::CoroutineKind::Coroutine(_)) {
399            let hir::Closure { capture_clause, fn_decl_span, .. } = self
400                .infcx
401                .tcx
402                .hir_node_by_def_id(self.body.source.def_id().expect_local())
403                .expect_closure();
404            let span = match capture_clause {
405                rustc_hir::CaptureBy::Value { move_kw } => move_kw.shrink_to_lo(),
406                rustc_hir::CaptureBy::Ref => fn_decl_span.shrink_to_lo(),
407            };
408            diag.span_suggestion_verbose(
409                span,
410                "add `static` to mark this coroutine as unmovable",
411                "static ",
412                Applicability::MaybeIncorrect,
413            );
414        }
415        diag
416    }
417
418    pub(crate) fn cannot_borrow_across_destructor(&self, borrow_span: Span) -> Diag<'infcx> {
419        struct_span_code_err!(
420            self.dcx(),
421            borrow_span,
422            E0713,
423            "borrow may still be in use when destructor runs",
424        )
425    }
426
427    pub(crate) fn path_does_not_live_long_enough(&self, span: Span, path: &str) -> Diag<'infcx> {
428        struct_span_code_err!(self.dcx(), span, E0597, "{} does not live long enough", path,)
429    }
430
431    pub(crate) fn cannot_return_reference_to_local(
432        &self,
433        span: Span,
434        return_kind: &str,
435        reference_desc: &str,
436        path_desc: &str,
437    ) -> Diag<'infcx> {
438        struct_span_code_err!(
439            self.dcx(),
440            span,
441            E0515,
442            "cannot {RETURN} {REFERENCE} {LOCAL}",
443            RETURN = return_kind,
444            REFERENCE = reference_desc,
445            LOCAL = path_desc,
446        )
447        .with_span_label(
448            span,
449            format!("{return_kind}s a {reference_desc} data owned by the current function"),
450        )
451    }
452
453    pub(crate) fn cannot_capture_in_long_lived_closure(
454        &self,
455        closure_span: Span,
456        closure_kind: &str,
457        borrowed_path: &str,
458        capture_span: Span,
459        scope: &str,
460    ) -> Diag<'infcx> {
461        struct_span_code_err!(
462            self.dcx(),
463            closure_span,
464            E0373,
465            "{closure_kind} may outlive the current {scope}, but it borrows {borrowed_path}, \
466             which is owned by the current {scope}",
467        )
468        .with_span_label(capture_span, format!("{borrowed_path} is borrowed here"))
469        .with_span_label(closure_span, format!("may outlive borrowed value {borrowed_path}"))
470    }
471
472    pub(crate) fn thread_local_value_does_not_live_long_enough(&self, span: Span) -> Diag<'infcx> {
473        struct_span_code_err!(
474            self.dcx(),
475            span,
476            E0712,
477            "thread-local variable borrowed past end of function",
478        )
479    }
480
481    pub(crate) fn temporary_value_borrowed_for_too_long(&self, span: Span) -> Diag<'infcx> {
482        struct_span_code_err!(self.dcx(), span, E0716, "temporary value dropped while borrowed",)
483    }
484}
485
486pub(crate) fn borrowed_data_escapes_closure<'tcx>(
487    tcx: TyCtxt<'tcx>,
488    escape_span: Span,
489    escapes_from: &str,
490) -> Diag<'tcx> {
491    struct_span_code_err!(
492        tcx.dcx(),
493        escape_span,
494        E0521,
495        "borrowed data escapes outside of {}",
496        escapes_from,
497    )
498}