// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use rustc::session::config::BorrowckMode; use rustc::ty::{self, TyCtxt}; use rustc_errors::{DiagnosticBuilder, DiagnosticId}; use syntax_pos::{MultiSpan, Span}; use std::fmt; #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum Origin { Ast, Mir, } impl fmt::Display for Origin { fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { // If the user passed `-Z borrowck=compare`, then include // origin info as part of the error report, // otherwise let display_origin = ty::tls::with_opt(|opt_tcx| { if let Some(tcx) = opt_tcx { tcx.sess.opts.borrowck_mode == BorrowckMode::Compare } else { false } }); if display_origin { match *self { Origin::Mir => write!(w, " (Mir)"), Origin::Ast => write!(w, " (Ast)"), } } else { // Print no origin info Ok(()) } } } impl Origin { /// Whether we should emit errors for the origin in the given mode pub fn should_emit_errors(self, mode: BorrowckMode) -> bool { match self { Origin::Ast => mode.use_ast(), Origin::Mir => mode.use_mir(), } } } pub trait BorrowckErrors<'cx>: Sized + Copy { fn struct_span_err_with_code>( self, sp: S, msg: &str, code: DiagnosticId, ) -> DiagnosticBuilder<'cx>; fn struct_span_err>(self, sp: S, msg: &str) -> DiagnosticBuilder<'cx>; /// Cancels the given error if we shouldn't emit errors for a given /// origin in the current mode. /// /// Always make sure that the error gets passed through this function /// before you return it. fn cancel_if_wrong_origin( self, diag: DiagnosticBuilder<'cx>, o: Origin, ) -> DiagnosticBuilder<'cx>; fn cannot_move_when_borrowed( self, span: Span, desc: &str, o: Origin, ) -> DiagnosticBuilder<'cx> { let err = struct_span_err!( self, span, E0505, "cannot move out of `{}` because it is borrowed{OGN}", desc, OGN = o ); self.cancel_if_wrong_origin(err, o) } fn cannot_use_when_mutably_borrowed( self, span: Span, desc: &str, borrow_span: Span, borrow_desc: &str, o: Origin, ) -> DiagnosticBuilder<'cx> { let mut err = struct_span_err!( self, span, E0503, "cannot use `{}` because it was mutably borrowed{OGN}", desc, OGN = o ); err.span_label( borrow_span, format!("borrow of `{}` occurs here", borrow_desc), ); err.span_label(span, format!("use of borrowed `{}`", borrow_desc)); self.cancel_if_wrong_origin(err, o) } fn cannot_act_on_uninitialized_variable( self, span: Span, verb: &str, desc: &str, o: Origin, ) -> DiagnosticBuilder<'cx> { let err = struct_span_err!( self, span, E0381, "{} of possibly uninitialized variable: `{}`{OGN}", verb, desc, OGN = o ); self.cancel_if_wrong_origin(err, o) } fn cannot_mutably_borrow_multiply( self, new_loan_span: Span, desc: &str, opt_via: &str, old_loan_span: Span, old_opt_via: &str, old_load_end_span: Option, o: Origin, ) -> DiagnosticBuilder<'cx> { let mut err = struct_span_err!( self, new_loan_span, E0499, "cannot borrow `{}`{} as mutable more than once at a time{OGN}", desc, opt_via, OGN = o ); if old_loan_span == new_loan_span { // Both borrows are happening in the same place // Meaning the borrow is occurring in a loop err.span_label( new_loan_span, format!( "mutable borrow starts here in previous \ iteration of loop{}", opt_via ), ); if let Some(old_load_end_span) = old_load_end_span { err.span_label(old_load_end_span, "mutable borrow ends here"); } } else { err.span_label( old_loan_span, format!("first mutable borrow occurs here{}", old_opt_via), ); err.span_label( new_loan_span, format!("second mutable borrow occurs here{}", opt_via), ); if let Some(old_load_end_span) = old_load_end_span { err.span_label(old_load_end_span, "first borrow ends here"); } } self.cancel_if_wrong_origin(err, o) } fn cannot_uniquely_borrow_by_two_closures( self, new_loan_span: Span, desc: &str, old_loan_span: Span, old_load_end_span: Option, o: Origin, ) -> DiagnosticBuilder<'cx> { let mut err = struct_span_err!( self, new_loan_span, E0524, "two closures require unique access to `{}` at the same time{OGN}", desc, OGN = o ); if old_loan_span == new_loan_span { err.span_label( old_loan_span, "closures are constructed here in different iterations of loop" ); } else { err.span_label(old_loan_span, "first closure is constructed here"); err.span_label(new_loan_span, "second closure is constructed here"); } if let Some(old_load_end_span) = old_load_end_span { err.span_label(old_load_end_span, "borrow from first closure ends here"); } self.cancel_if_wrong_origin(err, o) } fn cannot_uniquely_borrow_by_one_closure( self, new_loan_span: Span, desc_new: &str, opt_via: &str, old_loan_span: Span, noun_old: &str, old_opt_via: &str, previous_end_span: Option, o: Origin, ) -> DiagnosticBuilder<'cx> { let mut err = struct_span_err!( self, new_loan_span, E0500, "closure requires unique access to `{}` but {} is already borrowed{}{OGN}", desc_new, noun_old, old_opt_via, OGN = o ); err.span_label( new_loan_span, format!("closure construction occurs here{}", opt_via), ); err.span_label(old_loan_span, format!("borrow occurs here{}", old_opt_via)); if let Some(previous_end_span) = previous_end_span { err.span_label(previous_end_span, "borrow ends here"); } self.cancel_if_wrong_origin(err, o) } fn cannot_reborrow_already_uniquely_borrowed( self, new_loan_span: Span, desc_new: &str, opt_via: &str, kind_new: &str, old_loan_span: Span, old_opt_via: &str, previous_end_span: Option, o: Origin, ) -> DiagnosticBuilder<'cx> { let mut err = struct_span_err!( self, new_loan_span, E0501, "cannot borrow `{}`{} as {} because previous closure \ requires unique access{OGN}", desc_new, opt_via, kind_new, OGN = o ); err.span_label(new_loan_span, format!("borrow occurs here{}", opt_via)); err.span_label( old_loan_span, format!("closure construction occurs here{}", old_opt_via), ); if let Some(previous_end_span) = previous_end_span { err.span_label(previous_end_span, "borrow from closure ends here"); } self.cancel_if_wrong_origin(err, o) } fn cannot_reborrow_already_borrowed( self, span: Span, desc_new: &str, msg_new: &str, kind_new: &str, old_span: Span, noun_old: &str, kind_old: &str, msg_old: &str, old_load_end_span: Option, o: Origin, ) -> DiagnosticBuilder<'cx> { let mut err = struct_span_err!( self, span, E0502, "cannot borrow `{}`{} as {} because {} is also borrowed as {}{}{OGN}", desc_new, msg_new, kind_new, noun_old, kind_old, msg_old, OGN = o ); err.span_label(span, format!("{} borrow occurs here{}", kind_new, msg_new)); err.span_label( old_span, format!("{} borrow occurs here{}", kind_old, msg_old), ); if let Some(old_load_end_span) = old_load_end_span { err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old)); } self.cancel_if_wrong_origin(err, o) } fn cannot_assign_to_borrowed( self, span: Span, borrow_span: Span, desc: &str, o: Origin, ) -> DiagnosticBuilder<'cx> { let mut err = struct_span_err!( self, span, E0506, "cannot assign to `{}` because it is borrowed{OGN}", desc, OGN = o ); err.span_label(borrow_span, format!("borrow of `{}` occurs here", desc)); err.span_label( span, format!("assignment to borrowed `{}` occurs here", desc), ); self.cancel_if_wrong_origin(err, o) } fn cannot_move_into_closure(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> { let err = struct_span_err!( self, span, E0504, "cannot move `{}` into closure because it is borrowed{OGN}", desc, OGN = o ); self.cancel_if_wrong_origin(err, o) } fn cannot_reassign_immutable( self, span: Span, desc: &str, is_arg: bool, o: Origin, ) -> DiagnosticBuilder<'cx> { let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" }; let err = struct_span_err!( self, span, E0384, "cannot assign {} `{}`{OGN}", msg, desc, OGN = o ); self.cancel_if_wrong_origin(err, o) } fn cannot_assign(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> { let err = struct_span_err!(self, span, E0594, "cannot assign to {}{OGN}", desc, OGN = o); self.cancel_if_wrong_origin(err, o) } fn cannot_assign_static(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> { self.cannot_assign(span, &format!("immutable static item `{}`", desc), o) } fn cannot_move_out_of( self, move_from_span: Span, move_from_desc: &str, o: Origin, ) -> DiagnosticBuilder<'cx> { let mut err = struct_span_err!( self, move_from_span, E0507, "cannot move out of {}{OGN}", move_from_desc, OGN = o ); err.span_label( move_from_span, format!("cannot move out of {}", move_from_desc), ); self.cancel_if_wrong_origin(err, o) } /// Signal an error due to an attempt to move out of the interior /// of an array or slice. `is_index` is None when error origin /// didn't capture whether there was an indexing operation or not. fn cannot_move_out_of_interior_noncopy( self, move_from_span: Span, ty: ty::Ty, is_index: Option, o: Origin, ) -> DiagnosticBuilder<'cx> { let type_name = match (&ty.sty, is_index) { (&ty::TyArray(_, _), Some(true)) | (&ty::TyArray(_, _), None) => "array", (&ty::TySlice(_), _) => "slice", _ => span_bug!(move_from_span, "this path should not cause illegal move"), }; let mut err = struct_span_err!( self, move_from_span, E0508, "cannot move out of type `{}`, \ a non-copy {}{OGN}", ty, type_name, OGN = o ); err.span_label(move_from_span, "cannot move out of here"); self.cancel_if_wrong_origin(err, o) } fn cannot_move_out_of_interior_of_drop( self, move_from_span: Span, container_ty: ty::Ty, o: Origin, ) -> DiagnosticBuilder<'cx> { let mut err = struct_span_err!( self, move_from_span, E0509, "cannot move out of type `{}`, \ which implements the `Drop` trait{OGN}", container_ty, OGN = o ); err.span_label(move_from_span, "cannot move out of here"); self.cancel_if_wrong_origin(err, o) } fn cannot_act_on_moved_value( self, use_span: Span, verb: &str, optional_adverb_for_moved: &str, moved_path: Option, o: Origin, ) -> DiagnosticBuilder<'cx> { let moved_path = moved_path .map(|mp| format!(": `{}`", mp)) .unwrap_or("".to_owned()); let err = struct_span_err!( self, use_span, E0382, "{} of {}moved value{}{OGN}", verb, optional_adverb_for_moved, moved_path, OGN = o ); self.cancel_if_wrong_origin(err, o) } fn cannot_partially_reinit_an_uninit_struct( self, span: Span, uninit_path: &str, o: Origin, ) -> DiagnosticBuilder<'cx> { let err = struct_span_err!( self, span, E0383, "partial reinitialization of uninitialized structure `{}`{OGN}", uninit_path, OGN = o ); self.cancel_if_wrong_origin(err, o) } fn closure_cannot_assign_to_borrowed( self, span: Span, descr: &str, o: Origin, ) -> DiagnosticBuilder<'cx> { let err = struct_span_err!( self, span, E0595, "closure cannot assign to {}{OGN}", descr, OGN = o ); self.cancel_if_wrong_origin(err, o) } fn cannot_borrow_path_as_mutable_because( self, span: Span, path: &str, reason: &str, o: Origin, ) -> DiagnosticBuilder<'cx> { let err = struct_span_err!( self, span, E0596, "cannot borrow {} as mutable{}{OGN}", path, reason, OGN = o, ); self.cancel_if_wrong_origin(err, o) } fn cannot_borrow_path_as_mutable( self, span: Span, path: &str, o: Origin, ) -> DiagnosticBuilder<'cx> { self.cannot_borrow_path_as_mutable_because(span, path, "", o) } fn cannot_borrow_across_generator_yield( self, span: Span, yield_span: Span, o: Origin, ) -> DiagnosticBuilder<'cx> { let mut err = struct_span_err!( self, span, E0626, "borrow may still be in use when generator yields{OGN}", OGN = o ); err.span_label(yield_span, "possible yield occurs here"); self.cancel_if_wrong_origin(err, o) } fn path_does_not_live_long_enough( self, span: Span, path: &str, o: Origin, ) -> DiagnosticBuilder<'cx> { let err = struct_span_err!( self, span, E0597, "{} does not live long enough{OGN}", path, OGN = o ); self.cancel_if_wrong_origin(err, o) } fn lifetime_too_short_for_reborrow( self, span: Span, path: &str, o: Origin, ) -> DiagnosticBuilder<'cx> { let err = struct_span_err!( self, span, E0598, "lifetime of {} is too short to guarantee \ its contents can be safely reborrowed{OGN}", path, OGN = o ); self.cancel_if_wrong_origin(err, o) } fn cannot_act_on_capture_in_sharable_fn( self, span: Span, bad_thing: &str, help: (Span, &str), o: Origin, ) -> DiagnosticBuilder<'cx> { let (help_span, help_msg) = help; let mut err = struct_span_err!( self, span, E0387, "{} in a captured outer variable in an `Fn` closure{OGN}", bad_thing, OGN = o ); err.span_help(help_span, help_msg); self.cancel_if_wrong_origin(err, o) } fn cannot_assign_into_immutable_reference( self, span: Span, bad_thing: &str, o: Origin, ) -> DiagnosticBuilder<'cx> { let mut err = struct_span_err!( self, span, E0389, "{} in a `&` reference{OGN}", bad_thing, OGN = o ); err.span_label(span, "assignment into an immutable reference"); self.cancel_if_wrong_origin(err, o) } fn cannot_capture_in_long_lived_closure( self, closure_span: Span, borrowed_path: &str, capture_span: Span, o: Origin, ) -> DiagnosticBuilder<'cx> { let mut err = struct_span_err!( self, closure_span, E0373, "closure may outlive the current function, \ but it borrows {}, \ which is owned by the current function{OGN}", borrowed_path, OGN = o ); err.span_label(capture_span, format!("{} is borrowed here", borrowed_path)) .span_label( closure_span, format!("may outlive borrowed value {}", borrowed_path), ); self.cancel_if_wrong_origin(err, o) } } impl<'cx, 'gcx, 'tcx> BorrowckErrors<'cx> for TyCtxt<'cx, 'gcx, 'tcx> { fn struct_span_err_with_code>( self, sp: S, msg: &str, code: DiagnosticId, ) -> DiagnosticBuilder<'cx> { self.sess.struct_span_err_with_code(sp, msg, code) } fn struct_span_err>(self, sp: S, msg: &str) -> DiagnosticBuilder<'cx> { self.sess.struct_span_err(sp, msg) } fn cancel_if_wrong_origin( self, mut diag: DiagnosticBuilder<'cx>, o: Origin, ) -> DiagnosticBuilder<'cx> { if !o.should_emit_errors(self.borrowck_mode()) { self.sess.diagnostic().cancel(&mut diag); } diag } }