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 err.span_label(old_loan_span, "first closure is constructed here");
207 err.span_label(new_loan_span, "second closure is constructed here");
208 if let Some(old_load_end_span) = old_load_end_span {
209 err.span_label(old_load_end_span, "borrow from first closure ends here");
211 self.cancel_if_wrong_origin(err, o)
214 fn cannot_uniquely_borrow_by_one_closure(
222 previous_end_span: Option<Span>,
224 ) -> DiagnosticBuilder<'cx> {
225 let mut err = struct_span_err!(
229 "closure requires unique access to `{}` but {} is already borrowed{}{OGN}",
237 format!("closure construction occurs here{}", opt_via),
239 err.span_label(old_loan_span, format!("borrow occurs here{}", old_opt_via));
240 if let Some(previous_end_span) = previous_end_span {
241 err.span_label(previous_end_span, "borrow ends here");
243 self.cancel_if_wrong_origin(err, o)
246 fn cannot_reborrow_already_uniquely_borrowed(
254 previous_end_span: Option<Span>,
256 ) -> DiagnosticBuilder<'cx> {
257 let mut err = struct_span_err!(
261 "cannot borrow `{}`{} as {} because previous closure \
262 requires unique access{OGN}",
268 err.span_label(new_loan_span, format!("borrow occurs here{}", opt_via));
271 format!("closure construction occurs here{}", old_opt_via),
273 if let Some(previous_end_span) = previous_end_span {
274 err.span_label(previous_end_span, "borrow from closure ends here");
276 self.cancel_if_wrong_origin(err, o)
279 fn cannot_reborrow_already_borrowed(
289 old_load_end_span: Option<Span>,
291 ) -> DiagnosticBuilder<'cx> {
292 let mut err = struct_span_err!(
296 "cannot borrow `{}`{} as {} because {} is also borrowed as {}{}{OGN}",
305 err.span_label(span, format!("{} borrow occurs here{}", kind_new, msg_new));
308 format!("{} borrow occurs here{}", kind_old, msg_old),
310 if let Some(old_load_end_span) = old_load_end_span {
311 err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old));
313 self.cancel_if_wrong_origin(err, o)
316 fn cannot_assign_to_borrowed(
322 ) -> DiagnosticBuilder<'cx> {
323 let mut err = struct_span_err!(
327 "cannot assign to `{}` because it is borrowed{OGN}",
332 err.span_label(borrow_span, format!("borrow of `{}` occurs here", desc));
335 format!("assignment to borrowed `{}` occurs here", desc),
338 self.cancel_if_wrong_origin(err, o)
341 fn cannot_move_into_closure(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
342 let err = struct_span_err!(
346 "cannot move `{}` into closure because it is borrowed{OGN}",
351 self.cancel_if_wrong_origin(err, o)
354 fn cannot_reassign_immutable(
360 ) -> DiagnosticBuilder<'cx> {
361 let msg = if is_arg {
362 "to immutable argument"
364 "twice to immutable variable"
366 let err = struct_span_err!(
370 "cannot assign {} `{}`{OGN}",
376 self.cancel_if_wrong_origin(err, o)
379 fn cannot_assign(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
380 let err = struct_span_err!(self, span, E0594, "cannot assign to {}{OGN}", desc, OGN = o);
381 self.cancel_if_wrong_origin(err, o)
384 fn cannot_assign_static(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
385 self.cannot_assign(span, &format!("immutable static item `{}`", desc), o)
388 fn cannot_move_out_of(
390 move_from_span: Span,
391 move_from_desc: &str,
393 ) -> DiagnosticBuilder<'cx> {
394 let mut err = struct_span_err!(
398 "cannot move out of {}{OGN}",
404 format!("cannot move out of {}", move_from_desc),
407 self.cancel_if_wrong_origin(err, o)
410 /// Signal an error due to an attempt to move out of the interior
411 /// of an array or slice. `is_index` is None when error origin
412 /// didn't capture whether there was an indexing operation or not.
413 fn cannot_move_out_of_interior_noncopy(
415 move_from_span: Span,
417 is_index: Option<bool>,
419 ) -> DiagnosticBuilder<'cx> {
420 let type_name = match (&ty.sty, is_index) {
421 (&ty::TyArray(_, _), Some(true)) | (&ty::TyArray(_, _), None) => "array",
422 (&ty::TySlice(_), _) => "slice",
423 _ => span_bug!(move_from_span, "this path should not cause illegal move"),
425 let mut err = struct_span_err!(
429 "cannot move out of type `{}`, \
435 err.span_label(move_from_span, "cannot move out of here");
437 self.cancel_if_wrong_origin(err, o)
440 fn cannot_move_out_of_interior_of_drop(
442 move_from_span: Span,
443 container_ty: ty::Ty,
445 ) -> DiagnosticBuilder<'cx> {
446 let mut err = struct_span_err!(
450 "cannot move out of type `{}`, \
451 which implements the `Drop` trait{OGN}",
455 err.span_label(move_from_span, "cannot move out of here");
457 self.cancel_if_wrong_origin(err, o)
460 fn cannot_act_on_moved_value(
464 optional_adverb_for_moved: &str,
465 moved_path: Option<String>,
467 ) -> DiagnosticBuilder<'cx> {
468 let moved_path = moved_path
469 .map(|mp| format!(": `{}`", mp))
470 .unwrap_or("".to_owned());
472 let err = struct_span_err!(
476 "{} of {}moved value{}{OGN}",
478 optional_adverb_for_moved,
483 self.cancel_if_wrong_origin(err, o)
486 fn cannot_partially_reinit_an_uninit_struct(
491 ) -> DiagnosticBuilder<'cx> {
492 let err = struct_span_err!(
496 "partial reinitialization of uninitialized structure `{}`{OGN}",
501 self.cancel_if_wrong_origin(err, o)
504 fn closure_cannot_assign_to_borrowed(
509 ) -> DiagnosticBuilder<'cx> {
510 let err = struct_span_err!(
514 "closure cannot assign to {}{OGN}",
519 self.cancel_if_wrong_origin(err, o)
522 fn cannot_borrow_path_as_mutable(
527 ) -> DiagnosticBuilder<'cx> {
528 let err = struct_span_err!(
532 "cannot borrow {} as mutable{OGN}",
537 self.cancel_if_wrong_origin(err, o)
540 fn cannot_borrow_across_generator_yield(
545 ) -> DiagnosticBuilder<'cx> {
546 let mut err = struct_span_err!(
550 "borrow may still be in use when generator yields{OGN}",
553 err.span_label(yield_span, "possible yield occurs here");
555 self.cancel_if_wrong_origin(err, o)
558 fn path_does_not_live_long_enough(
563 ) -> DiagnosticBuilder<'cx> {
564 let err = struct_span_err!(
568 "{} does not live long enough{OGN}",
573 self.cancel_if_wrong_origin(err, o)
576 fn lifetime_too_short_for_reborrow(
581 ) -> DiagnosticBuilder<'cx> {
582 let err = struct_span_err!(
586 "lifetime of {} is too short to guarantee \
587 its contents can be safely reborrowed{OGN}",
592 self.cancel_if_wrong_origin(err, o)
595 fn cannot_act_on_capture_in_sharable_fn(
601 ) -> DiagnosticBuilder<'cx> {
602 let (help_span, help_msg) = help;
603 let mut err = struct_span_err!(
607 "{} in a captured outer variable in an `Fn` closure{OGN}",
611 err.span_help(help_span, help_msg);
613 self.cancel_if_wrong_origin(err, o)
616 fn cannot_assign_into_immutable_reference(
621 ) -> DiagnosticBuilder<'cx> {
622 let mut err = struct_span_err!(
626 "{} in a `&` reference{OGN}",
630 err.span_label(span, "assignment into an immutable reference");
632 self.cancel_if_wrong_origin(err, o)
635 fn cannot_capture_in_long_lived_closure(
641 ) -> DiagnosticBuilder<'cx> {
642 let mut err = struct_span_err!(
646 "closure may outlive the current function, \
648 which is owned by the current function{OGN}",
652 err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
655 format!("may outlive borrowed value {}", borrowed_path),
658 self.cancel_if_wrong_origin(err, o)
662 impl<'cx, 'gcx, 'tcx> BorrowckErrors<'cx> for TyCtxt<'cx, 'gcx, 'tcx> {
663 fn struct_span_err_with_code<S: Into<MultiSpan>>(
668 ) -> DiagnosticBuilder<'cx> {
669 self.sess.struct_span_err_with_code(sp, msg, code)
672 fn struct_span_err<S: Into<MultiSpan>>(self, sp: S, msg: &str) -> DiagnosticBuilder<'cx> {
673 self.sess.struct_span_err(sp, msg)
676 fn cancel_if_wrong_origin(
678 mut diag: DiagnosticBuilder<'cx>,
680 ) -> DiagnosticBuilder<'cx> {
681 if !o.should_emit_errors(self.borrowck_mode()) {
682 self.sess.diagnostic().cancel(&mut diag);