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 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 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 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 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}