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(
224 container_name: &str,
230 previous_end_span: Option<Span>,
232 ) -> DiagnosticBuilder<'cx> {
233 let mut err = struct_span_err!(
237 "closure requires unique access to `{}` but {} is already borrowed{}{OGN}",
245 format!("{} construction occurs here{}", container_name, opt_via),
247 err.span_label(old_loan_span, format!("borrow occurs here{}", old_opt_via));
248 if let Some(previous_end_span) = previous_end_span {
249 err.span_label(previous_end_span, "borrow ends here");
251 self.cancel_if_wrong_origin(err, o)
254 fn cannot_reborrow_already_uniquely_borrowed(
257 container_name: &str,
263 previous_end_span: Option<Span>,
265 ) -> DiagnosticBuilder<'cx> {
266 let mut err = struct_span_err!(
270 "cannot borrow `{}`{} as {} because previous closure \
271 requires unique access{OGN}",
277 err.span_label(new_loan_span, format!("borrow occurs here{}", opt_via));
280 format!("{} construction occurs here{}", container_name, old_opt_via),
282 if let Some(previous_end_span) = previous_end_span {
283 err.span_label(previous_end_span, "borrow from closure ends here");
285 self.cancel_if_wrong_origin(err, o)
288 fn cannot_reborrow_already_borrowed(
298 old_load_end_span: Option<Span>,
300 ) -> DiagnosticBuilder<'cx> {
301 let mut err = struct_span_err!(
305 "cannot borrow `{}`{} as {} because {} is also borrowed as {}{}{OGN}",
314 err.span_label(span, format!("{} borrow occurs here{}", kind_new, msg_new));
317 format!("{} borrow occurs here{}", kind_old, msg_old),
319 if let Some(old_load_end_span) = old_load_end_span {
320 err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old));
322 self.cancel_if_wrong_origin(err, o)
325 fn cannot_assign_to_borrowed(
331 ) -> DiagnosticBuilder<'cx> {
332 let mut err = struct_span_err!(
336 "cannot assign to `{}` because it is borrowed{OGN}",
341 err.span_label(borrow_span, format!("borrow of `{}` occurs here", desc));
344 format!("assignment to borrowed `{}` occurs here", desc),
347 self.cancel_if_wrong_origin(err, o)
350 fn cannot_move_into_closure(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
351 let err = struct_span_err!(
355 "cannot move `{}` into closure because it is borrowed{OGN}",
360 self.cancel_if_wrong_origin(err, o)
363 fn cannot_reassign_immutable(
369 ) -> DiagnosticBuilder<'cx> {
370 let msg = if is_arg {
371 "to immutable argument"
373 "twice to immutable variable"
375 let err = struct_span_err!(
379 "cannot assign {} `{}`{OGN}",
385 self.cancel_if_wrong_origin(err, o)
388 fn cannot_assign(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
389 let err = struct_span_err!(self, span, E0594, "cannot assign to {}{OGN}", desc, OGN = o);
390 self.cancel_if_wrong_origin(err, o)
393 fn cannot_assign_static(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
394 self.cannot_assign(span, &format!("immutable static item `{}`", desc), o)
397 fn cannot_move_out_of(
399 move_from_span: Span,
400 move_from_desc: &str,
402 ) -> DiagnosticBuilder<'cx> {
403 let mut err = struct_span_err!(
407 "cannot move out of {}{OGN}",
413 format!("cannot move out of {}", move_from_desc),
416 self.cancel_if_wrong_origin(err, o)
419 /// Signal an error due to an attempt to move out of the interior
420 /// of an array or slice. `is_index` is None when error origin
421 /// didn't capture whether there was an indexing operation or not.
422 fn cannot_move_out_of_interior_noncopy(
424 move_from_span: Span,
426 is_index: Option<bool>,
428 ) -> DiagnosticBuilder<'cx> {
429 let type_name = match (&ty.sty, is_index) {
430 (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
431 (&ty::Slice(_), _) => "slice",
432 _ => span_bug!(move_from_span, "this path should not cause illegal move"),
434 let mut err = struct_span_err!(
438 "cannot move out of type `{}`, \
444 err.span_label(move_from_span, "cannot move out of here");
446 self.cancel_if_wrong_origin(err, o)
449 fn cannot_move_out_of_interior_of_drop(
451 move_from_span: Span,
452 container_ty: ty::Ty,
454 ) -> DiagnosticBuilder<'cx> {
455 let mut err = struct_span_err!(
459 "cannot move out of type `{}`, \
460 which implements the `Drop` trait{OGN}",
464 err.span_label(move_from_span, "cannot move out of here");
466 self.cancel_if_wrong_origin(err, o)
469 fn cannot_act_on_moved_value(
473 optional_adverb_for_moved: &str,
474 moved_path: Option<String>,
476 ) -> DiagnosticBuilder<'cx> {
477 let moved_path = moved_path
478 .map(|mp| format!(": `{}`", mp))
479 .unwrap_or_default();
481 let err = struct_span_err!(
485 "{} of {}moved value{}{OGN}",
487 optional_adverb_for_moved,
492 self.cancel_if_wrong_origin(err, o)
495 fn cannot_partially_reinit_an_uninit_struct(
500 ) -> DiagnosticBuilder<'cx> {
501 let err = struct_span_err!(
505 "partial reinitialization of uninitialized structure `{}`{OGN}",
510 self.cancel_if_wrong_origin(err, o)
513 fn closure_cannot_assign_to_borrowed(
518 ) -> DiagnosticBuilder<'cx> {
519 let err = struct_span_err!(
523 "closure cannot assign to {}{OGN}",
528 self.cancel_if_wrong_origin(err, o)
531 fn cannot_borrow_path_as_mutable_because(
537 ) -> DiagnosticBuilder<'cx> {
538 let err = struct_span_err!(
542 "cannot borrow {} as mutable{}{OGN}",
548 self.cancel_if_wrong_origin(err, o)
551 fn cannot_borrow_path_as_mutable(
556 ) -> DiagnosticBuilder<'cx> {
557 self.cannot_borrow_path_as_mutable_because(span, path, "", o)
560 fn cannot_mutate_in_match_guard(
567 ) -> DiagnosticBuilder<'cx> {
568 let mut err = struct_span_err!(
572 "cannot {} `{}` in match guard{OGN}",
577 err.span_label(mutate_span, format!("cannot {}", action));
578 err.span_label(match_span, format!("value is immutable in match guard"));
580 self.cancel_if_wrong_origin(err, o)
583 fn cannot_borrow_across_generator_yield(
588 ) -> DiagnosticBuilder<'cx> {
589 let mut err = struct_span_err!(
593 "borrow may still be in use when generator yields{OGN}",
596 err.span_label(yield_span, "possible yield occurs here");
598 self.cancel_if_wrong_origin(err, o)
601 fn cannot_borrow_across_destructor(
605 ) -> DiagnosticBuilder<'cx> {
606 let err = struct_span_err!(
610 "borrow may still be in use when destructor runs{OGN}",
614 self.cancel_if_wrong_origin(err, o)
617 fn path_does_not_live_long_enough(
622 ) -> DiagnosticBuilder<'cx> {
623 let err = struct_span_err!(
627 "{} does not live long enough{OGN}",
632 self.cancel_if_wrong_origin(err, o)
635 fn lifetime_too_short_for_reborrow(
640 ) -> DiagnosticBuilder<'cx> {
641 let err = struct_span_err!(
645 "lifetime of {} is too short to guarantee \
646 its contents can be safely reborrowed{OGN}",
651 self.cancel_if_wrong_origin(err, o)
654 fn cannot_act_on_capture_in_sharable_fn(
660 ) -> DiagnosticBuilder<'cx> {
661 let (help_span, help_msg) = help;
662 let mut err = struct_span_err!(
666 "{} in a captured outer variable in an `Fn` closure{OGN}",
670 err.span_help(help_span, help_msg);
672 self.cancel_if_wrong_origin(err, o)
675 fn cannot_assign_into_immutable_reference(
680 ) -> DiagnosticBuilder<'cx> {
681 let mut err = struct_span_err!(
685 "{} in a `&` reference{OGN}",
689 err.span_label(span, "assignment into an immutable reference");
691 self.cancel_if_wrong_origin(err, o)
694 fn cannot_capture_in_long_lived_closure(
700 ) -> DiagnosticBuilder<'cx> {
701 let mut err = struct_span_err!(
705 "closure may outlive the current function, \
707 which is owned by the current function{OGN}",
711 err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
714 format!("may outlive borrowed value {}", borrowed_path),
717 self.cancel_if_wrong_origin(err, o)
720 fn thread_local_value_does_not_live_long_enough(
724 ) -> DiagnosticBuilder<'cx> {
725 let err = struct_span_err!(
729 "thread-local variable borrowed past end of function{OGN}",
733 self.cancel_if_wrong_origin(err, o)
736 fn temporary_value_borrowed_for_too_long(
740 ) -> DiagnosticBuilder<'cx> {
741 let err = struct_span_err!(
745 "temporary value dropped while borrowed{OGN}",
749 self.cancel_if_wrong_origin(err, o)
753 impl<'cx, 'gcx, 'tcx> BorrowckErrors<'cx> for TyCtxt<'cx, 'gcx, 'tcx> {
754 fn struct_span_err_with_code<S: Into<MultiSpan>>(
759 ) -> DiagnosticBuilder<'cx> {
760 self.sess.struct_span_err_with_code(sp, msg, code)
763 fn struct_span_err<S: Into<MultiSpan>>(self, sp: S, msg: &str) -> DiagnosticBuilder<'cx> {
764 self.sess.struct_span_err(sp, msg)
767 fn cancel_if_wrong_origin(
769 mut diag: DiagnosticBuilder<'cx>,
771 ) -> DiagnosticBuilder<'cx> {
772 if !o.should_emit_errors(self.borrowck_mode()) {
773 self.sess.diagnostic().cancel(&mut diag);