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