1 use rustc::session::config::BorrowckMode;
2 use rustc::ty::{self, TyCtxt};
3 use rustc_errors::{DiagnosticBuilder, DiagnosticId};
4 use syntax_pos::{MultiSpan, Span};
8 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
14 impl fmt::Display for Origin {
15 fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
16 // If the user passed `-Z borrowck=compare`, then include
17 // origin info as part of the error report,
19 let display_origin = ty::tls::with_opt(|opt_tcx| {
20 if let Some(tcx) = opt_tcx {
21 tcx.sess.opts.borrowck_mode == BorrowckMode::Compare
28 Origin::Mir => write!(w, " (Mir)"),
29 Origin::Ast => write!(w, " (Ast)"),
32 // Print no origin info
39 /// Whether we should emit errors for the origin in the given mode
40 pub fn should_emit_errors(self, mode: BorrowckMode) -> bool {
42 Origin::Ast => mode.use_ast(),
43 Origin::Mir => mode.use_mir(),
48 pub trait BorrowckErrors<'cx>: Sized + Copy {
49 fn struct_span_err_with_code<S: Into<MultiSpan>>(
54 ) -> DiagnosticBuilder<'cx>;
56 fn struct_span_err<S: Into<MultiSpan>>(self, sp: S, msg: &str) -> DiagnosticBuilder<'cx>;
58 /// Cancels the given error if we shouldn't emit errors for a given
59 /// origin in the current mode.
61 /// Always make sure that the error gets passed through this function
62 /// before you return it.
63 fn cancel_if_wrong_origin(
65 diag: DiagnosticBuilder<'cx>,
67 ) -> DiagnosticBuilder<'cx>;
69 fn cannot_move_when_borrowed(
74 ) -> DiagnosticBuilder<'cx> {
75 let err = struct_span_err!(
79 "cannot move out of `{}` because it is borrowed{OGN}",
83 self.cancel_if_wrong_origin(err, o)
86 fn cannot_use_when_mutably_borrowed(
93 ) -> DiagnosticBuilder<'cx> {
94 let mut err = struct_span_err!(
98 "cannot use `{}` because it was mutably borrowed{OGN}",
105 format!("borrow of `{}` occurs here", borrow_desc),
107 err.span_label(span, format!("use of borrowed `{}`", borrow_desc));
109 self.cancel_if_wrong_origin(err, o)
112 fn cannot_act_on_uninitialized_variable(
118 ) -> DiagnosticBuilder<'cx> {
119 let err = struct_span_err!(
123 "{} of possibly uninitialized variable: `{}`{OGN}",
128 self.cancel_if_wrong_origin(err, o)
131 fn cannot_mutably_borrow_multiply(
138 old_load_end_span: Option<Span>,
140 ) -> DiagnosticBuilder<'cx> {
141 let mut err = struct_span_err!(
145 "cannot borrow `{}`{} as mutable more than once at a time{OGN}",
150 if old_loan_span == new_loan_span {
151 // Both borrows are happening in the same place
152 // Meaning the borrow is occurring in a loop
156 "mutable borrow starts here in previous \
157 iteration of loop{}",
161 if let Some(old_load_end_span) = old_load_end_span {
162 err.span_label(old_load_end_span, "mutable borrow ends here");
167 format!("first mutable borrow occurs here{}", old_opt_via),
171 format!("second mutable borrow occurs here{}", opt_via),
173 if let Some(old_load_end_span) = old_load_end_span {
174 err.span_label(old_load_end_span, "first borrow ends here");
177 self.cancel_if_wrong_origin(err, o)
180 fn cannot_uniquely_borrow_by_two_closures(
185 old_load_end_span: Option<Span>,
187 ) -> DiagnosticBuilder<'cx> {
188 let mut err = struct_span_err!(
192 "two closures require unique access to `{}` at the same time{OGN}",
196 if old_loan_span == new_loan_span {
199 "closures are constructed here in different iterations of loop"
202 err.span_label(old_loan_span, "first closure is constructed here");
203 err.span_label(new_loan_span, "second closure is constructed here");
205 if let Some(old_load_end_span) = old_load_end_span {
206 err.span_label(old_load_end_span, "borrow from first closure ends here");
208 self.cancel_if_wrong_origin(err, o)
211 fn cannot_uniquely_borrow_by_one_closure(
214 container_name: &str,
220 previous_end_span: Option<Span>,
222 ) -> DiagnosticBuilder<'cx> {
223 let mut err = struct_span_err!(
227 "closure requires unique access to `{}` but {} is already borrowed{}{OGN}",
235 format!("{} construction occurs here{}", container_name, opt_via),
237 err.span_label(old_loan_span, format!("borrow occurs here{}", old_opt_via));
238 if let Some(previous_end_span) = previous_end_span {
239 err.span_label(previous_end_span, "borrow ends here");
241 self.cancel_if_wrong_origin(err, o)
244 fn cannot_reborrow_already_uniquely_borrowed(
247 container_name: &str,
253 previous_end_span: Option<Span>,
254 second_borrow_desc: &str,
256 ) -> DiagnosticBuilder<'cx> {
257 let mut err = struct_span_err!(
261 "cannot borrow `{}`{} as {} because previous closure \
262 requires unique access{OGN}",
270 format!("{}borrow occurs here{}", second_borrow_desc, opt_via),
274 format!("{} construction occurs here{}", container_name, old_opt_via),
276 if let Some(previous_end_span) = previous_end_span {
277 err.span_label(previous_end_span, "borrow from closure ends here");
279 self.cancel_if_wrong_origin(err, o)
282 fn cannot_reborrow_already_borrowed(
292 old_load_end_span: Option<Span>,
294 ) -> DiagnosticBuilder<'cx> {
295 let mut err = struct_span_err!(
299 "cannot borrow `{}`{} as {} because {} is also borrowed as {}{}{OGN}",
308 err.span_label(span, format!("{} borrow occurs here{}", kind_new, msg_new));
311 format!("{} borrow occurs here{}", kind_old, msg_old),
313 if let Some(old_load_end_span) = old_load_end_span {
314 err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old));
316 self.cancel_if_wrong_origin(err, o)
319 fn cannot_assign_to_borrowed(
325 ) -> DiagnosticBuilder<'cx> {
326 let mut err = struct_span_err!(
330 "cannot assign to `{}` because it is borrowed{OGN}",
335 err.span_label(borrow_span, format!("borrow of `{}` occurs here", desc));
338 format!("assignment to borrowed `{}` occurs here", desc),
341 self.cancel_if_wrong_origin(err, o)
344 fn cannot_move_into_closure(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
345 let err = struct_span_err!(
349 "cannot move `{}` into closure because it is borrowed{OGN}",
354 self.cancel_if_wrong_origin(err, o)
357 fn cannot_reassign_immutable(
363 ) -> DiagnosticBuilder<'cx> {
364 let msg = if is_arg {
365 "to immutable argument"
367 "twice to immutable variable"
369 let err = struct_span_err!(
373 "cannot assign {} `{}`{OGN}",
379 self.cancel_if_wrong_origin(err, o)
382 fn cannot_assign(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
383 let err = struct_span_err!(self, span, E0594, "cannot assign to {}{OGN}", desc, OGN = o);
384 self.cancel_if_wrong_origin(err, o)
387 fn cannot_assign_static(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
388 self.cannot_assign(span, &format!("immutable static item `{}`", desc), o)
391 fn cannot_move_out_of(
393 move_from_span: Span,
394 move_from_desc: &str,
396 ) -> DiagnosticBuilder<'cx> {
397 let mut err = struct_span_err!(
401 "cannot move out of {}{OGN}",
407 format!("cannot move out of {}", move_from_desc),
410 self.cancel_if_wrong_origin(err, o)
413 /// Signal an error due to an attempt to move out of the interior
414 /// of an array or slice. `is_index` is None when error origin
415 /// didn't capture whether there was an indexing operation or not.
416 fn cannot_move_out_of_interior_noncopy(
418 move_from_span: Span,
420 is_index: Option<bool>,
422 ) -> DiagnosticBuilder<'cx> {
423 let type_name = match (&ty.sty, is_index) {
424 (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
425 (&ty::Slice(_), _) => "slice",
426 _ => span_bug!(move_from_span, "this path should not cause illegal move"),
428 let mut err = struct_span_err!(
432 "cannot move out of type `{}`, \
438 err.span_label(move_from_span, "cannot move out of here");
440 self.cancel_if_wrong_origin(err, o)
443 fn cannot_move_out_of_interior_of_drop(
445 move_from_span: Span,
446 container_ty: ty::Ty,
448 ) -> DiagnosticBuilder<'cx> {
449 let mut err = struct_span_err!(
453 "cannot move out of type `{}`, \
454 which implements the `Drop` trait{OGN}",
458 err.span_label(move_from_span, "cannot move out of here");
460 self.cancel_if_wrong_origin(err, o)
463 fn cannot_act_on_moved_value(
467 optional_adverb_for_moved: &str,
468 moved_path: Option<String>,
470 ) -> DiagnosticBuilder<'cx> {
471 let moved_path = moved_path
472 .map(|mp| format!(": `{}`", mp))
473 .unwrap_or_default();
475 let err = struct_span_err!(
479 "{} of {}moved value{}{OGN}",
481 optional_adverb_for_moved,
486 self.cancel_if_wrong_origin(err, o)
489 fn cannot_partially_reinit_an_uninit_struct(
494 ) -> DiagnosticBuilder<'cx> {
495 let err = struct_span_err!(
499 "partial reinitialization of uninitialized structure `{}`{OGN}",
504 self.cancel_if_wrong_origin(err, o)
507 fn closure_cannot_assign_to_borrowed(
512 ) -> DiagnosticBuilder<'cx> {
513 let err = struct_span_err!(
517 "closure cannot assign to {}{OGN}",
522 self.cancel_if_wrong_origin(err, o)
525 fn cannot_borrow_path_as_mutable_because(
531 ) -> DiagnosticBuilder<'cx> {
532 let err = struct_span_err!(
536 "cannot borrow {} as mutable{}{OGN}",
542 self.cancel_if_wrong_origin(err, o)
545 fn cannot_borrow_path_as_mutable(
550 ) -> DiagnosticBuilder<'cx> {
551 self.cannot_borrow_path_as_mutable_because(span, path, "", o)
554 fn cannot_mutate_in_match_guard(
561 ) -> DiagnosticBuilder<'cx> {
562 let mut err = struct_span_err!(
566 "cannot {} `{}` in match guard{OGN}",
571 err.span_label(mutate_span, format!("cannot {}", action));
572 err.span_label(match_span, String::from("value is immutable in match guard"));
574 self.cancel_if_wrong_origin(err, o)
577 fn cannot_borrow_across_generator_yield(
582 ) -> DiagnosticBuilder<'cx> {
583 let mut err = struct_span_err!(
587 "borrow may still be in use when generator yields{OGN}",
590 err.span_label(yield_span, "possible yield occurs here");
592 self.cancel_if_wrong_origin(err, o)
595 fn cannot_borrow_across_destructor(
599 ) -> DiagnosticBuilder<'cx> {
600 let err = struct_span_err!(
604 "borrow may still be in use when destructor runs{OGN}",
608 self.cancel_if_wrong_origin(err, o)
611 fn path_does_not_live_long_enough(
616 ) -> DiagnosticBuilder<'cx> {
617 let err = struct_span_err!(
621 "{} does not live long enough{OGN}",
626 self.cancel_if_wrong_origin(err, o)
629 fn cannot_return_reference_to_local(
632 reference_desc: &str,
635 ) -> DiagnosticBuilder<'cx> {
636 let mut err = struct_span_err!(
640 "cannot return {REFERENCE} {LOCAL}{OGN}",
641 REFERENCE=reference_desc,
648 format!("returns a {} data owned by the current function", reference_desc),
651 self.cancel_if_wrong_origin(err, o)
654 fn lifetime_too_short_for_reborrow(
659 ) -> DiagnosticBuilder<'cx> {
660 let err = struct_span_err!(
664 "lifetime of {} is too short to guarantee \
665 its contents can be safely reborrowed{OGN}",
670 self.cancel_if_wrong_origin(err, o)
673 fn cannot_act_on_capture_in_sharable_fn(
679 ) -> DiagnosticBuilder<'cx> {
680 let (help_span, help_msg) = help;
681 let mut err = struct_span_err!(
685 "{} in a captured outer variable in an `Fn` closure{OGN}",
689 err.span_help(help_span, help_msg);
691 self.cancel_if_wrong_origin(err, o)
694 fn cannot_assign_into_immutable_reference(
699 ) -> DiagnosticBuilder<'cx> {
700 let mut err = struct_span_err!(
704 "{} in a `&` reference{OGN}",
708 err.span_label(span, "assignment into an immutable reference");
710 self.cancel_if_wrong_origin(err, o)
713 fn cannot_capture_in_long_lived_closure(
719 ) -> DiagnosticBuilder<'cx> {
720 let mut err = struct_span_err!(
724 "closure may outlive the current function, \
726 which is owned by the current function{OGN}",
730 err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
733 format!("may outlive borrowed value {}", borrowed_path),
736 self.cancel_if_wrong_origin(err, o)
739 fn borrowed_data_escapes_closure(
744 ) -> DiagnosticBuilder<'cx> {
745 let err = struct_span_err!(
749 "borrowed data escapes outside of {}{OGN}",
754 self.cancel_if_wrong_origin(err, o)
757 fn thread_local_value_does_not_live_long_enough(
761 ) -> DiagnosticBuilder<'cx> {
762 let err = struct_span_err!(
766 "thread-local variable borrowed past end of function{OGN}",
770 self.cancel_if_wrong_origin(err, o)
773 fn temporary_value_borrowed_for_too_long(
777 ) -> DiagnosticBuilder<'cx> {
778 let err = struct_span_err!(
782 "temporary value dropped while borrowed{OGN}",
786 self.cancel_if_wrong_origin(err, o)
790 impl<'cx, 'gcx, 'tcx> BorrowckErrors<'cx> for TyCtxt<'cx, 'gcx, 'tcx> {
791 fn struct_span_err_with_code<S: Into<MultiSpan>>(
796 ) -> DiagnosticBuilder<'cx> {
797 self.sess.struct_span_err_with_code(sp, msg, code)
800 fn struct_span_err<S: Into<MultiSpan>>(self, sp: S, msg: &str) -> DiagnosticBuilder<'cx> {
801 self.sess.struct_span_err(sp, msg)
804 fn cancel_if_wrong_origin(
806 mut diag: DiagnosticBuilder<'cx>,
808 ) -> DiagnosticBuilder<'cx> {
809 if !o.should_emit_errors(self.borrowck_mode()) {
810 self.sess.diagnostic().cancel(&mut diag);