]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc_mir/util/borrowck_errors.rs
New upstream version 1.31.0~beta.4+dfsg1
[rustc.git] / src / librustc_mir / util / borrowck_errors.rs
index 9de3072658660acea829ffc4547864b3e750e821..1715086686c4224dfb70900f34c14a9cf37a0a16 100644 (file)
 // 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;
+use rustc_errors::{DiagnosticBuilder, DiagnosticId};
 use syntax_pos::{MultiSpan, Span};
 
 use std::fmt;
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum Origin { Ast, Mir }
+pub enum Origin {
+    Ast,
+    Mir,
+}
 
 impl fmt::Display for Origin {
     fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            Origin::Mir => write!(w, " (Mir)"),
-            Origin::Ast => ty::tls::with_opt(|opt_tcx| {
-                // If user passed `-Z borrowck-mir`, then include an
-                // AST origin as part of the error report
-                if let Some(tcx) = opt_tcx {
-                    if tcx.sess.opts.debugging_opts.borrowck_mir {
-                        return write!(w, " (Ast)");
-                    }
-                }
-                // otherwise, do not include the origin (i.e., print
-                // nothing at all)
-                Ok(())
-            }),
+        // 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(())
         }
     }
 }
 
-pub trait BorrowckErrors {
-    fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
-                                                         sp: S,
-                                                         msg: &str,
-                                                         code: &str)
-                                                         -> DiagnosticBuilder<'a>;
-
-    fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
-                                               sp: S,
-                                               msg: &str)
-                                               -> DiagnosticBuilder<'a>;
-
-    fn cannot_move_when_borrowed(&self, span: Span, desc: &str, o: Origin)
-                                 -> DiagnosticBuilder
-    {
-        struct_span_err!(self, span, E0505,
-                         "cannot move out of `{}` because it is borrowed{OGN}",
-                         desc, OGN=o)
-    }
-
-    fn cannot_use_when_mutably_borrowed(&self, span: Span, desc: &str, o: Origin)
-                                        -> DiagnosticBuilder
-    {
-        struct_span_err!(self, span, E0503,
-                         "cannot use `{}` because it was mutably borrowed{OGN}",
-                         desc, OGN=o)
-    }
-
-    fn cannot_act_on_uninitialized_variable(&self,
-                                            span: Span,
-                                            verb: &str,
-                                            desc: &str,
-                                            o: Origin)
-                                            -> DiagnosticBuilder
-    {
-        struct_span_err!(self, span, E0381,
-                         "{} of possibly uninitialized variable: `{}`{OGN}",
-                         verb, desc, OGN=o)
-    }
-
-    fn cannot_mutably_borrow_multiply(&self,
-                                      span: Span,
-                                      desc: &str,
-                                      opt_via: &str,
-                                      o: Origin)
-                                      -> DiagnosticBuilder
-    {
-        struct_span_err!(self, span, E0499,
-                         "cannot borrow `{}`{} as mutable more than once at a time{OGN}",
-                         desc, opt_via, OGN=o)
-    }
-
-    fn cannot_uniquely_borrow_by_two_closures(&self, span: Span, desc: &str, o: Origin)
-                                              -> DiagnosticBuilder
-    {
-        struct_span_err!(self, span, E0524,
-                         "two closures require unique access to `{}` at the same time{OGN}",
-                         desc, OGN=o)
-    }
-
-    fn cannot_uniquely_borrow_by_one_closure(&self,
-                                             span: Span,
-                                             desc_new: &str,
-                                             noun_old: &str,
-                                             msg_old: &str,
-                                             o: Origin)
-                                             -> DiagnosticBuilder
-    {
-        struct_span_err!(self, span, E0500,
-                         "closure requires unique access to `{}` but {} is already borrowed{}{OGN}",
-                         desc_new, noun_old, msg_old, OGN=o)
-    }
-
-    fn cannot_reborrow_already_uniquely_borrowed(&self,
-                                                 span: Span,
-                                                 desc_new: &str,
-                                                 msg_new: &str,
-                                                 kind_new: &str,
-                                                 o: Origin)
-                                                 -> DiagnosticBuilder
-    {
-        struct_span_err!(self, span, E0501,
-                         "cannot borrow `{}`{} as {} because previous closure \
-                          requires unique access{OGN}",
-                         desc_new, msg_new, kind_new, OGN=o)
-    }
-
-    fn cannot_reborrow_already_borrowed(&self,
-                                        span: Span,
-                                        desc_new: &str,
-                                        msg_new: &str,
-                                        kind_new: &str,
-                                        noun_old: &str,
-                                        kind_old: &str,
-                                        msg_old: &str,
-                                        o: Origin)
-                                        -> DiagnosticBuilder
-    {
-        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)
-    }
-
-    fn cannot_assign_to_borrowed(&self, span: Span, desc: &str, o: Origin)
-                                 -> DiagnosticBuilder
-    {
-        struct_span_err!(self, span, E0506,
-                         "cannot assign to `{}` because it is borrowed{OGN}",
-                         desc, OGN=o)
-    }
-
-    fn cannot_move_into_closure(&self, span: Span, desc: &str, o: Origin)
-                                -> DiagnosticBuilder
-    {
-        struct_span_err!(self, span, E0504,
-                         "cannot move `{}` into closure because it is borrowed{OGN}",
-                         desc, OGN=o)
-    }
-
-    fn cannot_reassign_immutable(&self, span: Span, desc: &str, o: Origin)
-                                 -> DiagnosticBuilder
-    {
-        struct_span_err!(self, span, E0384,
-                         "re-assignment of immutable variable `{}`{OGN}",
-                         desc, OGN=o)
-    }
-
-    fn cannot_assign_static(&self, span: Span, desc: &str, o: Origin)
-                            -> DiagnosticBuilder
-    {
-        self.struct_span_err(span, &format!("cannot assign to immutable static item {}{OGN}",
-                                            desc, OGN=o))
+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<S: Into<MultiSpan>>(
+        self,
+        sp: S,
+        msg: &str,
+        code: DiagnosticId,
+    ) -> DiagnosticBuilder<'cx>;
+
+    fn struct_span_err<S: Into<MultiSpan>>(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<Span>,
+        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<Span>,
+        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,
+        container_name: &str,
+        desc_new: &str,
+        opt_via: &str,
+        old_loan_span: Span,
+        noun_old: &str,
+        old_opt_via: &str,
+        previous_end_span: Option<Span>,
+        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!("{} construction occurs here{}", container_name, 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,
+        container_name: &str,
+        desc_new: &str,
+        opt_via: &str,
+        kind_new: &str,
+        old_loan_span: Span,
+        old_opt_via: &str,
+        previous_end_span: Option<Span>,
+        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!("{} construction occurs here{}", container_name, 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<Span>,
+        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<bool>,
+        o: Origin,
+    ) -> DiagnosticBuilder<'cx> {
+        let type_name = match (&ty.sty, is_index) {
+            (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
+            (&ty::Slice(_), _) => "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<String>,
+        o: Origin,
+    ) -> DiagnosticBuilder<'cx> {
+        let moved_path = moved_path
+            .map(|mp| format!(": `{}`", mp))
+            .unwrap_or_default();
+
+        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_mutate_in_match_guard(
+        self,
+        mutate_span: Span,
+        match_span: Span,
+        match_place: &str,
+        action: &str,
+        o: Origin,
+    ) -> DiagnosticBuilder<'cx> {
+        let mut err = struct_span_err!(
+            self,
+            mutate_span,
+            E0510,
+            "cannot {} `{}` in match guard{OGN}",
+            action,
+            match_place,
+            OGN = o
+        );
+        err.span_label(mutate_span, format!("cannot {}", action));
+        err.span_label(match_span, format!("value is immutable in match guard"));
+
+        self.cancel_if_wrong_origin(err, 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 cannot_borrow_across_destructor(
+        self,
+        borrow_span: Span,
+        o: Origin,
+    ) -> DiagnosticBuilder<'cx> {
+        let err = struct_span_err!(
+            self,
+            borrow_span,
+            E0713,
+            "borrow may still be in use when destructor runs{OGN}",
+            OGN = o
+        );
+
+        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 cannot_return_reference_to_local(
+        self,
+        span: Span,
+        reference_desc: &str,
+        path_desc: &str,
+        o: Origin,
+    ) -> DiagnosticBuilder<'cx> {
+        let mut err = struct_span_err!(
+            self,
+            span,
+            E0515,
+            "cannot return {REFERENCE} {LOCAL}{OGN}",
+            REFERENCE=reference_desc,
+            LOCAL=path_desc,
+            OGN = o
+        );
+
+        err.span_label(
+            span,
+            format!("returns a {} data owned by the current function", reference_desc),
+        );
+
+        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)
+    }
+
+    fn borrowed_data_escapes_closure(
+        self,
+        escape_span: Span,
+        escapes_from: &str,
+        o: Origin,
+    ) -> DiagnosticBuilder<'cx> {
+        let err = struct_span_err!(
+            self,
+            escape_span,
+            E0521,
+            "borrowed data escapes outside of {}{OGN}",
+            escapes_from,
+            OGN = o
+        );
+
+        self.cancel_if_wrong_origin(err, o)
+    }
+
+    fn thread_local_value_does_not_live_long_enough(
+        self,
+        span: Span,
+        o: Origin,
+    ) -> DiagnosticBuilder<'cx> {
+        let err = struct_span_err!(
+            self,
+            span,
+            E0712,
+            "thread-local variable borrowed past end of function{OGN}",
+            OGN = o
+        );
+
+        self.cancel_if_wrong_origin(err, o)
+    }
+
+    fn temporary_value_borrowed_for_too_long(
+        self,
+        span: Span,
+        o: Origin,
+    ) -> DiagnosticBuilder<'cx> {
+        let err = struct_span_err!(
+            self,
+            span,
+            E0716,
+            "temporary value dropped while borrowed{OGN}",
+            OGN = o
+        );
+
+        self.cancel_if_wrong_origin(err, o)
     }
 }
 
-impl<'b, 'tcx, 'gcx> BorrowckErrors for TyCtxt<'b, 'tcx, 'gcx> {
-    fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
-                                                         sp: S,
-                                                         msg: &str,
-                                                         code: &str)
-                                                         -> DiagnosticBuilder<'a>
-    {
+impl<'cx, 'gcx, 'tcx> BorrowckErrors<'cx> for TyCtxt<'cx, 'gcx, 'tcx> {
+    fn struct_span_err_with_code<S: Into<MultiSpan>>(
+        self,
+        sp: S,
+        msg: &str,
+        code: DiagnosticId,
+    ) -> DiagnosticBuilder<'cx> {
         self.sess.struct_span_err_with_code(sp, msg, code)
     }
 
-    fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
-                                               sp: S,
-                                               msg: &str)
-                                               -> DiagnosticBuilder<'a>
-    {
+    fn struct_span_err<S: Into<MultiSpan>>(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
+    }
 }