1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use rustc::session::config::BorrowckMode;
12 use rustc::ty::{self, TyCtxt};
13 use rustc_errors::{DiagnosticBuilder, DiagnosticId};
14 use syntax_pos::{MultiSpan, Span};
18 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
24 impl fmt::Display for Origin {
25 fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
26 // If the user passed `-Z borrowck=compare`, then include
27 // origin info as part of the error report,
29 let display_origin = ty::tls::with_opt(|opt_tcx| {
30 if let Some(tcx) = opt_tcx {
31 tcx.sess.opts.borrowck_mode == BorrowckMode::Compare
38 Origin::Mir => write!(w, " (Mir)"),
39 Origin::Ast => write!(w, " (Ast)"),
42 // Print no origin info
49 /// Whether we should emit errors for the origin in the given mode
50 pub fn should_emit_errors(self, mode: BorrowckMode) -> bool {
52 Origin::Ast => mode.use_ast(),
53 Origin::Mir => mode.use_mir(),
58 pub trait BorrowckErrors<'cx>: Sized + Copy {
59 fn struct_span_err_with_code<S: Into<MultiSpan>>(
64 ) -> DiagnosticBuilder<'cx>;
66 fn struct_span_err<S: Into<MultiSpan>>(self, sp: S, msg: &str) -> DiagnosticBuilder<'cx>;
68 /// Cancels the given error if we shouldn't emit errors for a given
69 /// origin in the current mode.
71 /// Always make sure that the error gets passed through this function
72 /// before you return it.
73 fn cancel_if_wrong_origin(
75 diag: DiagnosticBuilder<'cx>,
77 ) -> DiagnosticBuilder<'cx>;
79 fn cannot_move_when_borrowed(
84 ) -> DiagnosticBuilder<'cx> {
85 let err = struct_span_err!(
89 "cannot move out of `{}` because it is borrowed{OGN}",
93 self.cancel_if_wrong_origin(err, o)
96 fn cannot_use_when_mutably_borrowed(
103 ) -> DiagnosticBuilder<'cx> {
104 let mut err = struct_span_err!(
108 "cannot use `{}` because it was mutably borrowed{OGN}",
115 format!("borrow of `{}` occurs here", borrow_desc),
117 err.span_label(span, format!("use of borrowed `{}`", borrow_desc));
119 self.cancel_if_wrong_origin(err, o)
122 fn cannot_act_on_uninitialized_variable(
128 ) -> DiagnosticBuilder<'cx> {
129 let err = struct_span_err!(
133 "{} of possibly uninitialized variable: `{}`{OGN}",
138 self.cancel_if_wrong_origin(err, o)
141 fn cannot_mutably_borrow_multiply(
148 old_load_end_span: Option<Span>,
150 ) -> DiagnosticBuilder<'cx> {
151 let mut err = struct_span_err!(
155 "cannot borrow `{}`{} as mutable more than once at a time{OGN}",
160 if old_loan_span == new_loan_span {
161 // Both borrows are happening in the same place
162 // Meaning the borrow is occurring in a loop
166 "mutable borrow starts here in previous \
167 iteration of loop{}",
171 if let Some(old_load_end_span) = old_load_end_span {
172 err.span_label(old_load_end_span, "mutable borrow ends here");
177 format!("first mutable borrow occurs here{}", old_opt_via),
181 format!("second mutable borrow occurs here{}", opt_via),
183 if let Some(old_load_end_span) = old_load_end_span {
184 err.span_label(old_load_end_span, "first borrow ends here");
187 self.cancel_if_wrong_origin(err, o)
190 fn cannot_uniquely_borrow_by_two_closures(
195 old_load_end_span: Option<Span>,
197 ) -> DiagnosticBuilder<'cx> {
198 let mut err = struct_span_err!(
202 "two closures require unique access to `{}` at the same time{OGN}",
206 if old_loan_span == new_loan_span {
209 "closures are constructed here in different iterations of loop"
212 err.span_label(old_loan_span, "first closure is constructed here");
213 err.span_label(new_loan_span, "second closure is constructed here");
215 if let Some(old_load_end_span) = old_load_end_span {
216 err.span_label(old_load_end_span, "borrow from first closure ends here");
218 self.cancel_if_wrong_origin(err, o)
221 fn cannot_uniquely_borrow_by_one_closure(
229 previous_end_span: Option<Span>,
231 ) -> DiagnosticBuilder<'cx> {
232 let mut err = struct_span_err!(
236 "closure requires unique access to `{}` but {} is already borrowed{}{OGN}",
244 format!("closure construction occurs here{}", opt_via),
246 err.span_label(old_loan_span, format!("borrow occurs here{}", old_opt_via));
247 if let Some(previous_end_span) = previous_end_span {
248 err.span_label(previous_end_span, "borrow ends here");
250 self.cancel_if_wrong_origin(err, o)
253 fn cannot_reborrow_already_uniquely_borrowed(
261 previous_end_span: Option<Span>,
263 ) -> DiagnosticBuilder<'cx> {
264 let mut err = struct_span_err!(
268 "cannot borrow `{}`{} as {} because previous closure \
269 requires unique access{OGN}",
275 err.span_label(new_loan_span, format!("borrow occurs here{}", opt_via));
278 format!("closure construction occurs here{}", old_opt_via),
280 if let Some(previous_end_span) = previous_end_span {
281 err.span_label(previous_end_span, "borrow from closure ends here");
283 self.cancel_if_wrong_origin(err, o)
286 fn cannot_reborrow_already_borrowed(
296 old_load_end_span: Option<Span>,
298 ) -> DiagnosticBuilder<'cx> {
299 let mut err = struct_span_err!(
303 "cannot borrow `{}`{} as {} because {} is also borrowed as {}{}{OGN}",
312 err.span_label(span, format!("{} borrow occurs here{}", kind_new, msg_new));
315 format!("{} borrow occurs here{}", kind_old, msg_old),
317 if let Some(old_load_end_span) = old_load_end_span {
318 err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old));
320 self.cancel_if_wrong_origin(err, o)
323 fn cannot_assign_to_borrowed(
329 ) -> DiagnosticBuilder<'cx> {
330 let mut err = struct_span_err!(
334 "cannot assign to `{}` because it is borrowed{OGN}",
339 err.span_label(borrow_span, format!("borrow of `{}` occurs here", desc));
342 format!("assignment to borrowed `{}` occurs here", desc),
345 self.cancel_if_wrong_origin(err, o)
348 fn cannot_move_into_closure(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
349 let err = struct_span_err!(
353 "cannot move `{}` into closure because it is borrowed{OGN}",
358 self.cancel_if_wrong_origin(err, o)
361 fn cannot_reassign_immutable(
367 ) -> DiagnosticBuilder<'cx> {
368 let msg = if is_arg {
369 "to immutable argument"
371 "twice to immutable variable"
373 let err = struct_span_err!(
377 "cannot assign {} `{}`{OGN}",
383 self.cancel_if_wrong_origin(err, o)
386 fn cannot_assign(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
387 let err = struct_span_err!(self, span, E0594, "cannot assign to {}{OGN}", desc, OGN = o);
388 self.cancel_if_wrong_origin(err, o)
391 fn cannot_assign_static(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
392 self.cannot_assign(span, &format!("immutable static item `{}`", desc), o)
395 fn cannot_move_out_of(
397 move_from_span: Span,
398 move_from_desc: &str,
400 ) -> DiagnosticBuilder<'cx> {
401 let mut err = struct_span_err!(
405 "cannot move out of {}{OGN}",
411 format!("cannot move out of {}", move_from_desc),
414 self.cancel_if_wrong_origin(err, o)
417 /// Signal an error due to an attempt to move out of the interior
418 /// of an array or slice. `is_index` is None when error origin
419 /// didn't capture whether there was an indexing operation or not.
420 fn cannot_move_out_of_interior_noncopy(
422 move_from_span: Span,
424 is_index: Option<bool>,
426 ) -> DiagnosticBuilder<'cx> {
427 let type_name = match (&ty.sty, is_index) {
428 (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
429 (&ty::Slice(_), _) => "slice",
430 _ => span_bug!(move_from_span, "this path should not cause illegal move"),
432 let mut err = struct_span_err!(
436 "cannot move out of type `{}`, \
442 err.span_label(move_from_span, "cannot move out of here");
444 self.cancel_if_wrong_origin(err, o)
447 fn cannot_move_out_of_interior_of_drop(
449 move_from_span: Span,
450 container_ty: ty::Ty,
452 ) -> DiagnosticBuilder<'cx> {
453 let mut err = struct_span_err!(
457 "cannot move out of type `{}`, \
458 which implements the `Drop` trait{OGN}",
462 err.span_label(move_from_span, "cannot move out of here");
464 self.cancel_if_wrong_origin(err, o)
467 fn cannot_act_on_moved_value(
471 optional_adverb_for_moved: &str,
472 moved_path: Option<String>,
474 ) -> DiagnosticBuilder<'cx> {
475 let moved_path = moved_path
476 .map(|mp| format!(": `{}`", mp))
477 .unwrap_or(String::new());
479 let err = struct_span_err!(
483 "{} of {}moved value{}{OGN}",
485 optional_adverb_for_moved,
490 self.cancel_if_wrong_origin(err, o)
493 fn cannot_partially_reinit_an_uninit_struct(
498 ) -> DiagnosticBuilder<'cx> {
499 let err = struct_span_err!(
503 "partial reinitialization of uninitialized structure `{}`{OGN}",
508 self.cancel_if_wrong_origin(err, o)
511 fn closure_cannot_assign_to_borrowed(
516 ) -> DiagnosticBuilder<'cx> {
517 let err = struct_span_err!(
521 "closure cannot assign to {}{OGN}",
526 self.cancel_if_wrong_origin(err, o)
529 fn cannot_borrow_path_as_mutable_because(
535 ) -> DiagnosticBuilder<'cx> {
536 let err = struct_span_err!(
540 "cannot borrow {} as mutable{}{OGN}",
546 self.cancel_if_wrong_origin(err, o)
549 fn cannot_borrow_path_as_mutable(
554 ) -> DiagnosticBuilder<'cx> {
555 self.cannot_borrow_path_as_mutable_because(span, path, "", o)
558 fn cannot_borrow_across_generator_yield(
563 ) -> DiagnosticBuilder<'cx> {
564 let mut err = struct_span_err!(
568 "borrow may still be in use when generator yields{OGN}",
571 err.span_label(yield_span, "possible yield occurs here");
573 self.cancel_if_wrong_origin(err, o)
576 fn cannot_borrow_across_destructor(
580 ) -> DiagnosticBuilder<'cx> {
581 let err = struct_span_err!(
585 "borrow may still be in use when destructor runs{OGN}",
589 self.cancel_if_wrong_origin(err, o)
592 fn path_does_not_live_long_enough(
597 ) -> DiagnosticBuilder<'cx> {
598 let err = struct_span_err!(
602 "{} does not live long enough{OGN}",
607 self.cancel_if_wrong_origin(err, o)
610 fn lifetime_too_short_for_reborrow(
615 ) -> DiagnosticBuilder<'cx> {
616 let err = struct_span_err!(
620 "lifetime of {} is too short to guarantee \
621 its contents can be safely reborrowed{OGN}",
626 self.cancel_if_wrong_origin(err, o)
629 fn cannot_act_on_capture_in_sharable_fn(
635 ) -> DiagnosticBuilder<'cx> {
636 let (help_span, help_msg) = help;
637 let mut err = struct_span_err!(
641 "{} in a captured outer variable in an `Fn` closure{OGN}",
645 err.span_help(help_span, help_msg);
647 self.cancel_if_wrong_origin(err, o)
650 fn cannot_assign_into_immutable_reference(
655 ) -> DiagnosticBuilder<'cx> {
656 let mut err = struct_span_err!(
660 "{} in a `&` reference{OGN}",
664 err.span_label(span, "assignment into an immutable reference");
666 self.cancel_if_wrong_origin(err, o)
669 fn cannot_capture_in_long_lived_closure(
675 ) -> DiagnosticBuilder<'cx> {
676 let mut err = struct_span_err!(
680 "closure may outlive the current function, \
682 which is owned by the current function{OGN}",
686 err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
689 format!("may outlive borrowed value {}", borrowed_path),
692 self.cancel_if_wrong_origin(err, o)
695 fn thread_local_value_does_not_live_long_enough(
699 ) -> DiagnosticBuilder<'cx> {
700 let err = struct_span_err!(
704 "thread-local variable borrowed past end of function{OGN}",
708 self.cancel_if_wrong_origin(err, o)
712 impl<'cx, 'gcx, 'tcx> BorrowckErrors<'cx> for TyCtxt<'cx, 'gcx, 'tcx> {
713 fn struct_span_err_with_code<S: Into<MultiSpan>>(
718 ) -> DiagnosticBuilder<'cx> {
719 self.sess.struct_span_err_with_code(sp, msg, code)
722 fn struct_span_err<S: Into<MultiSpan>>(self, sp: S, msg: &str) -> DiagnosticBuilder<'cx> {
723 self.sess.struct_span_err(sp, msg)
726 fn cancel_if_wrong_origin(
728 mut diag: DiagnosticBuilder<'cx>,
730 ) -> DiagnosticBuilder<'cx> {
731 if !o.should_emit_errors(self.borrowck_mode()) {
732 self.sess.diagnostic().cancel(&mut diag);